diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 00000000..7b07db08 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,62 @@ +## Changes from ASTP 0.0.1 to 1.0.0 + +### Host OSAL + +- Bugfix in MessageQueue, which caused the sender not to be set properly + +### FreeRTOS OSAL + +- vRequestContextSwitchFromISR is declared extern "C" so it can be defined in +a C file without issues + +### PUS Services + +- It is now possible to change the message queue depth for the telecommand verification service (PUS1) +- The same is possible for the event reporting service (PUS5) +- PUS Health Service added, which allows to command and retrieve health via PUS packets + + +### EnhancedControllerBase + +- New base class for a controller which also implements HasActionsIF and HasLocalDataPoolIF + +### Local Pool + +- Interface of LocalPools has changed. LocalPool is not a template anymore. Instead the size and bucket number of the pools per page and the number of pages are passed to the ctor instead of two ctor arguments and a template parameter + +### Parameter Service + +- The API of the parameter service has been changed to prevent inconsistencies +between documentation and actual code and to clarify usage. +- The parameter ID now consists of: + 1. Domain ID (1 byte) + 2. Unique Identifier (1 byte) + 3. Linear Index (2 bytes) +The linear index can be used for arrays as well as matrices. +The parameter load command now explicitely expects the ECSS PTC and PFC +information as well as the rows and column number. Rows and column will +default to one, which is equivalent to one scalar parameter (the most +important use-case) + +### File System Interface + +- A new interfaces specifies the functions for a software object which exposes the file system of a given hardware to use message based file handling (e.g. PUS commanding) + +### Internal Error Reporter + +- The new internal error reporter uses the local data pools. The pool IDs for +the exisiting three error values and the new error set will be hardcoded for +now, the the constructor for the internal error reporter just takes an object +ID for now. + +### Device Handler Base + +- There is an additional `PERFORM_OPERATION` step for the device handler base. It is important +that DHB users adapt their polling sequence tables to perform this step. This steps allows for aclear distinction between operation and communication steps + +### Events + +- makeEvent function: Now takes three input parameters instead of two and +allows setting a unique ID. Event.cpp source file removed, functions now +defined in header directly. Namespaces renamed. Functions declared `constexpr` +now diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..669283c7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,85 @@ +cmake_minimum_required(VERSION 3.13) + +set(LIB_FSFW_NAME fsfw) +add_library(${LIB_FSFW_NAME}) + +# Set options for FSFW OSAL selection. +if(UNIX) +set(OS_FSFW "linux" CACHE STRING "OS abstraction layer used in the FSFW") +elseif(WIN32) +set(OS_FSFW "host" CACHE STRING "OS abstraction layer used in the FSFW") +endif() + +set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos) + +if(${OS_FSFW} STREQUAL host) +set(OS_FSFW_NAME "Host") +elseif(${OS_FSFW} STREQUAL linux) +set(OS_FSFW_NAME "Linux") +elseif(${OS_FSFW} STREQUAL freertos) +set(OS_FSFW_NAME "FreeRTOS") +elseif(${OS_FSFW} STREQUAL rtems) +set(OS_FSFW_NAME "RTEMS") +else() +message(WARNING "Invalid operating system for FSFW specified! Setting to host..") +set(OS_FSFW_NAME "Host") +set(OS_FSFW "host") +endif() + +message(STATUS "Compiling FSFW for the ${OS_FSFW_NAME} operating system") + +# Options to exclude parts of the FSFW from compilation. +option(FSFW_USE_RMAP "Compile with RMAP" ON) +option(FSFW_USE_DATALINKLAYER "Compile with Data Link Layer" ON) + +add_subdirectory(action) +add_subdirectory(container) +add_subdirectory(controller) +add_subdirectory(coordinates) +add_subdirectory(datalinklayer) +add_subdirectory(datapool) +add_subdirectory(devicehandlers) +add_subdirectory(events) +add_subdirectory(fdir) +add_subdirectory(globalfunctions) +add_subdirectory(health) +add_subdirectory(internalError) +add_subdirectory(ipc) +add_subdirectory(memory) +add_subdirectory(modes) +add_subdirectory(monitoring) +add_subdirectory(objectmanager) +add_subdirectory(osal) +add_subdirectory(parameters) +add_subdirectory(power) +add_subdirectory(pus) + +if(FSFW_USE_RMAP) +add_subdirectory(rmap) +endif() + +add_subdirectory(serialize) +add_subdirectory(serviceinterface) +add_subdirectory(storagemanager) +add_subdirectory(subsystem) +add_subdirectory(tasks) +add_subdirectory(tcdistribution) +add_subdirectory(thermal) +add_subdirectory(timemanager) +add_subdirectory(tmstorage) +add_subdirectory(tmtcpacket) +add_subdirectory(tmtcservices) + +# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. +# If this is not given, we include the default configuration and emit a warning. +if(NOT FSFW_CONFIG_PATH) +message(WARNING "Flight Software Framework configuration path not set!") +message(WARNING "Setting default configuration!") +add_subdirectory(defaultcfg/fsfwconfig) +endif() + +# Required include paths to compile the FSFW +target_include_directories(${LIB_FSFW_NAME} + INTERFACE + ${FSFW_CONFIG_PATH} +) diff --git a/FSFWVersion.h b/FSFWVersion.h index dcb592dc..11a60891 100644 --- a/FSFWVersion.h +++ b/FSFWVersion.h @@ -1,10 +1,11 @@ #ifndef FSFW_DEFAULTCFG_VERSION_H_ #define FSFW_DEFAULTCFG_VERSION_H_ -const char* const FSFW_VERSION_NAME = "fsfw"; +const char* const FSFW_VERSION_NAME = "ASTP"; #define FSFW_VERSION 0 #define FSFW_SUBVERSION 0 +#define FSFW_REVISION 1 diff --git a/NOTICE b/NOTICE index e1663282..be1a37c4 100644 --- a/NOTICE +++ b/NOTICE @@ -4,6 +4,8 @@ The initial version of the Flight Software Framework was developed during the Flying Laptop Project by the Universität Stuttgart in coorporation with Airbus Defence and Space GmbH. +The supreme FSFW Logo was designed by Markus Koller and Luise Trilsbach. + Copyrights in the Flight Software Framework are retained by their contributors. No copyright assignment is required to contribute to the Flight Software Framework. diff --git a/README.md b/README.md index fc86fca7..4aabe36a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,159 @@ -Flight Software Framework (FSFW) -====== +![FSFW Logo](logo/FSFW_Logo_V3_bw.png) +# Flight Software Framework (FSFW) -I want to be written! +The Flight Software Framework is a C++ Object Oriented Framework for unmanned, +automated systems like Satellites. + +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 + +The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. +Therefore, a mode and health system provides control over the states of the software and the controlled devices. +In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well. + +The recommended hardware is a microprocessor with more than 2 MB of RAM and 1 MB of non-volatile Memory. +For reference, current Applications use a Cobham Gaisler UT699 (LEON3FT), a ISISPACE IOBC or a Zynq-7020 SoC. + + +## Structure + +The general structure is driven by the usage of interfaces provided by objects. The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be widely available, even with older compilers. +The FSFW uses dynamic allocation during the initialization but provides static containers during runtime. +This simplifies the instantiation of objects and allows the usage of some standard containers. +Dynamic Allocation after initialization is discouraged and different solutions are provided in the FSFW to achieve that. +The fsfw uses Run-time type information. +Exceptions are not allowed. + +### Failure Handling + +Functions should return a defined ReturnValue_t to signal to the caller that something is gone wrong. +Returnvalues must be unique. For this the function HasReturnvaluesIF::makeReturnCode or the Macro MAKE_RETURN can be used. +The CLASS_ID is a unique id for that type of object. See returnvalues/FwClassIds. + +### OSAL +The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS. A independent OSAL called "host" is currently not finished. This aims to be running on windows as well. +The OSAL provides periodic tasks, message queues, clocks and Semaphores as well as Mutexes. + +### Core Components + +Clock: + * This is a class of static functions that can be used at anytime + * Leap Seconds must be set if any time conversions from UTC to other times is used + +ObjectManager (must be created): + +* The component which handles all references. All SystemObjects register at this component. +* Any SystemObject needs to have a unique ObjectId. Those can be managed like objects::framework_objects. +* A reference to an object can be get by calling the following function. T must be the specific Interface you want to call. +A nullptr check of the returning Pointer must be done. This function is based on Run-time type information. + +``` c++ + template T* ObjectManagerIF::get( object_id_t id ) + +``` +* A typical way to create all objects on startup is a handing a static produce function to the ObjectManager on creation. +By calling objectManager->initialize() the produce function will be called and all SystemObjects will be initialized afterwards. + +Event Manager: + +* Component which allows routing of events +* Other objects can subscribe to specific events, ranges of events or all events of an object. +* Subscriptions can be done during runtime but should be done during initialization +* Amounts of allowed subscriptions must be configured by setting this parameters: + +``` c++ +namespace fsfwconfig { +//! Configure the allocated pool sizes for the event manager. +static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240; +static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120; +static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; +} +``` + + +Health Table: + +* A component which holds every health state +* Provides a thread safe way to access all health states without the need of message exchanges + +Stores + +* The message based communication can only exchange a few bytes of information inside the message itself. Therefore, additional information can be exchanged with Stores. With this, only the store address must be exchanged in the message. +* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC Store is used. For outgoing TM a TM store is used. +* All of them should use the Thread Safe Class storagemanager/PoolManager + +Tasks + +There are two different types of tasks: + * The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the insertion to the Tasks. + * FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for DeviceHandlers, where polling should be in a defined order. An example can be found in defaultcfg/fsfwconfig/pollingSequence + + +### Static Ids in the framework + +Some parts of the framework use a static routing address for communication. +An example setup of ids can be found in the example config in "defaultcft/fsfwconfig/objects/Factory::setStaticFrameworkObjectIds()". + +### Events + +Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT. This works analog to the returnvalues. +Every object that needs own EventIds has to get a unique SUBSYSTEM_ID. +Every SystemObject can call triggerEvent from the parent class. +Therefore, event messages contain the specific EventId and the objectId of the object that has triggered. + +### Internal Communication + +Components communicate mostly over Message through Queues. +Those queues are created by calling the singleton QueueFactory::instance()->create(). + +### External Communication + +The external communication with the mission control system is mostly up to the user implementation. +The FSFW provides PUS Services which can be used to but don't need to be used. +The services can be seen as a conversion from a TC to a message based communication and back. + +#### CCSDS Frames, CCSDS Space Packets and PUS + +If the communication is based on CCSDS Frames and Space Packets, several classes can be used to distributed the packets to the corresponding services. Those can be found in tcdistribution. +If Space Packets are used, a timestamper must be created. +An example can be found in the timemanager folder, this uses CCSDSTime::CDS_short. + +#### DeviceHandling + +DeviceHandlers are a core component of the FSFW. +The idea is, to have a software counterpart of every physical device to provide a simple mode, health and commanding interface. +By separating the underlying Communication Interface with DeviceCommunicationIF, a DH can be tested on different hardware. +The DH has mechanisms to monitor the communication with the physical device which allow for FDIR reaction. +A standard FDIR component for the DH will be created automatically but can be overwritten by the user. + +#### Modes, Health + +The two interfaces HasModesIF and HasHealthIF provide access for commanding and monitoring of components. +On-board Mode Management is implement in hierarchy system. +DeviceHandlers and Controllers are the lowest part of the hierarchy. +The next layer are Assemblies. Those assemblies act as a component which handle redundancies of handlers. +Assemblies share a common core with the next level which are the Subsystems. + +Those Assemblies are intended to act as auto-generated components from a database which describes the subsystem modes. +The definitions contain transition and target tables which contain the DH, Assembly and Controller Modes to be commanded. +Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a switch into any higher AOCS mode might first turn on the sensors, than the actuators and the controller as last component. +The target table is used to describe the state that is checked continuously by the subsystem. +All of this allows System Modes to be generated as Subsystem object as well from the same database. +This System contains list of subsystem modes in the transition and target tables. +Therefore, it allows a modular system to create system modes and easy commanding of those, because only the highest components must be commanded. + +The health state represents if the component is able to perform its tasks. +This can be used to signal the system to avoid using this component instead of a redundant one. +The on-board FDIR uses the health state for isolation and recovery. + +## Example config + +A example config can be found in defaultcfg/fsfwconfig. + +## Unit Tests + +Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include catch2 itself. +See README.md in the unittest Folder. \ No newline at end of file diff --git a/action/ActionHelper.cpp b/action/ActionHelper.cpp index 0d3baa88..28557916 100644 --- a/action/ActionHelper.cpp +++ b/action/ActionHelper.cpp @@ -1,5 +1,6 @@ #include "ActionHelper.h" #include "HasActionsIF.h" + #include "../ipc/MessageQueueSenderIF.h" #include "../objectmanager/ObjectManagerIF.h" diff --git a/action/ActionMessage.h b/action/ActionMessage.h index 0a718aab..7a859de0 100644 --- a/action/ActionMessage.h +++ b/action/ActionMessage.h @@ -1,5 +1,5 @@ -#ifndef ACTIONMESSAGE_H_ -#define ACTIONMESSAGE_H_ +#ifndef FSFW_ACTION_ACTIONMESSAGE_H_ +#define FSFW_ACTION_ACTIONMESSAGE_H_ #include "../ipc/CommandMessage.h" #include "../objectmanager/ObjectManagerIF.h" @@ -18,15 +18,19 @@ public: static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5); static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6); virtual ~ActionMessage(); - static void setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters); + static void setCommand(CommandMessage* message, ActionId_t fid, + store_address_t parameters); static ActionId_t getActionId(const CommandMessage* message ); static store_address_t getStoreId(const CommandMessage* message ); - static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + static void setStepReply(CommandMessage* message, ActionId_t fid, + uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); static uint8_t getStep(const CommandMessage* message ); static ReturnValue_t getReturnCode(const CommandMessage* message ); - static void setDataReply(CommandMessage* message, ActionId_t actionId, store_address_t data); - static void setCompletionReply(CommandMessage* message, ActionId_t fid, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); + static void setDataReply(CommandMessage* message, ActionId_t actionId, + store_address_t data); + static void setCompletionReply(CommandMessage* message, ActionId_t fid, + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); static void clear(CommandMessage* message); }; -#endif /* ACTIONMESSAGE_H_ */ +#endif /* FSFW_ACTION_ACTIONMESSAGE_H_ */ diff --git a/action/CMakeLists.txt b/action/CMakeLists.txt new file mode 100644 index 00000000..a62d4044 --- /dev/null +++ b/action/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ActionHelper.cpp + ActionMessage.cpp + CommandActionHelper.cpp + SimpleActionHelper.cpp +) \ No newline at end of file diff --git a/action/CommandsActionsIF.h b/action/CommandsActionsIF.h index 3d04015d..491bfc70 100644 --- a/action/CommandsActionsIF.h +++ b/action/CommandsActionsIF.h @@ -1,5 +1,5 @@ -#ifndef COMMANDSACTIONSIF_H_ -#define COMMANDSACTIONSIF_H_ +#ifndef FSFW_ACTION_COMMANDSACTIONSIF_H_ +#define FSFW_ACTION_COMMANDSACTIONSIF_H_ #include "CommandActionHelper.h" #include "../returnvalues/HasReturnvaluesIF.h" @@ -24,11 +24,14 @@ public: virtual MessageQueueIF* getCommandQueuePtr() = 0; protected: virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0; - virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) = 0; - virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) = 0; + virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, + ReturnValue_t returnCode) = 0; + virtual void dataReceived(ActionId_t actionId, const uint8_t* data, + uint32_t size) = 0; virtual void completionSuccessfulReceived(ActionId_t actionId) = 0; - virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) = 0; + virtual void completionFailedReceived(ActionId_t actionId, + ReturnValue_t returnCode) = 0; }; -#endif /* COMMANDSACTIONSIF_H_ */ +#endif /* FSFW_ACTION_COMMANDSACTIONSIF_H_ */ diff --git a/container/CMakeLists.txt b/container/CMakeLists.txt new file mode 100644 index 00000000..904cde55 --- /dev/null +++ b/container/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + SharedRingBuffer.cpp + SimpleRingBuffer.cpp +) \ No newline at end of file diff --git a/controller/CMakeLists.txt b/controller/CMakeLists.txt new file mode 100644 index 00000000..6f660738 --- /dev/null +++ b/controller/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ControllerBase.cpp +) \ No newline at end of file diff --git a/controller/ControllerBase.cpp b/controller/ControllerBase.cpp index 69551731..2a402468 100644 --- a/controller/ControllerBase.cpp +++ b/controller/ControllerBase.cpp @@ -1,16 +1,16 @@ -#include "../subsystem/SubsystemBase.h" #include "ControllerBase.h" + #include "../subsystem/SubsystemBase.h" #include "../ipc/QueueFactory.h" #include "../action/HasActionsIF.h" -ControllerBase::ControllerBase(uint32_t setObjectId, uint32_t parentId, +ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth) : - SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF), submode( - SUBMODE_NONE), commandQueue(NULL), modeHelper( - this), healthHelper(this, setObjectId),hkSwitcher(this),executingTask(NULL) { - commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth); - + SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF), + submode(SUBMODE_NONE), modeHelper(this), + healthHelper(this, setObjectId) { + commandQueue = QueueFactory::instance()->createMessageQueue( + commandQueueDepth); } ControllerBase::~ControllerBase() { @@ -24,9 +24,9 @@ ReturnValue_t ControllerBase::initialize() { } MessageQueueId_t parentQueue = 0; - if (parentId != 0) { + if (parentId != objects::NO_OBJECT) { SubsystemBase *parent = objectManager->get(parentId); - if (parent == NULL) { + if (parent == nullptr) { return RETURN_FAILED; } parentQueue = parent->getCommandQueue(); @@ -44,10 +44,6 @@ ReturnValue_t ControllerBase::initialize() { return result; } - result = hkSwitcher.initialize(); - if (result != RETURN_OK) { - return result; - } return RETURN_OK; } @@ -56,26 +52,27 @@ MessageQueueId_t ControllerBase::getCommandQueue() const { } void ControllerBase::handleQueue() { - CommandMessage message; - ReturnValue_t result; - for (result = commandQueue->receiveMessage(&message); result == RETURN_OK; - result = commandQueue->receiveMessage(&message)) { + CommandMessage command; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + for (result = commandQueue->receiveMessage(&command); + result == RETURN_OK; + result = commandQueue->receiveMessage(&command)) { - result = modeHelper.handleModeCommand(&message); + result = modeHelper.handleModeCommand(&command); if (result == RETURN_OK) { continue; } - result = healthHelper.handleHealthCommand(&message); + result = healthHelper.handleHealthCommand(&command); if (result == RETURN_OK) { continue; } - result = handleCommandMessage(&message); + result = handleCommandMessage(&command); if (result == RETURN_OK) { continue; } - message.setToUnknownCommand(); - commandQueue->reply(&message); + command.setToUnknownCommand(); + commandQueue->reply(&command); } } @@ -106,7 +103,6 @@ void ControllerBase::announceMode(bool recursive) { ReturnValue_t ControllerBase::performOperation(uint8_t opCode) { handleQueue(); - hkSwitcher.performOperation(); performControlOperation(); return RETURN_OK; } @@ -135,3 +131,7 @@ void ControllerBase::setTaskIF(PeriodicTaskIF* task_){ void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { } + +ReturnValue_t ControllerBase::initializeAfterTaskCreation() { + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/controller/ControllerBase.h b/controller/ControllerBase.h index f5182ceb..6e83fe80 100644 --- a/controller/ControllerBase.h +++ b/controller/ControllerBase.h @@ -1,5 +1,5 @@ -#ifndef CONTROLLERBASE_H_ -#define CONTROLLERBASE_H_ +#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_ +#define FSFW_CONTROLLER_CONTROLLERBASE_H_ #include "../health/HasHealthIF.h" #include "../health/HealthHelper.h" @@ -7,73 +7,88 @@ #include "../modes/ModeHelper.h" #include "../objectmanager/SystemObject.h" #include "../tasks/ExecutableObjectIF.h" +#include "../tasks/PeriodicTaskIF.h" #include "../datapool/HkSwitchHelper.h" - +/** + * @brief Generic base class for controller classes + * @details + * Implements common interfaces for controllers, which generally have + * a mode and a health state. This avoids boilerplate code. + */ class ControllerBase: public HasModesIF, public HasHealthIF, public ExecutableObjectIF, public SystemObject, public HasReturnvaluesIF { public: - static const Mode_t MODE_NORMAL = 2; - ControllerBase(uint32_t setObjectId, uint32_t parentId, + ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3); virtual ~ControllerBase(); - ReturnValue_t initialize(); + /** SystemObject override */ + virtual ReturnValue_t initialize() override; - virtual MessageQueueId_t getCommandQueue() const; + virtual MessageQueueId_t getCommandQueue() const override; - virtual ReturnValue_t performOperation(uint8_t opCode); - - virtual ReturnValue_t setHealth(HealthState health); - - virtual HasHealthIF::HealthState getHealth(); - - /** - * Implementation of ExecutableObjectIF function - * - * Used to setup the reference of the task, that executes this component - * @param task_ Pointer to the taskIF of this task - */ - virtual void setTaskIF(PeriodicTaskIF* task_); + /** HasHealthIF overrides */ + virtual ReturnValue_t setHealth(HealthState health) override; + virtual HasHealthIF::HealthState getHealth() override; + /** ExecutableObjectIF overrides */ + virtual ReturnValue_t performOperation(uint8_t opCode) override; + virtual void setTaskIF(PeriodicTaskIF* task) override; + virtual ReturnValue_t initializeAfterTaskCreation() override; protected: - const uint32_t parentId; + + /** + * Implemented by child class. Handle command messages which are not + * mode or health messages. + * @param message + * @return + */ + virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0; + + /** + * Periodic helper, implemented by child class. + */ + virtual void performControlOperation() = 0; + + virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t *msToReachTheMode) = 0; + + const object_id_t parentId; Mode_t mode; Submode_t submode; - MessageQueueIF* commandQueue; + MessageQueueIF* commandQueue = nullptr; ModeHelper modeHelper; HealthHelper healthHelper; - HkSwitchHelper hkSwitcher; - /** - * Pointer to the task which executes this component, is invalid before setTaskIF was called. + * Pointer to the task which executes this component, + * is invalid before setTaskIF was called. */ - PeriodicTaskIF* executingTask; + PeriodicTaskIF* executingTask = nullptr; - void handleQueue(); + /** Handle mode and health messages */ + virtual void handleQueue(); - virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0; - virtual void performControlOperation() = 0; - virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode) = 0; + /** Mode helpers */ virtual void modeChanged(Mode_t mode, Submode_t submode); virtual void startTransition(Mode_t mode, Submode_t submode); virtual void getMode(Mode_t *mode, Submode_t *submode); virtual void setToExternalControl(); virtual void announceMode(bool recursive); + /** HK helpers */ virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); }; -#endif /* CONTROLLERBASE_H_ */ +#endif /* FSFW_CONTROLLER_CONTROLLERBASE_H_ */ diff --git a/controller/ExtendedControllerBase.cpp b/controller/ExtendedControllerBase.cpp new file mode 100644 index 00000000..f69d2ea1 --- /dev/null +++ b/controller/ExtendedControllerBase.cpp @@ -0,0 +1,114 @@ +#include "ExtendedControllerBase.h" + + +ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, + object_id_t parentId, size_t commandQueueDepth): + ControllerBase(objectId, parentId, commandQueueDepth), + localPoolManager(this, commandQueue), + actionHelper(this, commandQueue) { +} + +ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t *data, size_t size) { + // needs to be overriden and implemented by child class. + return HasReturnvaluesIF::RETURN_OK; +} + + + +ReturnValue_t ExtendedControllerBase::initializeLocalDataPool( + LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + // needs to be overriden and implemented by child class. + return HasReturnvaluesIF::RETURN_OK; +} + +object_id_t ExtendedControllerBase::getObjectId() const { + return SystemObject::getObjectId(); +} + +LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() { + return &localPoolManager; +} + +uint32_t ExtendedControllerBase::getPeriodicOperationFrequency() const { + return this->executingTask->getPeriodMs(); +} + +ReturnValue_t ExtendedControllerBase::handleCommandMessage( + CommandMessage *message) { + ReturnValue_t result = actionHelper.handleActionMessage(message); + if(result == HasReturnvaluesIF::RETURN_OK) { + return result; + } + return localPoolManager.handleHousekeepingMessage(message); +} + +void ExtendedControllerBase::handleQueue() { + CommandMessage command; + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + for (result = commandQueue->receiveMessage(&command); + result == RETURN_OK; + result = commandQueue->receiveMessage(&command)) { + result = actionHelper.handleActionMessage(&command); + if (result == RETURN_OK) { + continue; + } + + result = modeHelper.handleModeCommand(&command); + if (result == RETURN_OK) { + continue; + } + + result = healthHelper.handleHealthCommand(&command); + if (result == RETURN_OK) { + continue; + } + + result = localPoolManager.handleHousekeepingMessage(&command); + if (result == RETURN_OK) { + continue; + } + + result = handleCommandMessage(&command); + if (result == RETURN_OK) { + continue; + } + command.setToUnknownCommand(); + commandQueue->reply(&command); + } +} + +ReturnValue_t ExtendedControllerBase::initialize() { + ReturnValue_t result = ControllerBase::initialize(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = actionHelper.initialize(commandQueue); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + return localPoolManager.initialize(commandQueue); +} + +ReturnValue_t ExtendedControllerBase::initializeAfterTaskCreation() { + return localPoolManager.initializeAfterTaskCreation(); +} + +ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) { + handleQueue(); + hkSwitcher.performOperation(); + localPoolManager.performHkOperation(); + performControlOperation(); + return RETURN_OK; +} + +MessageQueueId_t ExtendedControllerBase::getCommandQueue() const { + return commandQueue->getId(); +} + +LocalPoolDataSetBase* ExtendedControllerBase::getDataSetHandle(sid_t sid) { + sif::warning << "ExtendedControllerBase::getDataSetHandle: No child " + << " implementation provided, returning nullptr!" << std::endl; + return nullptr; +} diff --git a/controller/ExtendedControllerBase.h b/controller/ExtendedControllerBase.h new file mode 100644 index 00000000..02c5728e --- /dev/null +++ b/controller/ExtendedControllerBase.h @@ -0,0 +1,72 @@ +#ifndef FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ +#define FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ + +#include "ControllerBase.h" + +#include "../action/HasActionsIF.h" +#include "../datapoollocal/HasLocalDataPoolIF.h" +#include "../action/ActionHelper.h" +#include "../datapoollocal/LocalDataPoolManager.h" + +/** + * @brief Extendes the basic ControllerBase with the common components + * HasActionsIF for commandability and HasLocalDataPoolIF to keep + * a pool of local data pool variables. + * @details + * Default implementations required for the interfaces will be empty and have + * to be implemented by child class. + */ +class ExtendedControllerBase: public ControllerBase, + public HasActionsIF, + public HasLocalDataPoolIF { +public: + ExtendedControllerBase(object_id_t objectId, object_id_t parentId, + size_t commandQueueDepth = 3); + + /** SystemObjectIF overrides */ + virtual ReturnValue_t initialize() override; + + virtual MessageQueueId_t getCommandQueue() const override; + + /** ExecutableObjectIF overrides */ + virtual ReturnValue_t performOperation(uint8_t opCode) override; + virtual ReturnValue_t initializeAfterTaskCreation() override; + +protected: + LocalDataPoolManager localPoolManager; + ActionHelper actionHelper; + + /** + * Implemented by child class. Handle all command messages which are + * not health, mode, action or housekeeping messages. + * @param message + * @return + */ + virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0; + + /** + * Periodic helper from ControllerBase, implemented by child class. + */ + virtual void performControlOperation() = 0; + + /** Handle the four messages mentioned above */ + void handleQueue() override; + + /** HasActionsIF overrides */ + virtual ReturnValue_t executeAction(ActionId_t actionId, + MessageQueueId_t commandedBy, const uint8_t* data, + size_t size) override; + + /** HasLocalDatapoolIF overrides */ + virtual object_id_t getObjectId() const override; + virtual ReturnValue_t initializeLocalDataPool( + LocalDataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + virtual LocalDataPoolManager* getHkManagerHandle() override; + virtual uint32_t getPeriodicOperationFrequency() const override; + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; +}; + + + +#endif /* FSFW_CONTROLLER_EXTENDEDCONTROLLERBASE_H_ */ diff --git a/coordinates/CMakeLists.txt b/coordinates/CMakeLists.txt new file mode 100644 index 00000000..a1fa1e52 --- /dev/null +++ b/coordinates/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + CoordinateTransformations.cpp + Sgp4Propagator.cpp +) \ No newline at end of file diff --git a/datalinklayer/CMakeLists.txt b/datalinklayer/CMakeLists.txt new file mode 100644 index 00000000..148e7c5d --- /dev/null +++ b/datalinklayer/CMakeLists.txt @@ -0,0 +1,12 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + Clcw.cpp + DataLinkLayer.cpp + Farm1StateLockout.cpp + Farm1StateOpen.cpp + Farm1StateWait.cpp + MapPacketExtraction.cpp + TcTransferFrame.cpp + TcTransferFrameLocal.cpp + VirtualChannelReception.cpp +) \ No newline at end of file diff --git a/datalinklayer/DataLinkLayer.h b/datalinklayer/DataLinkLayer.h index 5a900099..17a57d61 100644 --- a/datalinklayer/DataLinkLayer.h +++ b/datalinklayer/DataLinkLayer.h @@ -19,12 +19,12 @@ class VirtualChannelReception; class DataLinkLayer : public CCSDSReturnValuesIF { public: static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_1; - static const Event RF_AVAILABLE = MAKE_EVENT(0, SEVERITY::INFO); //!< A RF available signal was detected. P1: raw RFA state, P2: 0 - static const Event RF_LOST = MAKE_EVENT(1, SEVERITY::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0 - static const Event BIT_LOCK = MAKE_EVENT(2, SEVERITY::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0 - static const Event BIT_LOCK_LOST = MAKE_EVENT(3, SEVERITY::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0 -// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, SEVERITY::INFO); //!< The CCSDS Board detected that either bit lock or RF available or both are lost. No parameters. - static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, SEVERITY::LOW); //!< The CCSDS Board could not interpret a TC + static const Event RF_AVAILABLE = MAKE_EVENT(0, severity::INFO); //!< A RF available signal was detected. P1: raw RFA state, P2: 0 + static const Event RF_LOST = MAKE_EVENT(1, severity::INFO); //!< A previously found RF available signal was lost. P1: raw RFA state, P2: 0 + static const Event BIT_LOCK = MAKE_EVENT(2, severity::INFO); //!< A Bit Lock signal. Was detected. P1: raw BLO state, P2: 0 + static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO); //!< A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0 +// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, severity::INFO); //!< The CCSDS Board detected that either bit lock or RF available or both are lost. No parameters. + static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, severity::LOW); //!< The CCSDS Board could not interpret a TC /** * The Constructor sets the passed parameters and nothing else. * @param set_frame_buffer The buffer in which incoming frame candidates are stored. diff --git a/datalinklayer/MapPacketExtraction.cpp b/datalinklayer/MapPacketExtraction.cpp index d64348e1..845ed7c1 100644 --- a/datalinklayer/MapPacketExtraction.cpp +++ b/datalinklayer/MapPacketExtraction.cpp @@ -1,10 +1,3 @@ -/** - * @file MapPacketExtraction.cpp - * @brief This file defines the MapPacketExtraction class. - * @date 26.03.2013 - * @author baetz - */ - #include "MapPacketExtraction.h" #include "../ipc/QueueFactory.h" #include "../serviceinterface/ServiceInterfaceStream.h" @@ -12,14 +5,14 @@ #include "../tmtcpacket/SpacePacketBase.h" #include "../tmtcservices/AcceptsTelecommandsIF.h" #include "../tmtcservices/TmTcMessage.h" -#include +#include MapPacketExtraction::MapPacketExtraction(uint8_t setMapId, object_id_t setPacketDestination) : - lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), bufferPosition( - packetBuffer), packetDestination(setPacketDestination), packetStore( - NULL), tcQueueId(MessageQueueIF::NO_QUEUE) { - memset(packetBuffer, 0, sizeof(packetBuffer)); + lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), + bufferPosition(packetBuffer), packetDestination(setPacketDestination), + tcQueueId(MessageQueueIF::NO_QUEUE) { + std::memset(packetBuffer, 0, sizeof(packetBuffer)); } ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) { diff --git a/datalinklayer/MapPacketExtraction.h b/datalinklayer/MapPacketExtraction.h index 507f13db..ddb867fb 100644 --- a/datalinklayer/MapPacketExtraction.h +++ b/datalinklayer/MapPacketExtraction.h @@ -1,12 +1,5 @@ -/** - * @file MapPacketExtraction.h - * @brief This file defines the MapPacketExtraction class. - * @date 26.03.2013 - * @author baetz - */ - -#ifndef MAPPACKETEXTRACTION_H_ -#define MAPPACKETEXTRACTION_H_ +#ifndef FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_ +#define FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_ #include "MapPacketExtractionIF.h" #include "../objectmanager/ObjectManagerIF.h" @@ -20,17 +13,19 @@ class StorageManagerIF; * The class implements the full MAP Packet Extraction functionality as described in the CCSDS * TC Space Data Link Protocol. It internally stores incomplete segmented packets until they are * fully received. All found packets are forwarded to a single distribution entity. + * @author B. Baetz */ class MapPacketExtraction: public MapPacketExtractionIF { private: static const uint32_t MAX_PACKET_SIZE = 4096; uint8_t lastSegmentationFlag; //!< The segmentation flag of the last received frame. uint8_t mapId; //!< MAP ID of this MAP Channel. - uint32_t packetLength; //!< Complete length of the current Space Packet. + uint32_t packetLength = 0; //!< Complete length of the current Space Packet. uint8_t* bufferPosition; //!< Position to write to in the internal Packet buffer. uint8_t packetBuffer[MAX_PACKET_SIZE]; //!< The internal Space Packet Buffer. object_id_t packetDestination; - StorageManagerIF* packetStore; //!< Pointer to the store where full TC packets are stored. + //!< Pointer to the store where full TC packets are stored. + StorageManagerIF* packetStore = nullptr; MessageQueueId_t tcQueueId; //!< QueueId to send found packets to the distributor. /** * Debug method to print the packet Buffer's content. @@ -75,4 +70,4 @@ public: uint8_t getMapId() const; }; -#endif /* MAPPACKETEXTRACTION_H_ */ +#endif /* FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_ */ diff --git a/datapool/CMakeLists.txt b/datapool/CMakeLists.txt new file mode 100644 index 00000000..e741f6a1 --- /dev/null +++ b/datapool/CMakeLists.txt @@ -0,0 +1,11 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ControllerSet.cpp + DataPool.cpp + DataPoolAdmin.cpp + DataPoolParameterWrapper.cpp + DataSet.cpp + HkSwitchHelper.cpp + PoolEntry.cpp + PoolRawAccess.cpp +) \ No newline at end of file diff --git a/datapool/ControllerSet.h b/datapool/ControllerSet.h deleted file mode 100644 index e27debff..00000000 --- a/datapool/ControllerSet.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef CONTROLLERSET_H_ -#define CONTROLLERSET_H_ - -#include "DataSet.h" - -class ControllerSet :public DataSet { -public: - ControllerSet(); - virtual ~ControllerSet(); - - virtual void setToDefault() = 0; - void setInvalid(); -}; - -#endif /* CONTROLLERSET_H_ */ diff --git a/datapool/DataPool.cpp b/datapool/DataPool.cpp deleted file mode 100644 index 1b6cb7a1..00000000 --- a/datapool/DataPool.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "DataPool.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../ipc/MutexFactory.h" - -DataPool::DataPool( void ( *initFunction )( std::map* pool_map ) ) { - mutex = MutexFactory::instance()->createMutex(); - if (initFunction != NULL ) { - initFunction( &this->data_pool ); - } -} - -DataPool::~DataPool() { - MutexFactory::instance()->deleteMutex(mutex); - for ( std::map::iterator it = this->data_pool.begin(); it != this->data_pool.end(); ++it ) { - delete it->second; - } -} - -//The function checks PID, type and array length before returning a copy of the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr. -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t sizeOrPosition ) { - std::map::iterator it = this->data_pool.find( data_pool_id ); - if ( it != this->data_pool.end() ) { - PoolEntry* entry = dynamic_cast< PoolEntry* >( it->second ); - if (entry != NULL ) { - if ( sizeOrPosition <= entry->length ) { - return entry; - } - } - } - return NULL; -} - -PoolEntryIF* DataPool::getRawData( uint32_t data_pool_id ) { - std::map::iterator it = this->data_pool.find( data_pool_id ); - if ( it != this->data_pool.end() ) { - return it->second; - } else { - return NULL; - } -} - -//uint8_t DataPool::getRawData( uint32_t data_pool_id, uint8_t* address, uint16_t* size, uint32_t maxSize ) { -// std::map::iterator it = this->data_pool.find( data_pool_id ); -// if ( it != this->data_pool.end() ) { -// if ( it->second->getByteSize() <= maxSize ) { -// *size = it->second->getByteSize(); -// memcpy( address, it->second->getRawData(), *size ); -// return DP_SUCCESSFUL; -// } -// } -// *size = 0; -// return DP_FAILURE; -//} - -ReturnValue_t DataPool::freeDataPoolLock() { - ReturnValue_t status = mutex->unlockMutex(); - if ( status != RETURN_OK ) { - sif::error << "DataPool::DataPool: unlock of mutex failed with error code: " << status << std::endl; - } - return status; -} - -ReturnValue_t DataPool::lockDataPool() { - ReturnValue_t status = mutex->lockMutex(MutexIF::BLOCKING); - if ( status != RETURN_OK ) { - sif::error << "DataPool::DataPool: lock of mutex failed with error code: " << status << std::endl; - } - return status; -} - -void DataPool::print() { - sif::debug << "DataPool contains: " << std::endl; - std::map::iterator dataPoolIt; - dataPoolIt = this->data_pool.begin(); - while( dataPoolIt != this->data_pool.end() ) { - sif::debug << std::hex << dataPoolIt->first << std::dec << " |"; - dataPoolIt->second->print(); - dataPoolIt++; - } -} - -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData(uint32_t data_pool_id, - uint8_t size); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData(uint32_t data_pool_id, - uint8_t size); - - -uint32_t DataPool::PIDToDataPoolId(uint32_t parameter_id) { - return (parameter_id >> 8) & 0x00FFFFFF; -} - -uint8_t DataPool::PIDToArrayIndex(uint32_t parameter_id) { - return (parameter_id & 0x000000FF); -} - -uint32_t DataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) { - return (poolId << 8) + index; -} - - -//SHOULDDO: Do we need a mutex lock here... I don't think so, as we only check static const values of elements in a list that do not change. -//there is no guarantee in the standard, but it seems to me that the implementation is safe -UM -ReturnValue_t DataPool::getType(uint32_t parameter_id, Type* type) { - std::map::iterator it = this->data_pool.find( PIDToDataPoolId(parameter_id)); - if ( it != this->data_pool.end() ) { - *type = it->second->getType(); - return RETURN_OK; - } else { - *type = Type::UNKNOWN_TYPE; - return RETURN_FAILED; - } -} - -bool DataPool::exists(uint32_t parameterId) { - uint32_t poolId = PIDToDataPoolId(parameterId); - uint32_t index = PIDToArrayIndex(parameterId); - std::map::iterator it = this->data_pool.find( poolId ); - if (it != data_pool.end()) { - if (it->second->getSize() >= index) { - return true; - } - } - return false; -} diff --git a/datapool/DataPool.h b/datapool/DataPool.h deleted file mode 100644 index 7abf2898..00000000 --- a/datapool/DataPool.h +++ /dev/null @@ -1,135 +0,0 @@ -/** - * \file DataPool.h - * - * \date 10/17/2012 - * \author Bastian Baetz - * - * \brief This file contains the definition of the DataPool class and (temporarily) - * the "extern" definition of the global dataPool instance. - */ - -#ifndef DATAPOOL_H_ -#define DATAPOOL_H_ - -#include "PoolEntry.h" -#include "../globalfunctions/Type.h" -#include "../ipc/MutexIF.h" -#include - -/** - * \defgroup data_pool Data Pool - * This is the group, where all classes associated with Data Pool Handling belong to. - * This includes classes to access Data Pool variables. - */ - -#define DP_SUCCESSFUL 0 -#define DP_FAILURE 1 - -/** - * \brief This class represents the OBSW global data-pool. - * - * \details All variables are registered and space is allocated in an initialization - * function, which is passed do the constructor. - * Space for the variables is allocated on the heap (with a new call). - * The data is found by a data pool id, which uniquely represents a variable. - * Data pool variables should be used with a blackboard logic in mind, - * which means read data is valid (if flagged so), but not necessarily up-to-date. - * Variables are either single values or arrays. - * \ingroup data_pool - */ -class DataPool : public HasReturnvaluesIF { -private: - /** - * \brief This is the actual data pool itself. - * \details It is represented by a map - * with the data pool id as index and a pointer to a single PoolEntry as value. - */ - std::map data_pool; -public: - /** - * \brief The mutex is created in the constructor and makes access mutual exclusive. - * \details Locking and unlocking the pool is only done by the DataSet class. - */ - MutexIF* mutex; - /** - * \brief In the classes constructor, the passed initialization function is called. - * \details To enable filling the pool, - * a pointer to the map is passed, allowing direct access to the pool's content. - * On runtime, adding or removing variables is forbidden. - */ - DataPool( void ( *initFunction )( std::map* pool_map ) ); - /** - * \brief The destructor iterates through the data_pool map and calls all Entries destructors to clean up the heap. - */ - ~DataPool(); - /** - * \brief This is the default call to access the pool. - * \details A pointer to the PoolEntry object is returned. - * The call checks data pool id, type and array size. Returns NULL in case of failure. - * \param data_pool_id The data pool id to search. - * \param sizeOrPosition The array size (not byte size!) of the pool entry, or the position the user wants to read. - * If smaller than the entry size, everything's ok. - */ - template PoolEntry* getData( uint32_t data_pool_id, uint8_t sizeOrPosition ); - /** - * \brief An alternative call to get a data pool entry in case the type is not implicitly known - * (i.e. in Housekeeping Telemetry). - * \details It returns a basic interface and does NOT perform - * a size check. The caller has to assure he does not copy too much data. - * Returns NULL in case the entry is not found. - * \param data_pool_id The data pool id to search. - */ - PoolEntryIF* getRawData( uint32_t data_pool_id ); - /** - * \brief This is a small helper function to facilitate locking the global data pool. - * \details It fetches the pool's mutex id and tries to acquire the mutex. - */ - ReturnValue_t lockDataPool(); - /** - * \brief This is a small helper function to facilitate unlocking the global data pool. - * \details It fetches the pool's mutex id and tries to free the mutex. - */ - ReturnValue_t freeDataPoolLock(); - /** - * \brief The print call is a simple debug method. - * \details It prints the current content of the data pool. - * It iterates through the data_pool map and calls each entry's print() method. - */ - void print(); - /** - * Extracts the data pool id from a SCOS 2000 PID. - * @param parameter_id The passed Parameter ID. - * @return The data pool id as used within the OBSW. - */ - static uint32_t PIDToDataPoolId( uint32_t parameter_id ); - /** - * Extracts an array index out of a SCOS 2000 PID. - * @param parameter_id The passed Parameter ID. - * @return The index of the corresponding data pool entry. - */ - static uint8_t PIDToArrayIndex( uint32_t parameter_id ); - /** - * Retransforms a data pool id and an array index to a SCOS 2000 PID. - */ - static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index ); - - /** - * Method to return the type of a pool variable. - * @param parameter_id A parameterID (not pool id) of a DP member. - * @param type Returns the type or TYPE::UNKNOWN_TYPE - * @return RETURN_OK if parameter exists, RETURN_FAILED else. - */ - ReturnValue_t getType( uint32_t parameter_id, Type* type ); - - /** - * Method to check if a PID exists. - * Does not lock, as there's no possibility to alter the list that is checked during run-time. - * @param parameterId The PID (not pool id!) of a parameter. - * @return true if exists, false else. - */ - bool exists(uint32_t parameterId); -}; - -//We assume someone globally instantiates a DataPool. -extern DataPool dataPool; -#endif /* DATAPOOL_H_ */ diff --git a/datapool/DataSet.cpp b/datapool/DataSet.cpp deleted file mode 100644 index e41489bd..00000000 --- a/datapool/DataSet.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "DataSet.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -DataSet::DataSet() : - fill_count(0), state(DATA_SET_UNINITIALISED) { - for (unsigned count = 0; count < DATA_SET_MAX_SIZE; count++) { - registeredVariables[count] = NULL; - } -} - -DataSet::~DataSet() { - //Don't do anything with your variables, they are dead already! (Destructor is already called) -} - -ReturnValue_t DataSet::read() { - ReturnValue_t result = RETURN_OK; - if (state == DATA_SET_UNINITIALISED) { - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_WRITE - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - ReturnValue_t status = registeredVariables[count]->read(); - if (status != RETURN_OK) { - result = INVALID_PARAMETER_DEFINITION; - break; - } - } - } - state = DATA_SET_WAS_READ; - freeDataPoolLock(); - } else { - sif::error << "DataSet::read(): Call made in wrong position." << std::endl; - result = SET_WAS_ALREADY_READ; - } - return result; -} - -ReturnValue_t DataSet::commit(uint8_t valid) { - setValid(valid); - return commit(); -} - -ReturnValue_t DataSet::commit() { - if (state == DATA_SET_WAS_READ) { - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_READ - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commit(); - } - } - state = DATA_SET_UNINITIALISED; - freeDataPoolLock(); - return RETURN_OK; - } else { - ReturnValue_t result = RETURN_OK; - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - == PoolVariableIF::VAR_WRITE - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commit(); - } else if (registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - if (result != COMMITING_WITHOUT_READING) { - sif::error << - "DataSet::commit(): commit-without-read " - "call made with non write-only variable." << std::endl; - result = COMMITING_WITHOUT_READING; - } - } - } - state = DATA_SET_UNINITIALISED; - freeDataPoolLock(); - return result; - } - -} - -void DataSet::registerVariable(PoolVariableIF* variable) { - if (state == DATA_SET_UNINITIALISED) { - if (variable != NULL) { - if (fill_count < DATA_SET_MAX_SIZE) { - registeredVariables[fill_count] = variable; - fill_count++; - return; - } - } - } - sif::error - << "DataSet::registerVariable: failed. Either NULL, or set is full, or call made in wrong position." - << std::endl; - return; -} - -uint8_t DataSet::freeDataPoolLock() { - return ::dataPool.freeDataPoolLock(); -} - -uint8_t DataSet::lockDataPool() { - return ::dataPool.lockDataPool(); -} - -ReturnValue_t DataSet::serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = RETURN_FAILED; - for (uint16_t count = 0; count < fill_count; count++) { - result = registeredVariables[count]->serialize(buffer, size, maxSize, - streamEndianness); - if (result != RETURN_OK) { - return result; - } - } - return result; -} - -size_t DataSet::getSerializedSize() const { - size_t size = 0; - for (uint16_t count = 0; count < fill_count; count++) { - size += registeredVariables[count]->getSerializedSize(); - } - return size; -} - -void DataSet::setValid(uint8_t valid) { - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_READ) { - registeredVariables[count]->setValid(valid); - } - } -} - -ReturnValue_t DataSet::deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result = RETURN_FAILED; - for (uint16_t count = 0; count < fill_count; count++) { - result = registeredVariables[count]->deSerialize(buffer, size, - streamEndianness); - if (result != RETURN_OK) { - return result; - } - } - return result; -} diff --git a/datapool/DataSet.h b/datapool/DataSet.h deleted file mode 100644 index 04044bfe..00000000 --- a/datapool/DataSet.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * \file DataSet.h - * - * \brief This file contains the DataSet class and a small structure called DataSetContent. - * - * \date 10/17/2012 - * - * \author Bastian Baetz - * - */ - -#ifndef DATASET_H_ -#define DATASET_H_ - -#include "DataPool.h" -#include "DataSetIF.h" -#include "PoolRawAccess.h" -#include "PoolVariable.h" -#include "PoolVarList.h" -#include "PoolVector.h" -#include "../serialize/SerializeAdapter.h" -/** - * \brief The DataSet class manages a set of locally checked out variables. - * - * \details This class manages a list, where a set of local variables (or pool variables) are - * registered. They are checked-out (i.e. their values are looked up and copied) - * with the read call. After the user finishes working with the pool variables, - * he can write back all variable values to the pool with the commit call. - * The data set manages locking and freeing the data pool, to ensure that all values - * are read and written back at once. - * An internal state manages usage of this class. Variables may only be registered before - * the read call is made, and the commit call only after the read call. - * If pool variables are writable and not committed until destruction of the set, the - * DataSet class automatically sets the valid flag in the data pool to invalid (without) - * changing the variable's value. - * - * \ingroup data_pool - */ -class DataSet: public DataSetIF, public HasReturnvaluesIF, public SerializeIF { -private: - //SHOULDDO we could use a linked list of datapool variables - static const uint8_t DATA_SET_MAX_SIZE = 63; //!< This definition sets the maximum number of variables to register in one DataSet. - - /** - * \brief This array represents all pool variables registered in this set. - * \details It has a maximum size of DATA_SET_MAX_SIZE. - */ - PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; - /** - * \brief The fill_count attribute ensures that the variables register in the correct array - * position and that the maximum number of variables is not exceeded. - */ - uint16_t fill_count; - /** - * States of the seet. - */ - enum States { - DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED - DATA_SET_WAS_READ //!< DATA_SET_WAS_READ - }; - /** - * \brief state manages the internal state of the data set, which is important e.g. for the - * behavior on destruction. - */ - States state; - /** - * \brief This is a small helper function to facilitate locking the global data pool. - * \details It makes use of the lockDataPool method offered by the DataPool class. - */ - uint8_t lockDataPool(); - /** - * \brief This is a small helper function to facilitate unlocking the global data pool. - * \details It makes use of the freeDataPoolLock method offered by the DataPool class. - */ - uint8_t freeDataPoolLock(); - -public: - static const uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; - static const ReturnValue_t INVALID_PARAMETER_DEFINITION = - MAKE_RETURN_CODE( 0x01 ); - static const ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); - static const ReturnValue_t COMMITING_WITHOUT_READING = - MAKE_RETURN_CODE(0x03); - - /** - * \brief The constructor simply sets the fill_count to zero and sets the state to "uninitialized". - */ - DataSet(); - /** - * \brief The destructor automatically manages writing the valid information of variables. - * \details In case the data set was read out, but not committed (indicated by state), - * the destructor parses all variables that are still registered to the set. - * For each, the valid flag in the data pool is set to "invalid". - */ - ~DataSet(); - /** - * \brief The read call initializes reading out all registered variables. - * \details It iterates through the list of registered variables and calls all read() - * functions of the registered pool variables (which read out their values from the - * data pool) which are not write-only. In case of an error (e.g. a wrong data type, - * or an invalid data pool id), the operation is aborted and - * \c INVALID_PARAMETER_DEFINITION returned. - * The data pool is locked during the whole read operation and freed afterwards. - * The state changes to "was written" after this operation. - * \return - \c RETURN_OK if all variables were read successfully. - * - \c INVALID_PARAMETER_DEFINITION if PID, size or type of the - * requested variable is invalid. - * - \c SET_WAS_ALREADY_READ if read() is called twice without calling - * commit() in between - */ - ReturnValue_t read(); - /** - * \brief The commit call initializes writing back the registered variables. - * \details It iterates through the list of registered variables and calls - * the commit() method of the remaining registered variables (which write back - * their values to the pool). - * The data pool is locked during the whole commit operation and freed afterwards. - * The state changes to "was committed" after this operation. - * If the set does contain at least one variable which is not write-only commit() - * can only be called after read(). If the set only contains variables which are - * write only, commit() can be called without a preceding read() call. - * \return - \c RETURN_OK if all variables were read successfully. - * - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only - * variables - */ - ReturnValue_t commit(void); - /** - * Variant of method above which sets validity of all elements of the set. - * @param valid Validity information from PoolVariableIF. - * \return - \c RETURN_OK if all variables were read successfully. - * - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only - * variables - */ - ReturnValue_t commit(uint8_t valid); - /** - * \brief This operation is used to register the local variables in the set. - * \details It copies all required information to the currently - * free space in the registeredVariables list. - */ - void registerVariable(PoolVariableIF* variable); - - /** - * Set the valid information of all variables contained in the set which are not readonly - * - * @param valid Validity information from PoolVariableIF. - */ - void setValid(uint8_t valid); - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - size_t getSerializedSize() const override; - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - -}; - -#endif /* DATASET_H_ */ diff --git a/datapool/DataSetIF.h b/datapool/DataSetIF.h index 7741477d..a6634a5c 100644 --- a/datapool/DataSetIF.h +++ b/datapool/DataSetIF.h @@ -1,39 +1,47 @@ -/** - * \file DataSetIF.h - * - * \brief This file contains the small interface to access the DataSet class. - * - * \date 10/23/2012 - * - * \author Bastian Baetz - * - */ - -#ifndef DATASETIF_H_ -#define DATASETIF_H_ +#ifndef FSFW_DATAPOOL_DATASETIF_H_ +#define FSFW_DATAPOOL_DATASETIF_H_ +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../timemanager/Clock.h" class PoolVariableIF; /** - * \brief This class defines a small interface to register on a DataSet. + * @brief This class defines a small interface to register on a DataSet. * - * \details Currently, the only purpose of this interface is to provide a method for locally - * checked-out variables to register on a data set. Still, it may become useful for - * other purposes as well. - * - * \ingroup data_pool + * @details + * Currently, the only purpose of this interface is to provide a + * method for locally checked-out variables to register on a data set. + * Still, it may become useful for other purposes as well. + * @author Bastian Baetz + * @ingroup data_pool */ class DataSetIF { public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; + static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = + MAKE_RETURN_CODE( 0x01 ); + static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); + static constexpr ReturnValue_t COMMITING_WITHOUT_READING = + MAKE_RETURN_CODE(0x03); + + static constexpr ReturnValue_t DATA_SET_UNINITIALISED = MAKE_RETURN_CODE( 0x04 ); + static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE( 0x05 ); + static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE( 0x06 ); + /** - * \brief This is an empty virtual destructor, as it is proposed for C++ interfaces. + * @brief This is an empty virtual destructor, + * as it is proposed for C++ interfaces. */ virtual ~DataSetIF() {} + /** - * \brief This operation provides a method to register local data pool variables - * to register in a data set by passing itself to this DataSet operation. + * @brief This operation provides a method to register local data pool + * variables to register in a data set by passing itself + * to this DataSet operation. */ - virtual void registerVariable( PoolVariableIF* variable ) = 0; + virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0; + + virtual uint16_t getFillCount() const = 0; }; -#endif /* DATASETIF_H_ */ +#endif /* FSFW_DATAPOOL_DATASETIF_H_ */ diff --git a/datapool/HkSwitchHelper.cpp b/datapool/HkSwitchHelper.cpp index 04096aca..1a2a25eb 100644 --- a/datapool/HkSwitchHelper.cpp +++ b/datapool/HkSwitchHelper.cpp @@ -1,5 +1,4 @@ -#include "HkSwitchHelper.h" -//#include +#include "../datapool/HkSwitchHelper.h" #include "../ipc/QueueFactory.h" HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) : @@ -22,14 +21,14 @@ ReturnValue_t HkSwitchHelper::initialize() { } ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) { - CommandMessage message; - while (actionQueue->receiveMessage(&message) == HasReturnvaluesIF::RETURN_OK) { - ReturnValue_t result = commandActionHelper.handleReply(&message); + CommandMessage command; + while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) { + ReturnValue_t result = commandActionHelper.handleReply(&command); if (result == HasReturnvaluesIF::RETURN_OK) { continue; } - message.setToUnknownCommand(); - actionQueue->reply(&message); + command.setToUnknownCommand(); + actionQueue->reply(&command); } return HasReturnvaluesIF::RETURN_OK; diff --git a/datapool/HkSwitchHelper.h b/datapool/HkSwitchHelper.h index 385b2047..bb9e7dc6 100644 --- a/datapool/HkSwitchHelper.h +++ b/datapool/HkSwitchHelper.h @@ -13,7 +13,7 @@ class HkSwitchHelper: public ExecutableObjectIF, public CommandsActionsIF { public: static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HK; - static const Event SWITCHING_TM_FAILED = MAKE_EVENT(1, SEVERITY::LOW); //!< Commanding the HK Service failed, p1: error code, p2 action: 0 disable / 1 enable + static const Event SWITCHING_TM_FAILED = MAKE_EVENT(1, severity::LOW); //!< Commanding the HK Service failed, p1: error code, p2 action: 0 disable / 1 enable HkSwitchHelper(EventReportingProxyIF *eventProxy); virtual ~HkSwitchHelper(); diff --git a/datapool/PoolDataSetBase.cpp b/datapool/PoolDataSetBase.cpp new file mode 100644 index 00000000..1acd3fd3 --- /dev/null +++ b/datapool/PoolDataSetBase.cpp @@ -0,0 +1,169 @@ +#include "PoolDataSetBase.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray, + const size_t maxFillCount): + registeredVariables(registeredVariablesArray), + maxFillCount(maxFillCount) { +} + +PoolDataSetBase::~PoolDataSetBase() {} + +ReturnValue_t PoolDataSetBase::registerVariable( + PoolVariableIF *variable) { + if (state != States::DATA_SET_UNINITIALISED) { + sif::error << "DataSet::registerVariable: " + "Call made in wrong position." << std::endl; + return DataSetIF::DATA_SET_UNINITIALISED; + } + if (variable == nullptr) { + sif::error << "DataSet::registerVariable: " + "Pool variable is nullptr." << std::endl; + return DataSetIF::POOL_VAR_NULL; + } + if (fillCount >= maxFillCount) { + sif::error << "DataSet::registerVariable: " + "DataSet is full." << std::endl; + return DataSetIF::DATA_SET_FULL; + } + registeredVariables[fillCount] = variable; + fillCount++; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PoolDataSetBase::read(uint32_t lockTimeout) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if (state == States::DATA_SET_UNINITIALISED) { + lockDataPool(lockTimeout); + for (uint16_t count = 0; count < fillCount; count++) { + result = readVariable(count); + if(result != RETURN_OK) { + break; + } + } + state = States::DATA_SET_WAS_READ; + unlockDataPool(); + } + else { + sif::error << "DataSet::read(): " + "Call made in wrong position. Don't forget to commit" + " member datasets!" << std::endl; + result = SET_WAS_ALREADY_READ; + } + return result; +} + +uint16_t PoolDataSetBase::getFillCount() const { + return fillCount; +} + +ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + // These checks are often performed by the respective + // variable implementation too, but I guess a double check does not hurt. + if (registeredVariables[count]->getReadWriteMode() != + PoolVariableIF::VAR_WRITE and + registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) + { + result = registeredVariables[count]->readWithoutLock(); + if(result != HasReturnvaluesIF::RETURN_OK) { + result = INVALID_PARAMETER_DEFINITION; + } + } + return result; +} + +ReturnValue_t PoolDataSetBase::commit(uint32_t lockTimeout) { + if (state == States::DATA_SET_WAS_READ) { + handleAlreadyReadDatasetCommit(lockTimeout); + return HasReturnvaluesIF::RETURN_OK; + } + else { + return handleUnreadDatasetCommit(lockTimeout); + } +} + +void PoolDataSetBase::handleAlreadyReadDatasetCommit(uint32_t lockTimeout) { + lockDataPool(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(); + } + } + state = States::DATA_SET_UNINITIALISED; + unlockDataPool(); +} + +ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(uint32_t lockTimeout) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + lockDataPool(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(); + } else if (registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + if (result != COMMITING_WITHOUT_READING) { + sif::error << "DataSet::commit(): commit-without-read call made " + "with non write-only variable." << std::endl; + result = COMMITING_WITHOUT_READING; + } + } + } + state = States::DATA_SET_UNINITIALISED; + unlockDataPool(); + return result; +} + + +ReturnValue_t PoolDataSetBase::lockDataPool(uint32_t timeoutMs) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PoolDataSetBase::unlockDataPool() { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, SerializeIF::Endianness streamEndianness) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->serialize(buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +ReturnValue_t PoolDataSetBase::deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->deSerialize(buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +size_t PoolDataSetBase::getSerializedSize() const { + uint32_t size = 0; + for (uint16_t count = 0; count < fillCount; count++) { + size += registeredVariables[count]->getSerializedSize(); + } + return size; +} + +void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) { + this->registeredVariables = variablesContainer; +} diff --git a/datapool/PoolDataSetBase.h b/datapool/PoolDataSetBase.h new file mode 100644 index 00000000..a8931d62 --- /dev/null +++ b/datapool/PoolDataSetBase.h @@ -0,0 +1,152 @@ +#ifndef FSFW_DATAPOOL_POOLDATASETBASE_H_ +#define FSFW_DATAPOOL_POOLDATASETBASE_H_ + +#include "PoolDataSetIF.h" +#include "PoolVariableIF.h" +#include "../ipc/MutexIF.h" + +/** + * @brief The DataSetBase class manages a set of locally checked out variables. + * @details + * This class manages a list, where a set of local variables (or pool variables) + * are registered. They are checked-out (i.e. their values are looked + * up and copied) with the read call. After the user finishes working with the + * pool variables, he can write back all variable values to the pool with + * the commit call. The data set manages locking and freeing the data pool, + * to ensure that all values are read and written back at once. + * + * An internal state manages usage of this class. Variables may only be + * registered before the read call is made, and the commit call only + * after the read call. + * + * If pool variables are writable and not committed until destruction + * of the set, the DataSet class automatically sets the valid flag in the + * data pool to invalid (without) changing the variable's value. + * + * The base class lockDataPool und unlockDataPool implementation are empty + * and should be implemented to protect the underlying pool type. + * @author Bastian Baetz + * @ingroup data_pool + */ +class PoolDataSetBase: public PoolDataSetIF, + public SerializeIF, + public HasReturnvaluesIF { +public: + + /** + * @brief Creates an empty dataset. Use registerVariable or + * supply a pointer to this dataset to PoolVariable + * initializations to register pool variables. + */ + PoolDataSetBase(PoolVariableIF** registeredVariablesArray, + const size_t maxFillCount); + virtual~ PoolDataSetBase(); + + /** + * @brief The read call initializes reading out all registered variables. + * @details + * It iterates through the list of registered variables and calls all read() + * functions of the registered pool variables (which read out their values + * from the data pool) which are not write-only. + * In case of an error (e.g. a wrong data type, or an invalid data pool id), + * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. + * + * The data pool is locked during the whole read operation and + * freed afterwards.The state changes to "was written" after this operation. + * @return + * - @c RETURN_OK if all variables were read successfully. + * - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the + * requested variable is invalid. + * - @c SET_WAS_ALREADY_READ if read() is called twice without calling + * commit() in between + */ + virtual ReturnValue_t read(uint32_t lockTimeout = + MutexIF::BLOCKING) override; + /** + * @brief The commit call initializes writing back the registered variables. + * @details + * It iterates through the list of registered variables and calls the + * commit() method of the remaining registered variables (which write back + * their values to the pool). + * + * The data pool is locked during the whole commit operation and + * freed afterwards. The state changes to "was committed" after this operation. + * + * If the set does contain at least one variable which is not write-only + * commit() can only be called after read(). If the set only contains + * variables which are write only, commit() can be called without a + * preceding read() call. + * @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; + + /** + * Register the passed pool variable instance into the data set. + * @param variable + * @return + */ + virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override; + /** + * Provides the means to lock the underlying data structure to ensure + * thread-safety. Default implementation is empty + * @return Always returns -@c RETURN_OK + */ + virtual ReturnValue_t lockDataPool(uint32_t timeoutMs = + MutexIF::BLOCKING) override; + /** + * Provides the means to unlock the underlying data structure to ensure + * thread-safety. Default implementation is empty + * @return Always returns -@c RETURN_OK + */ + virtual ReturnValue_t unlockDataPool() override; + + virtual uint16_t getFillCount() const; + + /* SerializeIF implementations */ + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; + +protected: + /** + * @brief The fill_count attribute ensures that the variables + * register in the correct array position and that the maximum + * number of variables is not exceeded. + */ + uint16_t fillCount = 0; + /** + * States of the seet. + */ + enum class States { + DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED + DATA_SET_WAS_READ //!< DATA_SET_WAS_READ + }; + /** + * @brief state manages the internal state of the data set, + * which is important e.g. for the behavior on destruction. + */ + States state = States::DATA_SET_UNINITIALISED; + + /** + * @brief This array represents all pool variables registered in this set. + * Child classes can use a static or dynamic container to create + * an array of registered variables and assign the first entry here. + */ + PoolVariableIF** registeredVariables = nullptr; + const size_t maxFillCount = 0; + + void setContainer(PoolVariableIF** variablesContainer); + +private: + ReturnValue_t readVariable(uint16_t count); + void handleAlreadyReadDatasetCommit(uint32_t lockTimeout); + ReturnValue_t handleUnreadDatasetCommit(uint32_t lockTimeout); +}; + +#endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */ diff --git a/datapool/PoolDataSetIF.h b/datapool/PoolDataSetIF.h new file mode 100644 index 00000000..aa45fa54 --- /dev/null +++ b/datapool/PoolDataSetIF.h @@ -0,0 +1,33 @@ +#ifndef FSFW_DATAPOOL_POOLDATASETIF_H_ +#define FSFW_DATAPOOL_POOLDATASETIF_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 { +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; + /** + * @brief Unlock call corresponding to the lock call. + * @return Unlock operation result + */ + virtual ReturnValue_t unlockDataPool() = 0; + + virtual bool isValid() const = 0; +}; + +#endif /* FSFW_DATAPOOL_POOLDATASETIF_H_ */ diff --git a/datapool/PoolEntry.cpp b/datapool/PoolEntry.cpp index 56e489a5..fb73328c 100644 --- a/datapool/PoolEntry.cpp +++ b/datapool/PoolEntry.cpp @@ -1,4 +1,5 @@ #include "PoolEntry.h" + #include "../serviceinterface/ServiceInterfaceStream.h" #include "../globalfunctions/arrayprinter.h" #include diff --git a/datapool/PoolEntry.h b/datapool/PoolEntry.h index 7b47c673..033db40d 100644 --- a/datapool/PoolEntry.h +++ b/datapool/PoolEntry.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_DATAPOOL_POOLENTRY_H_ -#define FRAMEWORK_DATAPOOL_POOLENTRY_H_ +#ifndef FSFW_DATAPOOL_POOLENTRY_H_ +#define FSFW_DATAPOOL_POOLENTRY_H_ #include "PoolEntryIF.h" @@ -127,4 +127,4 @@ public: Type getType(); }; -#endif /* POOLENTRY_H_ */ +#endif /* FSFW_DATAPOOL_POOLENTRY_H_ */ diff --git a/datapool/PoolEntryIF.h b/datapool/PoolEntryIF.h index 462de18b..d9db5237 100644 --- a/datapool/PoolEntryIF.h +++ b/datapool/PoolEntryIF.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_DATAPOOL_POOLENTRYIF_H_ -#define FRAMEWORK_DATAPOOL_POOLENTRYIF_H_ +#ifndef FSFW_DATAPOOL_POOLENTRYIF_H_ +#define FSFW_DATAPOOL_POOLENTRYIF_H_ #include "../globalfunctions/Type.h" #include @@ -60,4 +60,4 @@ public: virtual Type getType() = 0; }; -#endif /* POOLENTRYIF_H_ */ +#endif /* FSFW_DATAPOOL_POOLENTRYIF_H_ */ diff --git a/datapool/PoolRawAccess.cpp b/datapool/PoolRawAccess.cpp deleted file mode 100644 index f9264081..00000000 --- a/datapool/PoolRawAccess.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "DataPool.h" -#include "PoolEntryIF.h" -#include "PoolRawAccess.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../serialize/EndianConverter.h" - -#include - -PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry, - DataSetIF *data_set, ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), type( - Type::UNKNOWN_TYPE), typeSize(0), arraySize(0), sizeTillEnd(0), readWriteMode( - setReadWriteMode) { - memset(value, 0, sizeof(value)); - if (data_set != NULL) { - data_set->registerVariable(this); - } -} - -PoolRawAccess::~PoolRawAccess() { - -} - -ReturnValue_t PoolRawAccess::read() { - PoolEntryIF *read_out = ::dataPool.getRawData(dataPoolId); - if (read_out != NULL) { - valid = read_out->getValid(); - if (read_out->getSize() > arrayEntry) { - arraySize = read_out->getSize(); - typeSize = read_out->getByteSize() / read_out->getSize(); - type = read_out->getType(); - if (typeSize <= sizeof(value)) { - uint16_t arrayPosition = arrayEntry * typeSize; - sizeTillEnd = read_out->getByteSize() - arrayPosition; - uint8_t *ptr = - &((uint8_t*) read_out->getRawData())[arrayPosition]; - memcpy(value, ptr, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - //Error value type too large. - } - } else { - //Error index requested too large - } - } else { - //Error entry does not exist. - } - sif::error << "PoolRawAccess: read of DP Variable 0x" << std::hex - << dataPoolId << std::dec << " failed." << std::endl; - valid = INVALID; - typeSize = 0; - sizeTillEnd = 0; - memset(value, 0, sizeof(value)); - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t PoolRawAccess::commit() { - PoolEntryIF *write_back = ::dataPool.getRawData(dataPoolId); - if ((write_back != NULL) && (readWriteMode != VAR_READ)) { - write_back->setValid(valid); - uint8_t array_position = arrayEntry * typeSize; - uint8_t *ptr = &((uint8_t*) write_back->getRawData())[array_position]; - memcpy(ptr, value, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t* PoolRawAccess::getEntry() { - return value; -} - -ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t *buffer, - size_t *writtenBytes, size_t maxSize) { - uint8_t *data_ptr = getEntry(); -// debug << "PoolRawAccess::getEntry: Array position: " << index * size_of_type << " Size of T: " << (int)size_of_type << " ByteSize: " << byte_size << " Position: " << *size << std::endl; - if (typeSize == 0) { - return DATA_POOL_ACCESS_FAILED; - } - if (typeSize > maxSize) { - return INCORRECT_SIZE; - } - EndianConverter::convertBigEndian(buffer, data_ptr, typeSize); - *writtenBytes = typeSize; - return HasReturnvaluesIF::RETURN_OK; -} - -Type PoolRawAccess::getType() { - return type; -} - -size_t PoolRawAccess::getSizeOfType() { - return typeSize; -} - -size_t PoolRawAccess::getArraySize() { - return arraySize; -} - -uint32_t PoolRawAccess::getDataPoolId() const { - return dataPoolId; -} - -PoolVariableIF::ReadWriteMode_t PoolRawAccess::getReadWriteMode() const { - return readWriteMode; -} - -ReturnValue_t PoolRawAccess::setEntryFromBigEndian(const uint8_t *buffer, - size_t setSize) { - if (typeSize == setSize) { - EndianConverter::convertBigEndian(value, buffer, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - sif::error - << "PoolRawAccess::setEntryFromBigEndian: Illegal sizes: Internal" - << (uint32_t) typeSize << ", Requested: " << setSize - << std::endl; - return INCORRECT_SIZE; - } -} - -bool PoolRawAccess::isValid() const { - if (valid != INVALID) - return true; - else - return false; -} - -void PoolRawAccess::setValid(uint8_t valid) { - this->valid = valid; -} - -size_t PoolRawAccess::getSizeTillEnd() const { - return sizeTillEnd; -} - -ReturnValue_t PoolRawAccess::serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const { - if (typeSize + *size <= maxSize) { - switch (streamEndianness) { - case (Endianness::BIG): - EndianConverter::convertBigEndian(*buffer, value, typeSize); - break; - case (Endianness::LITTLE): - EndianConverter::convertLittleEndian(*buffer, value, typeSize); - break; - default: - case (Endianness::MACHINE): - memcpy(*buffer, value, typeSize); - break; - } - *size += typeSize; - (*buffer) += typeSize; - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } -} - -size_t PoolRawAccess::getSerializedSize() const { - return typeSize; -} - -ReturnValue_t PoolRawAccess::deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) { - - if (*size >= typeSize) { - switch (streamEndianness) { - case (Endianness::BIG): - EndianConverter::convertBigEndian(value, *buffer, typeSize); - break; - case (Endianness::LITTLE): - EndianConverter::convertLittleEndian(value, *buffer, typeSize); - break; - default: - case (Endianness::MACHINE): - memcpy(value, *buffer, typeSize); - break; - } - *size -= typeSize; - *buffer += typeSize; - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::STREAM_TOO_SHORT; - } -} diff --git a/datapool/PoolRawAccess.h b/datapool/PoolRawAccess.h deleted file mode 100644 index 0c7a06bf..00000000 --- a/datapool/PoolRawAccess.h +++ /dev/null @@ -1,152 +0,0 @@ -#ifndef POOLRAWACCESS_H_ -#define POOLRAWACCESS_H_ - -#include "DataSetIF.h" -#include "PoolVariableIF.h" - -/** - * This class allows accessing Data Pool variables as raw bytes. - * This is necessary to have an access method for HK data, as the PID's alone do not - * provide a type information. - * \ingroup data_pool - */ -class PoolRawAccess: public PoolVariableIF { -private: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The array entry that is fetched from the data pool. - */ - uint8_t arrayEntry; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief This value contains the type of the data pool entry. - */ - Type type; - /** - * \brief This value contains the size of the data pool entry in bytes. - */ - size_t typeSize; - /** - * The size of the DP array (single values return 1) - */ - size_t arraySize; - /** - * The size (in bytes) from the selected entry till the end of this DataPool variable. - */ - size_t sizeTillEnd; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - static const uint8_t RAW_MAX_SIZE = sizeof(double); -protected: - /** - * \brief This is a call to read the value from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read(); - /** - * \brief The commit call writes back the variable's value to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit(); -public: - static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; - static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); - uint8_t value[RAW_MAX_SIZE]; - PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, - DataSetIF *data_set, ReadWriteMode_t setReadWriteMode = - PoolVariableIF::VAR_READ); - /** - * \brief The classes destructor is empty. If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolRawAccess(); - /** - * \brief This operation returns a pointer to the entry fetched. - * \details This means, it does not return a pointer to byte "index", but to the start byte of - * array entry "index". Example: If the original data pool array consists of an double - * array of size four, getEntry(1) returns &(this->value[8]). - */ - uint8_t* getEntry(); - /** - * \brief This operation returns the fetched entry from the data pool and - * flips the bytes, if necessary. - * \details It makes use of the getEntry call of this function, but additionally flips the - * bytes to big endian, which is the default for external communication (as House- - * keeping telemetry). To achieve this, the data is copied directly to the passed - * buffer, if it fits in the given maxSize. - * \param buffer A pointer to a buffer to write to - * \param writtenBytes The number of bytes written is returned with this value. - * \param maxSize The maximum size that the function may write to buffer. - * \return - \c RETURN_OK if entry could be acquired - * - \c RETURN_FAILED else. - */ - ReturnValue_t getEntryEndianSafe(uint8_t *buffer, size_t *size, - size_t maxSize); - /** - * With this method, the content can be set from a big endian buffer safely. - * @param buffer Pointer to the data to set - * @param size Size of the data to write. Must fit this->size. - * @return - \c RETURN_OK on success - * - \c RETURN_FAILED on failure - */ - ReturnValue_t setEntryFromBigEndian(const uint8_t *buffer, - size_t setSize); - /** - * \brief This operation returns the type of the entry currently stored. - */ - Type getType(); - /** - * \brief This operation returns the size of the entry currently stored. - */ - size_t getSizeOfType(); - /** - * - * @return the size of the datapool array - */ - size_t getArraySize(); - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const; - /** - * This method returns if the variable is read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const; - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const; - - void setValid(uint8_t valid); - /** - * Getter for the remaining size. - */ - size_t getSizeTillEnd() const; - - ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const override; - - size_t getSerializedSize() const override; - - ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override; -}; - -#endif /* POOLRAWACCESS_H_ */ diff --git a/datapool/PoolVarList.h b/datapool/PoolVarList.h index 035ff2ac..0b2b0f06 100644 --- a/datapool/PoolVarList.h +++ b/datapool/PoolVarList.h @@ -1,14 +1,15 @@ -#ifndef POOLVARLIST_H_ -#define POOLVARLIST_H_ +#ifndef FSFW_DATAPOOL_POOLVARLIST_H_ +#define FSFW_DATAPOOL_POOLVARLIST_H_ -#include "PoolVariable.h" -#include "PoolVariableIF.h" +#include "../datapool/PoolVariableIF.h" +#include "../datapoolglob/GlobalPoolVariable.h" template class PoolVarList { private: - PoolVariable variables[n_var]; + GlobPoolVar variables[n_var]; public: - PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, PoolVariableIF::ReadWriteMode_t setReadWriteMode ) { + PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, + PoolVariableIF::ReadWriteMode_t setReadWriteMode ) { //I really should have a look at the new init list c++ syntax. if (dataSet == NULL) { return; @@ -20,9 +21,9 @@ public: } } - PoolVariable &operator [](int i) { return variables[i]; } + GlobPoolVar &operator [](int i) { return variables[i]; } }; -#endif /* POOLVARLIST_H_ */ +#endif /* FSFW_DATAPOOL_POOLVARLIST_H_ */ diff --git a/datapool/PoolVariable.h b/datapool/PoolVariable.h deleted file mode 100644 index a9d3407d..00000000 --- a/datapool/PoolVariable.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * \file PoolVariable.h - * - * \brief This file contains the PoolVariable class, which locally represents a non-array data pool variable. - * - * \date 10/17/2012 - * - * \author Bastian Baetz - */ - -#ifndef POOLVARIABLE_H_ -#define POOLVARIABLE_H_ - -#include "DataSetIF.h" -#include "PoolEntry.h" -#include "PoolVariableIF.h" -#include "../serialize/SerializeAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -template class PoolVarList; - -/** - * \brief This is the access class for non-array data pool entries. - * - * \details To ensure safe usage of the data pool, operation is not done directly on the data pool - * entries, but on local copies. This class provides simple type-safe access to single - * data pool entries (i.e. entries with length = 1). - * The class can be instantiated as read-write and read only. - * It provides a commit-and-roll-back semantic, which means that the variable's value in - * the data pool is not changed until the commit call is executed. - * \tparam T The template parameter sets the type of the variable. Currently, all plain data types - * are supported, but in principle any type is possible. - * \ingroup data_pool - */ -template -class PoolVariable: public PoolVariableIF { - template friend class PoolVarList; -protected: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - /** - * \brief This is a call to read the value from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read() { - PoolEntry *read_out = ::dataPool.getData < T > (dataPoolId, 1); - if (read_out != NULL) { - valid = read_out->valid; - value = *(read_out->address); - return HasReturnvaluesIF::RETURN_OK; - } else { - value = 0; - valid = false; - sif::error << "PoolVariable: read of DP Variable 0x" << std::hex - << dataPoolId << std::dec << " failed." << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * \brief The commit call writes back the variable's value to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit() { - PoolEntry *write_back = ::dataPool.getData < T > (dataPoolId, 1); - if ((write_back != NULL) && (readWriteMode != VAR_READ)) { - write_back->valid = valid; - *(write_back->address) = value; - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * Empty ctor for List initialization - */ - PoolVariable() : - dataPoolId(PoolVariableIF::NO_PARAMETER), valid( - PoolVariableIF::INVALID), readWriteMode(VAR_READ), value(0) { - - } -public: - /** - * \brief This is the local copy of the data pool entry. - * \details The user can work on this attribute - * just like he would on a simple local variable. - */ - T value; - /** - * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is - * passed). - * \details It DOES NOT fetch the current value from the data pool, but sets the value - * attribute to default (0). The value is fetched within the read() operation. - * \param set_id This is the id in the global data pool this instance of the access class - * corresponds to. - * \param dataSet The data set in which the variable shall register itself. If NULL, - * the variable is not registered. - * \param setWritable If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. - */ - PoolVariable(uint32_t set_id, DataSetIF *dataSet, - ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), valid(PoolVariableIF::INVALID), readWriteMode( - setReadWriteMode), value(0) { - if (dataSet != NULL) { - dataSet->registerVariable(this); - } - } - /** - * Copy ctor to copy classes containing Pool Variables. - */ - PoolVariable(const PoolVariable &rhs) : - dataPoolId(rhs.dataPoolId), valid(rhs.valid), readWriteMode( - rhs.readWriteMode), value(rhs.value) { - } - - /** - * \brief The classes destructor is empty. - * \details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolVariable() { - - } - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const { - return dataPoolId; - } - /** - * This operation sets the data pool id of the variable. - * The method is necessary to set id's of data pool member variables with bad initialization. - */ - void setDataPoolId(uint32_t poolId) { - dataPoolId = poolId; - } - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const { - return readWriteMode; - } - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const { - if (valid) - return true; - else - return false; - } - - uint8_t getValid() { - return valid; - } - - void setValid(uint8_t valid) { - this->valid = valid; - } - - operator T() { - return value; - } - - operator T() const { - return value; - } - - PoolVariable& operator=(T newValue) { - value = newValue; - return *this; - } - - PoolVariable& operator=(PoolVariable newPoolVariable) { - value = newPoolVariable.value; - return *this; - } - - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const override { - return SerializeAdapter::serialize(&value, buffer, size, maxSize, - streamEndianness); - } - - virtual size_t getSerializedSize() const override { - return SerializeAdapter::getSerializedSize(&value); - } - - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override { - return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); - } -}; - -typedef PoolVariable db_uint8_t; -typedef PoolVariable db_uint16_t; -typedef PoolVariable db_uint32_t; -typedef PoolVariable db_int8_t; -typedef PoolVariable db_int16_t; -typedef PoolVariable db_int32_t; -typedef PoolVariable db_bool_t; -typedef PoolVariable db_float_t; -typedef PoolVariable db_double_t; -//Alternative (but I thing this is not as useful: code duplication, differences too small): - -//template -//class PoolReader : public PoolVariableIF { -//private: -// uint32_t parameter_id; -// uint8_t valid; -//public: -// T value; -// PoolReader( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), valid(false), value(0) { -// set->registerVariable( this ); -// } -// -// ~PoolReader() {}; -// -// uint8_t commit() { -// return HasReturnvaluesIF::RETURN_OK; -// } -// -// uint8_t read() { -// PoolEntry* read_out = ::dataPool.getData( parameter_id, 1 ); -// if ( read_out != NULL ) { -// valid = read_out->valid; -// value = *(read_out->address); -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// value = 0; -// valid = false; -// return CHECKOUT_FAILED; -// } -// } -// uint32_t getParameterId() { return parameter_id; } -// bool isWritable() { return false; }; -// bool isValid() { if (valid) return true; else return false; } -//}; -// -//template -//class PoolWriter : public PoolVariableIF { -//private: -// uint32_t parameter_id; -//public: -// T value; -// PoolWriter( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), value(0) { -// set->registerVariable( this ); -// } -// -// ~PoolWriter() {}; -// -// uint8_t commit() { -// PoolEntry* write_back = ::dataPool.getData( parameter_id, 1 ); -// if ( write_back != NULL ) { -// write_back->valid = true; -// *(write_back->address) = value; -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// return CHECKOUT_FAILED; -// } -// } -// uint8_t read() { -// PoolEntry* read_out = ::dataPool.getData( parameter_id, 1 ); -// if ( read_out != NULL ) { -// value = *(read_out->address); -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// value = 0; -// return CHECKOUT_FAILED; -// } -// } -// uint32_t getParameterId() { return parameter_id; } -// bool isWritable() { return true; }; -// bool isValid() { return false; } -//}; - -#endif /* POOLVARIABLE_H_ */ diff --git a/datapool/PoolVariableIF.h b/datapool/PoolVariableIF.h index f47173df..cd15f744 100644 --- a/datapool/PoolVariableIF.h +++ b/datapool/PoolVariableIF.h @@ -1,71 +1,99 @@ -/* - * \file PoolVariableIF.h - * - * \brief This file contains the interface definition for pool variables. - * - * \date 10/17/2012 - * - * \author Bastian Baetz - */ - -#ifndef POOLVARIABLEIF_H_ -#define POOLVARIABLEIF_H_ +#ifndef FSFW_DATAPOOL_POOLVARIABLEIF_H_ +#define FSFW_DATAPOOL_POOLVARIABLEIF_H_ #include "../returnvalues/HasReturnvaluesIF.h" #include "../serialize/SerializeIF.h" /** - * \brief This interface is used to control local data pool variable representations. - * - * \details To securely handle data pool variables, all pool entries are locally managed by - * data pool variable access classes, which are called pool variables. To ensure a - * common state of a set of variables needed in a function, these local pool variables - * again are managed by other classes, e.g. the DataSet. This interface provides unified - * access to local pool variables for such manager classes. - * \ingroup data_pool + * @brief This interface is used to control data pool + * variable representations. + * @details + * To securely handle data pool variables, all pool entries are locally + * managed by data pool variable access classes, which are called pool + * variables. To ensure a common state of a set of variables needed in a + * function, these local pool variables again are managed by other classes, + * like the DataSet classes. This interface provides unified access to + * local pool variables for such manager classes. + * @author Bastian Baetz + * @ingroup data_pool */ class PoolVariableIF : public SerializeIF { - friend class DataSet; -protected: - /** - * \brief The commit call shall write back a newly calculated local value to the data pool. - */ - virtual ReturnValue_t commit() = 0; - /** - * \brief The read call shall read the value of this parameter from the data pool and store - * the content locally. - */ - virtual ReturnValue_t read() = 0; + friend class PoolDataSetBase; + friend class GlobDataSet; + friend class LocalPoolDataSetBase; public: - static const uint8_t VALID = 1; - static const uint8_t INVALID = 0; - static const uint32_t NO_PARAMETER = 0; + 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 bool VALID = 1; + static constexpr bool INVALID = 0; + static constexpr uint32_t NO_PARAMETER = 0xffffffff; + enum ReadWriteMode_t { VAR_READ, VAR_WRITE, VAR_READ_WRITE }; /** - * \brief This is an empty virtual destructor, as it is proposed for C++ interfaces. + * @brief This is an empty virtual destructor, + * as it is proposed for C++ interfaces. */ - virtual ~PoolVariableIF() { - } + virtual ~PoolVariableIF() {} /** - * \brief This method returns if the variable is write-only, read-write or read-only. + * @brief This method returns if the variable is write-only, + * read-write or read-only. */ virtual ReadWriteMode_t getReadWriteMode() const = 0; /** - * \brief This operation shall return the data pool id of the variable. + * @brief This operation shall return the data pool id of the variable. */ virtual uint32_t getDataPoolId() const = 0; /** - * \brief With this call, the valid information of the variable is returned. + * @brief With this call, the valid information of the + * variable is returned. */ virtual bool isValid() const = 0; /** - * \brief With this call, the valid information of the variable is set. + * @brief With this call, the valid information of the variable is set. */ - virtual void setValid(uint8_t validity) = 0; + virtual void setValid(bool validity) = 0; + /** + * @brief The commit call shall write back a newly calculated local + * value to the data pool. + * @details + * It is assumed that these calls are implemented in a thread-safe manner! + */ + virtual ReturnValue_t commit(uint32_t lockTimeout) = 0; + /** + * @brief The read call shall read the value of this parameter from + * the data pool and store the content locally. + * @details + * It is assumbed that these calls are implemented in a thread-safe manner! + */ + virtual ReturnValue_t read(uint32_t lockTimeout) = 0; + +protected: + + /** + * @brief Same as commit with the difference that comitting will be + * performed without a lock + * @return + * This can be used if the lock protection is handled externally + * to avoid the overhead of locking and unlocking consecutively. + * Declared protected to avoid free public usage. + */ + virtual ReturnValue_t readWithoutLock() = 0; + /** + * @brief Same as commit with the difference that comitting will be + * performed without a lock + * @return + * This can be used if the lock protection is handled externally + * to avoid the overhead of locking and unlocking consecutively. + * Declared protected to avoid free public usage. + */ + virtual ReturnValue_t commitWithoutLock() = 0; }; -#endif /* POOLVARIABLEIF_H_ */ +using pool_rwm_t = PoolVariableIF::ReadWriteMode_t; + +#endif /* FSFW_DATAPOOL_POOLVARIABLEIF_H_ */ diff --git a/datapool/PoolVector.h b/datapool/PoolVector.h deleted file mode 100644 index d4ca0842..00000000 --- a/datapool/PoolVector.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * \file PoolVector.h - * - * \brief This file contains the PoolVector class, the header only class to handle data pool vectors. - * - * \date 10/23/2012 - * - * \author Bastian Baetz - */ - -#ifndef POOLVECTOR_H_ -#define POOLVECTOR_H_ - -#include "DataSetIF.h" -#include "PoolEntry.h" -#include "PoolVariableIF.h" -#include "../serialize/SerializeAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -/** - * \brief This is the access class for array-type data pool entries. - * - * \details To ensure safe usage of the data pool, operation is not done directly on the data pool - * entries, but on local copies. This class provides simple type- and length-safe access - * to vector-style data pool entries (i.e. entries with length > 1). - * The class can be instantiated as read-write and read only. - * It provides a commit-and-roll-back semantic, which means that no array entry in - * the data pool is changed until the commit call is executed. - * There are two template parameters: - * \tparam T This template parameter specifies the data type of an array entry. Currently, all - * plain data types are supported, but in principle any type is possible. - * \tparam vector_size This template parameter specifies the vector size of this entry. - * Using a template parameter for this is not perfect, but avoids dynamic memory allocation. - * \ingroup data_pool - */ -template -class PoolVector: public PoolVariableIF { -private: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - -protected: - /** - * \brief This is a call to read the array's values from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies all array values and the valid - * information to its local attributes. In case of a failure (wrong type, size or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read() { - PoolEntry* read_out = ::dataPool.getData(this->dataPoolId, - vector_size); - if (read_out != NULL) { - this->valid = read_out->valid; - memcpy(this->value, read_out->address, read_out->getByteSize()); - - return HasReturnvaluesIF::RETURN_OK; - - } else { - memset(this->value, 0, vector_size * sizeof(T)); - sif::error << "PoolVector: read of DP Variable 0x" << std::hex - << dataPoolId << std::dec << " failed." << std::endl; - this->valid = INVALID; - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * \brief The commit call copies the array values back to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit() { - PoolEntry* write_back = ::dataPool.getData(this->dataPoolId, - vector_size); - if ((write_back != NULL) && (this->readWriteMode != VAR_READ)) { - write_back->valid = valid; - memcpy(write_back->address, this->value, write_back->getByteSize()); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } -public: - /** - * \brief This is the local copy of the data pool entry. - * \detials The user can work on this attribute - * just like he would on a local array of this type. - */ - T value[vector_size]; - /** - * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is - * passed). - * \details It DOES NOT fetch the current value from the data pool, but sets the value - * attribute to default (0). The value is fetched within the read() operation. - * \param set_id This is the id in the global data pool this instance of the access class - * corresponds to. - * \param dataSet The data set in which the variable shall register itself. If NULL, - * the variable is not registered. - * \param setWritable If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. - */ - PoolVector(uint32_t set_id, DataSetIF* set, - ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) { - memset(this->value, 0, vector_size * sizeof(T)); - if (set != NULL) { - set->registerVariable(this); - } - } - /** - * Copy ctor to copy classes containing Pool Variables. - */ -// PoolVector(const PoolVector& rhs) { -// PoolVector temp(rhs.dataPoolId, rhs.) -// memcpy(value, rhs.value, sizeof(T)*vector_size); -// } - /** - * \brief The classes destructor is empty. - * \details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolVector() { - } - ; - /** - * \brief The operation returns the number of array entries in this variable. - */ - uint8_t getSize() { - return vector_size; - } - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const { - return dataPoolId; - } - /** - * This operation sets the data pool id of the variable. - * The method is necessary to set id's of data pool member variables with bad initialization. - */ - void setDataPoolId(uint32_t poolId) { - dataPoolId = poolId; - } - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const { - return readWriteMode; - } - ; - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const { - if (valid != INVALID) - return true; - else - return false; - } - - void setValid(uint8_t valid) { - this->valid = valid; - } - - uint8_t getValid() { - return valid; - } - - T &operator [](int i) { - return value[i]; - } - - const T &operator [](int i) const { - return value[i]; - } - - PoolVector &operator=( - PoolVector newPoolVector) { - - for (uint16_t i = 0; i < vector_size; i++) { - this->value[i] = newPoolVector.value[i]; - } - return *this; - } - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - uint16_t i; - ReturnValue_t result; - for (i = 0; i < vector_size; i++) { - result = SerializeAdapter::serialize(&(value[i]), buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; - } - - virtual size_t getSerializedSize() const { - return vector_size * SerializeAdapter::getSerializedSize(value); - } - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - uint16_t i; - ReturnValue_t result; - for (i = 0; i < vector_size; i++) { - result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; - } -}; - -#endif /* POOLVECTOR_H_ */ diff --git a/datapool/SharedDataSetIF.h b/datapool/SharedDataSetIF.h new file mode 100644 index 00000000..b8d98794 --- /dev/null +++ b/datapool/SharedDataSetIF.h @@ -0,0 +1,14 @@ +#ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ +#define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ +#include "PoolDataSetIF.h" + +class SharedDataSetIF: public PoolDataSetIF { +public: + virtual ~SharedDataSetIF() {}; + +private: + virtual ReturnValue_t lockDataset(dur_millis_t mutexTimeout) = 0; + virtual ReturnValue_t unlockDataset() = 0; +}; + +#endif /* FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ */ diff --git a/datapool/ControllerSet.cpp b/datapoolglob/ControllerSet.cpp similarity index 79% rename from datapool/ControllerSet.cpp rename to datapoolglob/ControllerSet.cpp index 6339034c..54fc6e8c 100644 --- a/datapool/ControllerSet.cpp +++ b/datapoolglob/ControllerSet.cpp @@ -1,4 +1,4 @@ -#include "ControllerSet.h" +#include ControllerSet::ControllerSet() { diff --git a/datapoolglob/ControllerSet.h b/datapoolglob/ControllerSet.h new file mode 100644 index 00000000..5da11397 --- /dev/null +++ b/datapoolglob/ControllerSet.h @@ -0,0 +1,15 @@ +#ifndef FSFW_DATAPOOLGLOB_CONTROLLERSET_H_ +#define FSFW_DATAPOOLGLOB_CONTROLLERSET_H_ + +#include "../datapoolglob/GlobalDataSet.h" + +class ControllerSet :public GlobDataSet { +public: + ControllerSet(); + virtual ~ControllerSet(); + + virtual void setToDefault() = 0; + void setInvalid(); +}; + +#endif /* FSFW_DATAPOOLGLOB_CONTROLLERSET_H_ */ diff --git a/datapool/DataPoolAdmin.cpp b/datapoolglob/DataPoolAdmin.cpp similarity index 94% rename from datapool/DataPoolAdmin.cpp rename to datapoolglob/DataPoolAdmin.cpp index f298d530..6ede0841 100644 --- a/datapool/DataPoolAdmin.cpp +++ b/datapoolglob/DataPoolAdmin.cpp @@ -1,7 +1,8 @@ -#include "DataPool.h" #include "DataPoolAdmin.h" -#include "DataSet.h" +#include "GlobalDataSet.h" +#include "GlobalDataPool.h" #include "PoolRawAccess.h" + #include "../ipc/CommandMessage.h" #include "../ipc/QueueFactory.h" #include "../parameters/ParameterMessage.h" @@ -40,9 +41,9 @@ ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId, uint8_t valid = data[4]; - uint32_t poolId = ::dataPool.PIDToDataPoolId(address); + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); - DataSet mySet; + GlobDataSet mySet; PoolRawAccess variable(poolId, 0, &mySet, PoolVariableIF::VAR_READ_WRITE); ReturnValue_t status = mySet.read(); if (status != RETURN_OK) { @@ -92,9 +93,9 @@ void DataPoolAdmin::handleCommand() { ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, const uint8_t* data, size_t size, uint8_t** dataPointer) { - uint32_t poolId = ::dataPool.PIDToDataPoolId(address); - uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address); - DataSet testSet; + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); + uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); + GlobDataSet testSet; PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ); ReturnValue_t status = testSet.read(); @@ -113,7 +114,7 @@ ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, const uint8_t* readPosition = data; for (; size > 0; size -= typeSize) { - DataSet rawSet; + GlobDataSet rawSet; PoolRawAccess variable(poolId, arrayIndex, &rawSet, PoolVariableIF::VAR_READ_WRITE); status = rawSet.read(); @@ -131,9 +132,9 @@ ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, size_t size, uint8_t** dataPointer, uint8_t* copyHere) { - uint32_t poolId = ::dataPool.PIDToDataPoolId(address); - uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address); - DataSet testSet; + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); + uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); + GlobDataSet testSet; PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ); ReturnValue_t status = testSet.read(); @@ -146,7 +147,7 @@ ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, size_t size, } uint8_t* ptrToCopy = copyHere; for (; size > 0; size -= typeSize) { - DataSet rawSet; + GlobDataSet rawSet; PoolRawAccess variable(poolId, arrayIndex, &rawSet, PoolVariableIF::VAR_READ); status = rawSet.read(); diff --git a/datapool/DataPoolAdmin.h b/datapoolglob/DataPoolAdmin.h similarity index 92% rename from datapool/DataPoolAdmin.h rename to datapoolglob/DataPoolAdmin.h index e2d1e9e1..d8871b65 100644 --- a/datapool/DataPoolAdmin.h +++ b/datapoolglob/DataPoolAdmin.h @@ -1,15 +1,17 @@ -#ifndef DATAPOOLADMIN_H_ -#define DATAPOOLADMIN_H_ +#ifndef FSFW_DATAPOOLGLOB_DATAPOOLADMIN_H_ +#define FSFW_DATAPOOLGLOB_DATAPOOLADMIN_H_ + +#include "DataPoolParameterWrapper.h" -#include "../memory/MemoryHelper.h" -#include "../action/HasActionsIF.h" -#include "../action/SimpleActionHelper.h" #include "../objectmanager/SystemObject.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../tasks/ExecutableObjectIF.h" -#include "../parameters/ReceivesParameterMessagesIF.h" -#include "DataPoolParameterWrapper.h" +#include "../action/HasActionsIF.h" #include "../ipc/MessageQueueIF.h" +#include "../parameters/ReceivesParameterMessagesIF.h" +#include "../action/SimpleActionHelper.h" +#include "../memory/MemoryHelper.h" + class DataPoolAdmin: public HasActionsIF, public ExecutableObjectIF, @@ -55,4 +57,4 @@ private: Command_t initialCommand); }; -#endif /* DATAPOOLADMIN_H_ */ +#endif /* FSFW_DATAPOOLGLOB_DATAPOOLADMIN_H_ */ diff --git a/datapool/DataPoolParameterWrapper.cpp b/datapoolglob/DataPoolParameterWrapper.cpp similarity index 95% rename from datapool/DataPoolParameterWrapper.cpp rename to datapoolglob/DataPoolParameterWrapper.cpp index 79367405..3a57d90d 100644 --- a/datapool/DataPoolParameterWrapper.cpp +++ b/datapoolglob/DataPoolParameterWrapper.cpp @@ -1,10 +1,8 @@ -#include "DataPoolParameterWrapper.h" - -//for returncodes +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/DataPoolParameterWrapper.h" +#include "../datapoolglob/PoolRawAccess.h" #include "../parameters/HasParametersIF.h" -#include "DataSet.h" -#include "PoolRawAccess.h" DataPoolParameterWrapper::DataPoolParameterWrapper() : type(Type::UNKNOWN_TYPE), rows(0), columns(0), poolId( @@ -20,7 +18,7 @@ ReturnValue_t DataPoolParameterWrapper::set(uint8_t domainId, uint16_t parameterId) { poolId = (domainId << 16) + parameterId; - DataSet mySet; + GlobDataSet mySet; PoolRawAccess raw(poolId, 0, &mySet, PoolVariableIF::VAR_READ); ReturnValue_t status = mySet.read(); if (status != HasReturnvaluesIF::RETURN_OK) { @@ -57,7 +55,7 @@ ReturnValue_t DataPoolParameterWrapper::serialize(uint8_t** buffer, } for (uint8_t index = 0; index < rows; index++){ - DataSet mySet; + GlobDataSet mySet; PoolRawAccess raw(poolId, index, &mySet,PoolVariableIF::VAR_READ); mySet.read(); result = raw.serialize(buffer,size,maxSize,streamEndianness); @@ -94,7 +92,7 @@ ReturnValue_t DataPoolParameterWrapper::deSerializeData(uint8_t startingRow, for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) { - DataSet mySet; + GlobDataSet mySet; PoolRawAccess raw(poolId, startingRow + fromRow, &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); diff --git a/datapool/DataPoolParameterWrapper.h b/datapoolglob/DataPoolParameterWrapper.h similarity index 100% rename from datapool/DataPoolParameterWrapper.h rename to datapoolglob/DataPoolParameterWrapper.h diff --git a/datapoolglob/GlobalDataPool.cpp b/datapoolglob/GlobalDataPool.cpp new file mode 100644 index 00000000..afb27b77 --- /dev/null +++ b/datapoolglob/GlobalDataPool.cpp @@ -0,0 +1,133 @@ +#include "../datapoolglob/GlobalDataPool.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../ipc/MutexFactory.h" + +GlobalDataPool::GlobalDataPool( + void(*initFunction)(GlobPoolMap* pool_map)) { + mutex = MutexFactory::instance()->createMutex(); + if (initFunction != NULL ) { + initFunction( &this->globDataPool ); + } +} + +GlobalDataPool::~GlobalDataPool() { + MutexFactory::instance()->deleteMutex(mutex); + for(GlobPoolMapIter it = this->globDataPool.begin(); + it != this->globDataPool.end(); ++it ) + { + delete it->second; + } +} + +// The function checks PID, type and array length before returning a copy of +// the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr. +template PoolEntry* GlobalDataPool::getData( uint32_t data_pool_id, + uint8_t sizeOrPosition ) { + GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); + if ( it != this->globDataPool.end() ) { + PoolEntry* entry = dynamic_cast< PoolEntry* >( it->second ); + if (entry != nullptr ) { + if ( sizeOrPosition <= entry->length ) { + return entry; + } + } + } + return nullptr; +} + +PoolEntryIF* GlobalDataPool::getRawData( uint32_t data_pool_id ) { + GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); + if ( it != this->globDataPool.end() ) { + return it->second; + } else { + return nullptr; + } +} + +ReturnValue_t GlobalDataPool::unlockDataPool() { + ReturnValue_t status = mutex->unlockMutex(); + if(status != RETURN_OK) { + sif::error << "DataPool::DataPool: unlock of mutex failed with" + " error code: " << status << std::endl; + } + return status; +} + +ReturnValue_t GlobalDataPool::lockDataPool(uint32_t timeoutMs) { + ReturnValue_t status = mutex->lockMutex(MutexIF::TimeoutType::WAITING, + timeoutMs); + if(status != RETURN_OK) { + sif::error << "DataPool::DataPool: lock of mutex failed " + "with error code: " << status << std::endl; + } + return status; +} + +void GlobalDataPool::print() { + sif::debug << "DataPool contains: " << std::endl; + std::map::iterator dataPoolIt; + dataPoolIt = this->globDataPool.begin(); + while( dataPoolIt != this->globDataPool.end() ) { + sif::debug << std::hex << dataPoolIt->first << std::dec << " |"; + dataPoolIt->second->print(); + dataPoolIt++; + } +} + +uint32_t GlobalDataPool::PIDToDataPoolId(uint32_t parameter_id) { + return (parameter_id >> 8) & 0x00FFFFFF; +} + +uint8_t GlobalDataPool::PIDToArrayIndex(uint32_t parameter_id) { + return (parameter_id & 0x000000FF); +} + +uint32_t GlobalDataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) { + return (poolId << 8) + index; +} + + +//SHOULDDO: Do we need a mutex lock here... I don't think so, +//as we only check static const values of elements in a list that do not change. +//there is no guarantee in the standard, but it seems to me that the implementation is safe -UM +ReturnValue_t GlobalDataPool::getType(uint32_t parameter_id, Type* type) { + GlobPoolMapIter it = this->globDataPool.find( PIDToDataPoolId(parameter_id)); + if ( it != this->globDataPool.end() ) { + *type = it->second->getType(); + return RETURN_OK; + } else { + *type = Type::UNKNOWN_TYPE; + return RETURN_FAILED; + } +} + +bool GlobalDataPool::exists(uint32_t parameterId) { + uint32_t poolId = PIDToDataPoolId(parameterId); + uint32_t index = PIDToArrayIndex(parameterId); + GlobPoolMapIter it = this->globDataPool.find( poolId ); + if (it != globDataPool.end()) { + if (it->second->getSize() >= index) { + return true; + } + } + return false; +} + +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size); diff --git a/datapoolglob/GlobalDataPool.h b/datapoolglob/GlobalDataPool.h new file mode 100644 index 00000000..ce5b132c --- /dev/null +++ b/datapoolglob/GlobalDataPool.h @@ -0,0 +1,149 @@ +#ifndef GLOBALDATAPOOL_H_ +#define GLOBALDATAPOOL_H_ + +#include "../datapool/PoolEntry.h" +#include "../globalfunctions/Type.h" +#include "../ipc/MutexIF.h" +#include + +/** + * @defgroup data_pool Global data pool + * This is the group, where all classes associated with global + * data pool handling belong to. + * This includes classes to access Data Pool variables. + */ + +/** + * Typedefs for the global pool representations + */ +using GlobPoolMap = std::map; +using GlobPoolMapIter = GlobPoolMap::iterator; + +/** + * @brief This class represents the OBSW global data-pool. + * + * @details + * All variables are registered and space is allocated in an initialization + * function, which is passed do the constructor. Space for the variables is + * allocated on the heap (with a new call). + * + * The data is found by a data pool id, which uniquely represents a variable. + * Data pool variables should be used with a blackboard logic in mind, + * which means read data is valid (if flagged so), + * but not necessarily up-to-date. + * + * Variables are either single values or arrays. + * @author Bastian Baetz + * @ingroup data_pool + */ +class GlobalDataPool : public HasReturnvaluesIF { +private: + /** + * @brief This is the actual data pool itself. + * @details It is represented by a map with the data pool id as index + * and a pointer to a single PoolEntry as value. + */ + GlobPoolMap globDataPool; + + /** + * @brief The mutex is created in the constructor and makes + * access mutual exclusive. + * @details Locking and unlocking the pool is only done by the DataSet class. + */ + MutexIF* mutex; +public: + /** + * @brief In the classes constructor, + * the passed initialization function is called. + * @details + * To enable filling the pool, a pointer to the map is passed, + * allowing direct access to the pool's content. + * On runtime, adding or removing variables is forbidden. + */ + GlobalDataPool( void ( *initFunction )( GlobPoolMap* pool_map ) ); + + /** + * @brief The destructor iterates through the data_pool map and + * calls all entries destructors to clean up the heap. + */ + ~GlobalDataPool(); + + /** + * @brief This is the default call to access the pool. + * @details + * A pointer to the PoolEntry object is returned. + * The call checks data pool id, type and array size. + * Returns NULL in case of failure. + * @param data_pool_id The data pool id to search. + * @param sizeOrPosition The array size (not byte size!) of the pool entry, + * or the position the user wants to read. + * If smaller than the entry size, everything's ok. + */ + template PoolEntry* getData( uint32_t data_pool_id, + uint8_t sizeOrPosition ); + + /** + * @brief An alternative call to get a data pool entry in case the type is not implicitly known + * (i.e. in Housekeeping Telemetry). + * @details It returns a basic interface and does NOT perform + * a size check. The caller has to assure he does not copy too much data. + * Returns NULL in case the entry is not found. + * @param data_pool_id The data pool id to search. + */ + PoolEntryIF* getRawData( uint32_t data_pool_id ); + /** + * @brief This is a small helper function to facilitate locking the global data pool. + * @details It fetches the pool's mutex id and tries to acquire the mutex. + */ + ReturnValue_t lockDataPool(uint32_t timeoutMs = MutexIF::BLOCKING); + /** + * @brief This is a small helper function to facilitate unlocking the global data pool. + * @details It fetches the pool's mutex id and tries to free the mutex. + */ + ReturnValue_t unlockDataPool(); + /** + * @brief The print call is a simple debug method. + * @details It prints the current content of the data pool. + * It iterates through the data_pool map and calls each entry's print() method. + */ + void print(); + /** + * Extracts the data pool id from a SCOS 2000 PID. + * @param parameter_id The passed Parameter ID. + * @return The data pool id as used within the OBSW. + */ + static uint32_t PIDToDataPoolId( uint32_t parameter_id ); + /** + * Extracts an array index out of a SCOS 2000 PID. + * @param parameter_id The passed Parameter ID. + * @return The index of the corresponding data pool entry. + */ + static uint8_t PIDToArrayIndex( uint32_t parameter_id ); + /** + * Retransforms a data pool id and an array index to a SCOS 2000 PID. + */ + static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index ); + + /** + * Method to return the type of a pool variable. + * @param parameter_id A parameterID (not pool id) of a DP member. + * @param type Returns the type or TYPE::UNKNOWN_TYPE + * @return RETURN_OK if parameter exists, RETURN_FAILED else. + */ + ReturnValue_t getType( uint32_t parameter_id, Type* type ); + + /** + * Method to check if a PID exists. Does not lock, as there's no + * possibility to alter the list that is checked during run-time. + * @param parameterId The PID (not pool id!) of a parameter. + * @return true if exists, false else. + */ + bool exists(uint32_t parameterId); +}; + +//We assume someone globally instantiates a DataPool. +namespace glob { +extern GlobalDataPool dataPool; +} + +#endif /* DATAPOOL_H_ */ diff --git a/datapoolglob/GlobalDataSet.cpp b/datapoolglob/GlobalDataSet.cpp new file mode 100644 index 00000000..1e99f805 --- /dev/null +++ b/datapoolglob/GlobalDataSet.cpp @@ -0,0 +1,48 @@ +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +GlobDataSet::GlobDataSet(): PoolDataSetBase( + reinterpret_cast(®isteredVariables), + DATA_SET_MAX_SIZE) {} + +// Don't do anything with your variables, they are dead already! +// (Destructor is already called) +GlobDataSet::~GlobDataSet() {} + +ReturnValue_t GlobDataSet::commit(bool valid, uint32_t lockTimeout) { + setEntriesValid(valid); + setSetValid(valid); + return commit(lockTimeout); +} + +ReturnValue_t GlobDataSet::commit(uint32_t lockTimeout) { + return PoolDataSetBase::commit(lockTimeout); +} + +bool GlobDataSet::isValid() const { + return this->valid; +} + +ReturnValue_t GlobDataSet::unlockDataPool() { + return glob::dataPool.unlockDataPool(); +} + +ReturnValue_t GlobDataSet::lockDataPool(uint32_t timeoutMs) { + return glob::dataPool.lockDataPool(timeoutMs); +} + +void GlobDataSet::setEntriesValid(bool valid) { + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_READ) { + registeredVariables[count]->setValid(valid); + } + } +} + +void GlobDataSet::setSetValid(bool valid) { + this->valid = valid; +} + + diff --git a/datapoolglob/GlobalDataSet.h b/datapoolglob/GlobalDataSet.h new file mode 100644 index 00000000..2f0edbd5 --- /dev/null +++ b/datapoolglob/GlobalDataSet.h @@ -0,0 +1,98 @@ +#ifndef FRAMEWORK_DATAPOOLGLOB_DATASET_H_ +#define FRAMEWORK_DATAPOOLGLOB_DATASET_H_ + +#include "../datapool/PoolDataSetBase.h" + +/** + * @brief The DataSet class manages a set of locally checked out variables + * for the global data pool. + * @details + * This class uses the read-commit() semantic provided by the DataSetBase class. + * It extends the base class by using the global data pool, + * having a valid state and implementing lock und unlock calls for the global + * datapool. + * + * For more information on how this class works, see the DataSetBase + * documentation. + * @author Bastian Baetz + * @ingroup data_pool + */ +class GlobDataSet: public PoolDataSetBase { +public: + + /** + * @brief Creates an empty GlobDataSet. Use registerVariable or + * supply a pointer to this dataset to PoolVariable + * initializations to register pool variables. + */ + GlobDataSet(); + + /** + * @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". + */ + ~GlobDataSet(); + + /** + * Variant of method above which sets validity of all elements of the set. + * @param valid Validity information from PoolVariableIF. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + ReturnValue_t commit(bool valid, uint32_t lockTimeout = MutexIF::BLOCKING); + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + + /** + * Set all entries + * @param valid + */ + void setSetValid(bool valid); + + bool isValid() const override; + + /** + * Set the valid information of all variables contained in the set which + * are not read-only + * + * @param valid Validity information from PoolVariableIF. + */ + void setEntriesValid(bool valid); + + //!< This definition sets the maximum number of variables to + //! register in one DataSet. + static const uint8_t DATA_SET_MAX_SIZE = 63; + +private: + /** + * If the valid state of a dataset is always relevant to the whole + * data set we can use this flag. + */ + bool valid = false; + + /** + * @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; + + void handleAlreadyReadDatasetCommit(); + ReturnValue_t handleUnreadDatasetCommit(); + + PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; +}; + +#endif /* FRAMEWORK_DATAPOOLGLOB_DATASET_H_ */ diff --git a/datapoolglob/GlobalPoolVariable.h b/datapoolglob/GlobalPoolVariable.h new file mode 100644 index 00000000..a995bfaf --- /dev/null +++ b/datapoolglob/GlobalPoolVariable.h @@ -0,0 +1,213 @@ +#ifndef GLOBALPOOLVARIABLE_H_ +#define GLOBALPOOLVARIABLE_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapool/PoolVariableIF.h" +#include "../datapool/PoolEntry.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +template class PoolVarList; + + +/** + * @brief This is the access class for non-array data pool entries. + * + * @details + * To ensure safe usage of the data pool, operation is not done directly + * on the data pool entries, but on local copies. This class provides simple + * type-safe access to single data pool entries (i.e. entries with length = 1). + * The class can be instantiated as read-write and read only. + * It provides a commit-and-roll-back semantic, which means that the + * variable's value in the data pool is not changed until the + * commit call is executed. + * @tparam T The template parameter sets the type of the variable. + * Currently, all plain data types are supported, but in principle + * any type is possible. + * @ingroup data_pool + */ +template +class GlobPoolVar: public PoolVariableIF { + template friend class PoolVarList; + static_assert(not std::is_same::value, + "Do not use boolean for the PoolEntry type, use uint8_t instead!" + "There is no boolean type in CCSDS."); +public: + /** + * @brief In the constructor, the variable can register itself in a + * DataSet (if nullptr is not passed). + * @details + * It DOES NOT fetch the current value from the data pool, but + * sets the value attribute to default (0). + * The value is fetched within the read() operation. + * @param set_id This is the id in the global data pool + * this instance of the access class corresponds to. + * @param dataSet The data set in which the variable shall register + * itself. If NULL, the variable is not registered. + * @param setWritable If this flag is set to true, changes in the value + * attribute can be written back to the data pool, otherwise not. + */ + GlobPoolVar(uint32_t set_id, DataSetIF* dataSet, + ReadWriteMode_t setReadWriteMode); + + /** + * @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 Copy ctor to copy classes containing Pool Variables. + * (Robin): This only copies member variables, which is done + * by the default copy ctor. maybe we can ommit this ctor? + */ + GlobPoolVar(const GlobPoolVar& rhs); + + /** + * @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. + */ + ~GlobPoolVar() {} + + /** + * @brief This is a call to read the value from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The 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) override; + /** + * @brief The commit call writes back the variable's value to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The operation does NOT provide any mutual exclusive protection by itself. + * The commit 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) override; + +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 To access the correct data pool entry on read and commit calls, + * the data pool is stored. + */ + uint32_t dataPoolId; + + /** + * @brief The valid information as it was stored in the data pool is + * copied to this attribute. + */ + uint8_t valid; + + /** + * @brief The information whether the class is read-write or read-only + * is stored here. + */ + pool_rwm_t readWriteMode; + + /** + * Empty ctor for List initialization + */ + GlobPoolVar(); +public: + /** + * \brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const override; + + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const override; + /** + * This operation sets the data pool id of the variable. + * The method is necessary to set id's of data pool member variables with bad initialization. + */ + void setDataPoolId(uint32_t poolId); + + /** + * \brief With this call, the valid information of the variable is returned. + */ + bool isValid() const override; + + uint8_t getValid(); + + void setValid(bool valid) override; + + operator T() { + return value; + } + + operator T() const { + return value; + } + + GlobPoolVar &operator=(T newValue) { + value = newValue; + return *this; + } + + GlobPoolVar &operator=(GlobPoolVar newPoolVariable) { + value = newPoolVariable.value; + return *this; + } + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, + SerializeIF::Endianness streamEndianness) const override { + return SerializeAdapter::serialize(&value, buffer, size, max_size, + streamEndianness); + } + + virtual size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&value); + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&value, buffer, size, + streamEndianness); + } +}; + +#include "../datapoolglob/GlobalPoolVariable.tpp" + +typedef GlobPoolVar gp_bool_t; +typedef GlobPoolVar gp_uint8_t; +typedef GlobPoolVar gp_uint16_t; +typedef GlobPoolVar gp_uint32_t; +typedef GlobPoolVar gp_int8_t; +typedef GlobPoolVar gp_int16_t; +typedef GlobPoolVar gp_int32_t; +typedef GlobPoolVar gp_float_t; +typedef GlobPoolVar gp_double_t; + +#endif /* POOLVARIABLE_H_ */ diff --git a/datapoolglob/GlobalPoolVariable.tpp b/datapoolglob/GlobalPoolVariable.tpp new file mode 100644 index 00000000..d61d605d --- /dev/null +++ b/datapoolglob/GlobalPoolVariable.tpp @@ -0,0 +1,117 @@ +#ifndef GLOBALPOOLVARIABLE_TPP_ +#define GLOBALPOOLVARIABLE_TPP_ + +template +inline GlobPoolVar::GlobPoolVar(uint32_t set_id, + DataSetIF* dataSet, ReadWriteMode_t setReadWriteMode): + dataPoolId(set_id), valid(PoolVariableIF::INVALID), + readWriteMode(setReadWriteMode) +{ + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +template +inline ReturnValue_t GlobPoolVar::read(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +template +inline ReturnValue_t GlobPoolVar::commit(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = commitWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +template +inline ReturnValue_t GlobPoolVar::readWithoutLock() { + PoolEntry* read_out = glob::dataPool.getData(dataPoolId, 1); + if (read_out != NULL) { + valid = read_out->valid; + value = *(read_out->address); + return HasReturnvaluesIF::RETURN_OK; + } else { + value = 0; + valid = false; + sif::error << "PoolVariable: read of DP Variable 0x" << std::hex + << dataPoolId << std::dec << " failed." << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline ReturnValue_t GlobPoolVar::commitWithoutLock() { + PoolEntry* write_back = glob::dataPool.getData(dataPoolId, 1); + if ((write_back != NULL) && (readWriteMode != VAR_READ)) { + write_back->valid = valid; + *(write_back->address) = value; + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline GlobPoolVar::GlobPoolVar(): + dataPoolId(PoolVariableIF::NO_PARAMETER), + valid(PoolVariableIF::INVALID), + readWriteMode(VAR_READ), value(0) {} + +template +inline GlobPoolVar::GlobPoolVar(const GlobPoolVar& rhs) : + dataPoolId(rhs.dataPoolId), valid(rhs.valid), readWriteMode( + rhs.readWriteMode), value(rhs.value) {} + +template +inline pool_rwm_t GlobPoolVar::getReadWriteMode() const { + return readWriteMode; +} + +template +inline uint32_t GlobPoolVar::getDataPoolId() const { + return dataPoolId; +} + +template +inline void GlobPoolVar::setDataPoolId(uint32_t poolId) { + dataPoolId = poolId; +} + +template +inline bool GlobPoolVar::isValid() const { + if (valid) + return true; + else + return false; +} + +template +inline uint8_t GlobPoolVar::getValid() { + return valid; +} + +template +inline void GlobPoolVar::setValid(bool valid) { + this->valid = valid; +} + +#endif diff --git a/datapoolglob/GlobalPoolVector.h b/datapoolglob/GlobalPoolVector.h new file mode 100644 index 00000000..0f5daacd --- /dev/null +++ b/datapoolglob/GlobalPoolVector.h @@ -0,0 +1,185 @@ +#ifndef FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_H_ +#define FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntry.h" +#include "../datapool/PoolVariableIF.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +/** + * @brief This is the access class for array-type data pool entries. + * + * @details + * To ensure safe usage of the data pool, operation is not done directly on the + * data pool entries, but on local copies. This class provides simple type- + * and length-safe access to vector-style data pool entries (i.e. entries with + * length > 1). The class can be instantiated as read-write and read only. + * + * It provides a commit-and-roll-back semantic, which means that no array + * entry in the data pool is changed until the commit call is executed. + * There are two template parameters: + * @tparam T + * This template parameter specifies the data type of an array entry. Currently, + * all plain data types are supported, but in principle any type is possible. + * @tparam vector_size + * This template parameter specifies the vector size of this entry. Using a + * template parameter for this is not perfect, but avoids + * dynamic memory allocation. + * @ingroup data_pool + */ +template +class GlobPoolVector: public PoolVariableIF { +public: + /** + * @brief In the constructor, the variable can register itself in a + * DataSet (if no nullptr is passed). + * @details + * It DOES NOT fetch the current value from the data pool, but sets the + * value attribute to default (0). The value is fetched within the + * read() operation. + * @param set_id + * This is the id in the global data pool this instance of the access + * class corresponds to. + * @param dataSet + * The data set in which the variable shall register itself. If nullptr, + * the variable is not registered. + * @param setWritable + * If this flag is set to true, changes in the value attribute can be + * written back to the data pool, otherwise not. + */ + GlobPoolVector(uint32_t set_id, DataSetIF* set, + ReadWriteMode_t setReadWriteMode); + + /** + * @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. + */ + ~GlobPoolVector() {}; + /** + * @brief The operation returns the number of array entries + * in this variable. + */ + uint8_t getSize() { + return vectorSize; + } + /** + * @brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const { + return dataPoolId; + } + /** + * @brief This operation sets the data pool id of the variable. + * @details + * The method is necessary to set id's of data pool member variables + * with bad initialization. + */ + void setDataPoolId(uint32_t poolId) { + dataPoolId = poolId; + } + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const { + return readWriteMode; + } + + + /** + * @brief With this call, the valid information of the variable is returned. + */ + bool isValid() const { + if (valid != INVALID) + return true; + else + return false; + } + void setValid(bool valid) {this->valid = valid;} + uint8_t getValid() {return valid;} + + T &operator [](int i) {return value[i];} + const T &operator [](int i) const {return value[i];} + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t max_size, Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + 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 global data pool and copies all array values + * and the valid information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected by a lock of the global data pool. + * 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 valid flag is automatically set to "valid". + * The commit call is protected by a lock of the global data pool. + * 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; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + +private: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool id is stored. + */ + uint32_t dataPoolId; + /** + * @brief The valid information as it was stored in the data pool + * is copied to this attribute. + */ + uint8_t valid; + /** + * @brief The information whether the class is read-write or + * read-only is stored here. + */ + ReadWriteMode_t readWriteMode; +}; + +#include "../datapoolglob/GlobalPoolVector.tpp" + +template +using gp_vec_t = GlobPoolVector; + +#endif /* FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_H_ */ diff --git a/datapoolglob/GlobalPoolVector.tpp b/datapoolglob/GlobalPoolVector.tpp new file mode 100644 index 00000000..013a682a --- /dev/null +++ b/datapoolglob/GlobalPoolVector.tpp @@ -0,0 +1,117 @@ +#ifndef FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_TPP_ +#define FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_TPP_ + + +template +inline GlobPoolVector::GlobPoolVector(uint32_t set_id, + DataSetIF* set, ReadWriteMode_t setReadWriteMode) : + dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) { + memset(this->value, 0, vectorSize * sizeof(T)); + if (set != nullptr) { + set->registerVariable(this); + } +} + + +template +inline ReturnValue_t GlobPoolVector::read(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +template +inline ReturnValue_t GlobPoolVector::commit( + uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = commitWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +template +inline ReturnValue_t GlobPoolVector::readWithoutLock() { + PoolEntry* read_out = glob::dataPool.getData(this->dataPoolId, + vectorSize); + if (read_out != nullptr) { + this->valid = read_out->valid; + memcpy(this->value, read_out->address, read_out->getByteSize()); + + return HasReturnvaluesIF::RETURN_OK; + + } else { + memset(this->value, 0, vectorSize * sizeof(T)); + sif::error << "PoolVector: Read of DP Variable 0x" << std::hex + << std::setw(8) << std::setfill('0') << dataPoolId << + std::dec << " failed." << std::endl; + this->valid = INVALID; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline ReturnValue_t GlobPoolVector::commitWithoutLock() { + PoolEntry* writeBack = glob::dataPool.getData(this->dataPoolId, + vectorSize); + if ((writeBack != nullptr) && (this->readWriteMode != VAR_READ)) { + writeBack->valid = valid; + memcpy(writeBack->address, this->value, writeBack->getByteSize()); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline ReturnValue_t GlobPoolVector::serialize(uint8_t** buffer, + size_t* size, size_t max_size, + SerializeIF::Endianness streamEndianness) const { + uint16_t i; + ReturnValue_t result; + for (i = 0; i < vectorSize; i++) { + result = SerializeAdapter::serialize(&(value[i]), buffer, size, + max_size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +template +inline size_t GlobPoolVector::getSerializedSize() const { + return vectorSize * SerializeAdapter::getSerializedSize(value); +} + +template +inline ReturnValue_t GlobPoolVector::deSerialize( + const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + uint16_t i; + ReturnValue_t result; + for (i = 0; i < vectorSize; i++) { + result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +#endif diff --git a/datapool/PIDReader.h b/datapoolglob/PIDReader.h similarity index 77% rename from datapool/PIDReader.h rename to datapoolglob/PIDReader.h index 3b38b51d..9431e1d4 100644 --- a/datapool/PIDReader.h +++ b/datapoolglob/PIDReader.h @@ -1,9 +1,9 @@ #ifndef PIDREADER_H_ #define PIDREADER_H_ -#include "DataPool.h" -#include "DataSetIF.h" -#include "PoolEntry.h" -#include "PoolVariableIF.h" +#include "../datapool/DataSetIF.h" +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapool/PoolEntry.h" +#include "../datapool/PoolVariableIF.h" #include "../serialize/SerializeAdapter.h" #include "../serviceinterface/ServiceInterfaceStream.h" @@ -15,10 +15,10 @@ class PIDReader: public PoolVariableIF { protected: uint32_t parameterId; uint8_t valid; - ReturnValue_t read() { - uint8_t arrayIndex = DataPool::PIDToArrayIndex(parameterId); - PoolEntry *read_out = ::dataPool.getData( - DataPool::PIDToDataPoolId(parameterId), arrayIndex); + ReturnValue_t readWithoutLock() { + uint8_t arrayIndex = GlobalDataPool::PIDToArrayIndex(parameterId); + PoolEntry *read_out = glob::dataPool.getData( + GlobalDataPool::PIDToDataPoolId(parameterId), arrayIndex); if (read_out != NULL) { valid = read_out->valid; value = read_out->address[arrayIndex]; @@ -36,9 +36,13 @@ protected: * Reason is the possibility to access a single DP vector element, but if we commit, * we set validity of the whole vector. */ - ReturnValue_t commit() { + ReturnValue_t commit(uint32_t lockTimeout) override { return HasReturnvaluesIF::RETURN_FAILED; } + ReturnValue_t commitWithoutLock() override { + return HasReturnvaluesIF::RETURN_FAILED; + } + /** * Empty ctor for List initialization */ @@ -72,6 +76,19 @@ public: } } + ReturnValue_t read(uint32_t lockTimeout) override { + ReturnValue_t result = glob::dataPool.lockDataPool(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "PIDReader::read: Could not unlock data pool!" + << std::endl; + } + return result; + } /** * Copy ctor to copy classes containing Pool Variables. */ @@ -89,7 +106,7 @@ public: * \brief This operation returns the data pool id of the variable. */ uint32_t getDataPoolId() const { - return DataPool::PIDToDataPoolId(parameterId); + return GlobalDataPool::PIDToDataPoolId(parameterId); } uint32_t getParameterId() const { return parameterId; @@ -114,7 +131,7 @@ public: return valid; } - void setValid(uint8_t valid) { + void setValid(bool valid) { this->valid = valid; } diff --git a/datapool/PIDReaderList.h b/datapoolglob/PIDReaderList.h similarity index 68% rename from datapool/PIDReaderList.h rename to datapoolglob/PIDReaderList.h index 1f6aa99c..ae99f3aa 100644 --- a/datapool/PIDReaderList.h +++ b/datapoolglob/PIDReaderList.h @@ -1,8 +1,8 @@ -#ifndef FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ -#define FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ +#ifndef FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ +#define FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ -#include "PIDReader.h" -#include "PoolVariableIF.h" +#include "../datapool/PoolVariableIF.h" +#include "../datapoolglob/PIDReader.h" template class PIDReaderList { private: @@ -24,4 +24,4 @@ public: -#endif /* FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ */ +#endif /* FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ */ diff --git a/datapoolglob/PoolRawAccess.cpp b/datapoolglob/PoolRawAccess.cpp new file mode 100644 index 00000000..53706c6d --- /dev/null +++ b/datapoolglob/PoolRawAccess.cpp @@ -0,0 +1,239 @@ +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapoolglob/PoolRawAccess.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serialize/EndianConverter.h" + +#include + +PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry, + DataSetIF* dataSet, ReadWriteMode_t setReadWriteMode) : + dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), + type(Type::UNKNOWN_TYPE), typeSize(0), arraySize(0), sizeTillEnd(0), + readWriteMode(setReadWriteMode) { + memset(value, 0, sizeof(value)); + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +PoolRawAccess::~PoolRawAccess() {} + +ReturnValue_t PoolRawAccess::read(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +ReturnValue_t PoolRawAccess::readWithoutLock() { + ReturnValue_t result = RETURN_FAILED; + PoolEntryIF* readOut = glob::dataPool.getRawData(dataPoolId); + if (readOut != nullptr) { + result = handleReadOut(readOut); + if(result == RETURN_OK) { + return result; + } + } else { + result = READ_ENTRY_NON_EXISTENT; + } + handleReadError(result); + return result; +} + +ReturnValue_t PoolRawAccess::handleReadOut(PoolEntryIF* readOut) { + ReturnValue_t result = RETURN_FAILED; + valid = readOut->getValid(); + if (readOut->getSize() > arrayEntry) { + arraySize = readOut->getSize(); + typeSize = readOut->getByteSize() / readOut->getSize(); + type = readOut->getType(); + if (typeSize <= sizeof(value)) { + uint16_t arrayPosition = arrayEntry * typeSize; + sizeTillEnd = readOut->getByteSize() - arrayPosition; + uint8_t* ptr = &((uint8_t*) readOut->getRawData())[arrayPosition]; + memcpy(value, ptr, typeSize); + return RETURN_OK; + } else { + result = READ_TYPE_TOO_LARGE; + } + } else { + //debug << "PoolRawAccess: Size: " << (int)read_out->getSize() << std::endl; + result = READ_INDEX_TOO_LARGE; + } + return result; +} + +void PoolRawAccess::handleReadError(ReturnValue_t result) { + sif::error << "PoolRawAccess: read of DP Variable 0x" << std::hex << dataPoolId + << std::dec << " failed, "; + if(result == READ_TYPE_TOO_LARGE) { + sif::error << "type too large." << std::endl; + } + else if(result == READ_INDEX_TOO_LARGE) { + sif::error << "index too large." << std::endl; + } + else if(result == READ_ENTRY_NON_EXISTENT) { + sif::error << "entry does not exist." << std::endl; + } + + valid = INVALID; + typeSize = 0; + sizeTillEnd = 0; + memset(value, 0, sizeof(value)); +} + +ReturnValue_t PoolRawAccess::commit(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = commitWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +ReturnValue_t PoolRawAccess::commitWithoutLock() { + PoolEntryIF* write_back = glob::dataPool.getRawData(dataPoolId); + if ((write_back != NULL) && (readWriteMode != VAR_READ)) { + write_back->setValid(valid); + uint8_t array_position = arrayEntry * typeSize; + uint8_t* ptr = &((uint8_t*) write_back->getRawData())[array_position]; + memcpy(ptr, value, typeSize); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t* PoolRawAccess::getEntry() { + return value; +} + +ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer, + size_t* writtenBytes, size_t max_size) { + uint8_t* data_ptr = getEntry(); + // debug << "PoolRawAccess::getEntry: Array position: " << + // index * size_of_type << " Size of T: " << (int)size_of_type << + // " ByteSize: " << byte_size << " Position: " << *size << std::endl; + if (typeSize == 0) + return DATA_POOL_ACCESS_FAILED; + if (typeSize > max_size) + return INCORRECT_SIZE; + EndianConverter::convertBigEndian(buffer, data_ptr, typeSize); + *writtenBytes = typeSize; + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + if (typeSize + *size <= maxSize) { + switch(streamEndianness) { + case(Endianness::BIG): + EndianConverter::convertBigEndian(*buffer, value, typeSize); + break; + case(Endianness::LITTLE): + EndianConverter::convertLittleEndian(*buffer, value, typeSize); + break; + case(Endianness::MACHINE): + default: + memcpy(*buffer, value, typeSize); + break; + } + *size += typeSize; + (*buffer) += typeSize; + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } +} + + +Type PoolRawAccess::getType() { + return type; +} + +size_t PoolRawAccess::getSizeOfType() { + return typeSize; +} + +size_t PoolRawAccess::getArraySize(){ + return arraySize; +} + +uint32_t PoolRawAccess::getDataPoolId() const { + return dataPoolId; +} + +PoolVariableIF::ReadWriteMode_t PoolRawAccess::getReadWriteMode() const { + return readWriteMode; +} + +ReturnValue_t PoolRawAccess::setEntryFromBigEndian(const uint8_t *buffer, + size_t setSize) { + if (typeSize == setSize) { + EndianConverter::convertBigEndian(value, buffer, typeSize); + return HasReturnvaluesIF::RETURN_OK; + } else { + sif::error << "PoolRawAccess::setEntryFromBigEndian: Illegal sizes: " + "Internal" << (uint32_t) typeSize << ", Requested: " << setSize + << std::endl; + return INCORRECT_SIZE; + } +} + +bool PoolRawAccess::isValid() const { + if (valid != INVALID) + return true; + else + return false; +} + +void PoolRawAccess::setValid(bool valid) { + this->valid = valid; +} + +size_t PoolRawAccess::getSizeTillEnd() const { + return sizeTillEnd; +} + + +size_t PoolRawAccess::getSerializedSize() const { + return typeSize; +} + +ReturnValue_t PoolRawAccess::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + + if (*size >= typeSize) { + switch(streamEndianness) { + case(Endianness::BIG): + EndianConverter::convertBigEndian(value, *buffer, typeSize); + break; + case(Endianness::LITTLE): + EndianConverter::convertLittleEndian(value, *buffer, typeSize); + break; + case(Endianness::MACHINE): + default: + memcpy(value, *buffer, typeSize); + break; + } + *size -= typeSize; + *buffer += typeSize; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SerializeIF::STREAM_TOO_SHORT; + } +} diff --git a/datapoolglob/PoolRawAccess.h b/datapoolglob/PoolRawAccess.h new file mode 100644 index 00000000..15643a41 --- /dev/null +++ b/datapoolglob/PoolRawAccess.h @@ -0,0 +1,220 @@ +#ifndef POOLRAWACCESS_H_ +#define POOLRAWACCESS_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntryIF.h" +#include "../datapool/PoolVariableIF.h" +#include "../globalfunctions/Type.h" + +/** + * @brief This class allows accessing Data Pool variables as raw bytes. + * @details + * This is necessary to have an access method for HK data, as the PID's alone + * do not provide type information. Please note that the the raw pool access + * read() and commit() calls are not thread-safe. + * + * Please supply a data set and use the data set read(), commit() calls for + * thread-safe data pool access. + * @ingroup data_pool + */ +class PoolRawAccess: public PoolVariableIF, HasReturnvaluesIF { +public: + /** + * This constructor is used to access a data pool entry with a + * given ID if the target type is not known. A DataSet object is supplied + * and the data pool entry with the given ID is registered to that data set. + * Please note that a pool raw access buffer only has a buffer + * with a size of double. As such, for vector entries which have + * @param data_pool_id Target data pool entry ID + * @param arrayEntry + * @param data_set Dataset to register data pool entry to + * @param setReadWriteMode + * @param registerVectors If set to true, the constructor checks if + * there are multiple vector entries to registers + * and registers all of them recursively into the data_set + * + */ + PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, + DataSetIF* data_set, ReadWriteMode_t setReadWriteMode = + PoolVariableIF::VAR_READ); + + /** + * @brief This operation returns a pointer to the entry fetched. + * @details Return pointer to the buffer containing the raw data + * Size and number of data can be retrieved by other means. + */ + uint8_t* getEntry(); + /** + * @brief This operation returns the fetched entry from the data pool and + * flips the bytes, if necessary. + * @details It makes use of the getEntry call of this function, but additionally flips the + * bytes to big endian, which is the default for external communication (as House- + * keeping telemetry). To achieve this, the data is copied directly to the passed + * buffer, if it fits in the given max_size. + * @param buffer A pointer to a buffer to write to + * @param writtenBytes The number of bytes written is returned with this value. + * @param max_size The maximum size that the function may write to buffer. + * @return - @c RETURN_OK if entry could be acquired + * - @c RETURN_FAILED else. + */ + ReturnValue_t getEntryEndianSafe(uint8_t *buffer, size_t *size, + size_t maxSize); + + /** + * @brief Serialize raw pool entry into provided buffer directly + * @param buffer Provided buffer. Raw pool data will be copied here + * @param size [out] Increment provided size value by serialized size + * @param max_size Maximum allowed serialization size + * @param bigEndian Specify endianess + * @return - @c RETURN_OK if serialization was successfull + * - @c SerializeIF::BUFFER_TOO_SHORT if range check failed + */ + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + /** + * With this method, the content can be set from a big endian buffer safely. + * @param buffer Pointer to the data to set + * @param size Size of the data to write. Must fit this->size. + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t setEntryFromBigEndian(const uint8_t* buffer, + size_t setSize); + /** + * @brief This operation returns the type of the entry currently stored. + */ + Type getType(); + /** + * @brief This operation returns the size of the entry currently stored. + */ + size_t getSizeOfType(); + /** + * + * @return the size of the datapool array + */ + size_t getArraySize(); + /** + * @brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const; + + static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; + static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t READ_TYPE_TOO_LARGE = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t READ_INDEX_TOO_LARGE = MAKE_RETURN_CODE(0x04); + static const ReturnValue_t READ_ENTRY_NON_EXISTENT = MAKE_RETURN_CODE(0x05); + static const uint8_t RAW_MAX_SIZE = sizeof(double); + uint8_t value[RAW_MAX_SIZE]; + + + /** + * @brief The classes destructor is empty. If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~PoolRawAccess(); + + /** + * This method returns if the variable is read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const; + /** + * @brief With this call, the valid information of the variable is returned. + */ + bool isValid() const; + + void setValid(bool valid); + /** + * Getter for the remaining size. + */ + size_t getSizeTillEnd() const; + + /** + * @brief This is a call to read the value from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The call is protected by a lock of the global data pool. + * @return -@c RETURN_OK Read successfull + * -@c READ_TYPE_TOO_LARGE + * -@c READ_INDEX_TOO_LARGE + * -@c READ_ENTRY_NON_EXISTENT + */ + ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief The commit call writes back the variable's value to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The call is protected by a lock of the global data pool. + * + */ + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + +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; + + ReturnValue_t handleReadOut(PoolEntryIF* read_out); + void handleReadError(ReturnValue_t result); +private: + /** + * @brief To access the correct data pool entry on read and commit calls, the data pool id + * is stored. + */ + uint32_t dataPoolId; + /** + * @brief The array entry that is fetched from the data pool. + */ + uint8_t arrayEntry; + /** + * @brief The valid information as it was stored in the data pool is copied to this attribute. + */ + uint8_t valid; + /** + * @brief This value contains the type of the data pool entry. + */ + Type type; + /** + * @brief This value contains the size of the data pool entry type in bytes. + */ + size_t typeSize; + /** + * The size of the DP array (single values return 1) + */ + size_t arraySize; + /** + * The size (in bytes) from the selected entry till the end of this DataPool variable. + */ + size_t sizeTillEnd; + /** + * @brief The information whether the class is read-write or read-only is stored here. + */ + ReadWriteMode_t readWriteMode; +}; + +#endif /* POOLRAWACCESS_H_ */ diff --git a/datapoollocal/HasLocalDataPoolIF.h b/datapoollocal/HasLocalDataPoolIF.h new file mode 100644 index 00000000..7f1f202e --- /dev/null +++ b/datapoollocal/HasLocalDataPoolIF.h @@ -0,0 +1,136 @@ +#ifndef FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ +#define FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ + +#include "locPoolDefinitions.h" + +#include "../datapool/PoolEntryIF.h" +#include "../ipc/MessageQueueSenderIF.h" +#include "../housekeeping/HousekeepingMessage.h" + +#include + +class LocalDataPoolManager; +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. + * @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. + * + * 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 { +public: + virtual~ HasLocalDataPoolIF() {}; + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; + + static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID; + + virtual object_id_t getObjectId() const = 0; + + /** Command queue for housekeeping messages. */ + virtual MessageQueueId_t getCommandQueue() const = 0; + + /** + * Is used by pool owner to initialize the pool map once + * The manager instance shall also be passed to this function. + * It can be used to subscribe for periodic packets for for updates. + */ + virtual ReturnValue_t initializeLocalDataPool( + LocalDataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) = 0; + + /** Can be used to get a handle to the local data pool manager. */ + virtual LocalDataPoolManager* getHkManagerHandle() = 0; + + /** + * Returns the minimum sampling frequency in milliseconds, which will + * usually be the period the pool owner performs its periodic operation. + * @return + */ + virtual uint32_t getPeriodicOperationFrequency() const = 0; + + /** + * This function is used by the pool manager to get a valid dataset + * from a SID + * @param sid Corresponding structure ID + * @return + */ + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) = 0; + + /** + * Similar to the function above, but used to get a local pool variable + * handle. This is only needed for update notifications, so it is not + * defined as abstract. + * @param localPoolId + * @return + */ + virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) { + sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden" + << ". Returning nullptr!" << std::endl; + return nullptr; + } + + /** + * @brief This function will be called by the manager if an update + * notification is received. + * @details + * 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 + * the IPC store with this store ID. + */ + virtual void handleChangedDataset(sid_t sid, + store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { + return; + } + + /** + * @brief This function will be called by the manager if an update + * notification is received. + * @details + * Can be overriden by the child class to handle changed pool IDs. + * @param sid + * @param storeId If a snapshot was requested, data will be located inside + * the IPC store with this store ID. + */ + virtual void handleChangedPoolVariable(lp_id_t poolId, + store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { + 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; + }; +}; + +#endif /* FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ */ diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp new file mode 100644 index 00000000..f649a362 --- /dev/null +++ b/datapoollocal/LocalDataPoolManager.cpp @@ -0,0 +1,782 @@ +#include "LocalDataPoolManager.h" +#include "LocalPoolObjectBase.h" +#include "LocalPoolDataSetBase.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" +#include "../ipc/QueueFactory.h" + +#include +#include + +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; + } + + 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; + + ipcStore = objectManager->get(objects::IPC_STORE); + if(ipcStore == nullptr) { + sif::error << "LocalDataPoolManager::initialize: " + << std::hex << "0x" << owner->getObjectId() << ": Could not " + << "set IPC store." <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; + } + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation( + uint8_t nonDiagInvlFactor) { + setNonDiagnosticIntervalFactor(nonDiagInvlFactor); + return initializeHousekeepingPoolEntriesOnce(); +} + +ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { + if(not mapInitialized) { + ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, + *this); + if(result == HasReturnvaluesIF::RETURN_OK) { + mapInitialized = true; + } + return result; + } + sif::warning << "HousekeepingManager: The map should only be initialized " + << "once!" << std::endl; + 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 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 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; + } + + } + 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; +} + +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; + } + + 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)); + + 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; + } + + 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)); + + 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; + + } + 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;; +} + +void LocalDataPoolManager::handleChangeResetLogic( + DataType type, DataId dataId, MarkChangedIF* toReset) { + if(hkUpdateResetList == nullptr) { + // config error! + return; + } + + 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; + } +} + +void LocalDataPoolManager::resetHkUpdateResetHelper() { + if(hkUpdateResetList == nullptr) { + return; + } + + for(auto& changeInfo: *hkUpdateResetList) { + changeInfo.currentUpdateCounter = changeInfo.updateCounter; + } +} + +ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid, + bool enableReporting, float collectionInterval, bool isDiagnostics, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + objectManager->get(packetDestination); + if(hkReceiverObject == nullptr) { + sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" + << " Invalid receiver!"<< std::endl; + return HasReturnvaluesIF::RETURN_OK; + } + + 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); + } + + 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; + } + + 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); + } + + hkReceiversMap.push_back(hkReceiver); + + 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; + } + + hkReceiversMap.push_back(hkReceiver); + + 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; + } + + hkReceiversMap.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +void LocalDataPoolManager::handleHkUpdateResetListInsertion(DataType dataType, + DataId dataId) { + if(hkUpdateResetList == nullptr) { + hkUpdateResetList = new std::vector(); + } + + for(auto& updateResetStruct: *hkUpdateResetList) { + if(dataType == DataType::DATA_SET) { + if(updateResetStruct.dataId.sid == dataId.sid) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + else { + if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + + } + HkUpdateResetHelper hkUpdateResetHelper; + hkUpdateResetHelper.currentUpdateCounter = 1; + hkUpdateResetHelper.updateCounter = 1; + hkUpdateResetHelper.dataType = dataType; + if(dataType == DataType::DATA_SET) { + hkUpdateResetHelper.dataId.sid = dataId.sid; + } + else { + hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId; + } + hkUpdateResetList->push_back(hkUpdateResetHelper); +} + +ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( + CommandMessage* message) { + Command_t command = message->getCommand(); + sid_t sid = HousekeepingMessage::getSid(message); + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(command) { + // Houskeeping interface handling. + case(HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, true, true); + break; + } + + case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, false, true); + break; + } + + case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, true, false); + break; + } + + case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, false, false); + break; + } + + case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): + 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::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); + } + + // 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; + } + + 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; +} + +MutexIF* LocalDataPoolManager::getMutexHandle() { + return mutex; +} + +HasLocalDataPoolIF* LocalDataPoolManager::getOwner() { + return owner; +} + +ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, + LocalPoolDataSetBase* dataSet, bool forDownlink, + MessageQueueId_t destination) { + if(dataSet == nullptr) { + // Configuration error. + sif::warning << "HousekeepingManager::generateHousekeepingPacket:" + << " Set ID not found or dataset not assigned!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + 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); + } + + 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; + } + + return hkQueue->sendMessage(destination, &hkMessage); +} + +ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( + HousekeepingPacketDownlink& hkPacket, + store_address_t& storeId, bool forDownlink, + size_t* serializedSize) { + uint8_t* dataPtr = nullptr; + const size_t maxSize = hkPacket.getSerializedSize(); + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + maxSize, &dataPtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + if(forDownlink) { + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::BIG); + } + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::MACHINE); +} + +void LocalDataPoolManager::setNonDiagnosticIntervalFactor( + uint8_t nonDiagInvlFactor) { + this->nonDiagnosticIntervalFactor = nonDiagInvlFactor; +} + +void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { + sid_t sid = receiver.dataId.sid; + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(not dataSet->getReportingEnabled()) { + return; + } + + if(dataSet->periodicHelper == nullptr) { + // Configuration error. + return; + } + + if(not dataSet->periodicHelper->checkOpNecessary()) { + return; + } + + 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; + } +} + + +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; + } + + if((dataSet->getReportingEnabled() and enable) or + (not dataSet->getReportingEnabled() and not enable)) { + return REPORTING_STATUS_UNCHANGED; + } + + dataSet->setReportingEnabled(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; + } + + if(dataSet->periodicHelper == nullptr) { + // config error + return PERIODIC_HELPER_INVALID; + } + + dataSet->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 targetIsDiagnostics = dataSet->isDiagnostics(); + 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(); + + // 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; + } + + // 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; + } + + // Send structure reporting reply. + CommandMessage reply; + if(isDiagnostics) { + HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, + sid, storeId); + } + else { + HousekeepingMessage::setHkStuctureReportReply(&reply, + sid, storeId); + } + + hkQueue->reply(&reply); + return result; +} diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h new file mode 100644 index 00000000..95d48303 --- /dev/null +++ b/datapoollocal/LocalDataPoolManager.h @@ -0,0 +1,396 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ +#define FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ + +#include "HasLocalDataPoolIF.h" + +#include "../housekeeping/HousekeepingPacketDownlink.h" +#include "../housekeeping/HousekeepingMessage.h" +#include "../housekeeping/PeriodicHousekeepingHelper.h" +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntry.h" +#include "../objectmanager/SystemObjectIF.h" +#include "../ipc/MutexIF.h" +#include "../ipc/CommandMessage.h" +#include "../ipc/MessageQueueIF.h" +#include "../ipc/MutexHelper.h" + +#include + +namespace Factory { +void setStaticFrameworkObjectIds(); +} + +class LocalPoolDataSetBase; +class HousekeepingPacketUpdate; + +/** + * @brief This class is the managing instance for the local data pool. + * @details + * The actual data pool structure is a member of this class. Any class which + * has a local data pool shall have this manager class as a member and implement + * the HasLocalDataPoolIF. + * + * The manager offers some adaption points and functions which can be used + * by the owning class to simplify data handling significantly. + * + * Please ensure that both initialize and initializeAfterTaskCreation are + * called at some point by the owning class in the respective functions of the + * same name! + * + * Users of the data pool use the helper classes LocalDataSet, + * LocalPoolVariable and LocalPoolVector to access pool entries in + * a thread-safe and efficient way. + * + * The local data pools employ a blackboard logic: Only the most recent + * value is stored. The helper classes offer a read() and commit() interface + * through the PoolVariableIF which is used to read and update values. + * Each pool entry has a valid state too. + * @author R. Mueller + */ +class LocalDataPoolManager { + template friend class LocalPoolVar; + template friend class LocalPoolVector; + friend class LocalPoolDataSetBase; + friend void (Factory::setStaticFrameworkObjectIds)(); +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_NOT_SET = MAKE_RETURN_CODE(0x02); + + 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 + * a personal local data pool. The queueToUse can be supplied if it + * is already known. + * + * initialize() has to be called in any case before using the object! + * @param owner + * @param queueToUse + * @param appendValidityBuffer Specify whether a buffer containing the + * validity state is generated when serializing or deserializing packets. + */ + LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, + bool appendValidityBuffer = true); + virtual~ LocalDataPoolManager(); + + /** + * Assigns the queue to use. Make sure to call this in the #initialize + * function of the owner. + * @param queueToUse + * @param nonDiagInvlFactor See #setNonDiagnosticIntervalFactor doc + * @return + */ + ReturnValue_t initialize(MessageQueueIF* queueToUse); + + /** + * Initializes the map by calling the map initialization function and + * setting the periodic factor for non-diagnostic packets. + * Don't forget to call this in the #initializeAfterTaskCreation call of + * the owner, otherwise the map will be invalid! + * @param nonDiagInvlFactor + * @return + */ + ReturnValue_t initializeAfterTaskCreation( + uint8_t nonDiagInvlFactor = 5); + + /** + * @brief This should be called in the periodic handler of the owner. + * @details + * This in generally called in the #performOperation function of the owner. + * It performs all the periodic functionalities of the data pool manager, + * for example generating periodic HK packets. + * Marked virtual as an adaption point for custom data pool managers. + * @return + */ + virtual ReturnValue_t performHkOperation(); + + /** + * @brief Subscribe for the generation of periodic packets. + * @details + * This subscription mechanism will generally be used by the data creator + * to generate housekeeping packets which are downlinked directly. + * @return + */ + ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting, + float collectionInterval, bool isDiagnostics, + object_id_t packetDestination = defaultHkDestination); + + /** + * @brief Subscribe for the generation of packets if the dataset + * is marked as changed. + * @details + * This subscription mechanism will generally be used by the data creator. + * @param sid + * @param isDiagnostics + * @param packetDestination + * @return + */ + ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled, + bool isDiagnostics, + object_id_t packetDestination = defaultHkDestination); + + /** + * @brief Subscribe for a notification message which will be sent + * if a dataset has changed. + * @details + * This subscription mechanism will generally be used internally by + * other software components. + * @param setId Set ID of the set to receive update messages from. + * @param destinationObject + * @param targetQueueId + * @param generateSnapshot If this is set to true, a copy of the current + * data with a timestamp will be generated and sent via message. + * Otherwise, only an notification message is sent. + * @return + */ + ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId, + object_id_t destinationObject, + MessageQueueId_t targetQueueId, + bool generateSnapshot); + + /** + * @brief Subscribe for an notification message which will be sent if a + * pool variable has changed. + * @details + * This subscription mechanism will generally be used internally by + * other software components. + * @param localPoolId Pool ID of the pool variable + * @param destinationObject + * @param targetQueueId + * @param generateSnapshot If this is set to true, a copy of the current + * data with a timestamp will be generated and sent via message. + * Otherwise, only an notification message is sent. + * @return + */ + ReturnValue_t subscribeForVariableUpdateMessages(const lp_id_t localPoolId, + object_id_t destinationObject, + MessageQueueId_t targetQueueId, + bool generateSnapshot); + + /** + * Non-Diagnostics packets usually have a lower minimum sampling frequency + * than diagnostic packets. + * A factor can be specified to determine the minimum sampling frequency + * for non-diagnostic packets. The minimum sampling frequency of the + * diagnostics packets,which is usually jusst the period of the + * performOperation calls, is multiplied with that factor. + * @param factor + */ + void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor); + + /** + * @brief The manager is also able to handle housekeeping messages. + * @details + * This most commonly is used to handle messages for the housekeeping + * interface, but the manager is also able to handle update notifications + * and calls a special function which can be overriden by a child class + * to handle data set or pool variable updates. This is relevant + * for classes like controllers which have their own local datapool + * but pull their data from other local datapools. + * @param message + * @return + */ + virtual ReturnValue_t handleHousekeepingMessage(CommandMessage* message); + + /** + * Generate a housekeeping packet with a given SID. + * @param sid + * @return + */ + ReturnValue_t generateHousekeepingPacket(sid_t sid, + LocalPoolDataSetBase* dataSet, bool forDownlink, + MessageQueueId_t destination = MessageQueueIF::NO_QUEUE); + + HasLocalDataPoolIF* getOwner(); + + ReturnValue_t printPoolEntry(lp_id_t localPoolId); + + /** + * Different types of housekeeping reporting are possible. + * 1. PERIODIC: + * HK packets are generated in fixed intervals and sent to + * destination. Fromat will be raw. + * 2. UPDATE_NOTIFICATION: + * Notification will be sent out if HK data has changed. + * 3. UPDATE_SNAPSHOT: + * HK packets are only generated if explicitely requested. + * Propably not necessary, just use multiple local data sets or + * shared datasets. + */ + enum class ReportingType: uint8_t { + //! Periodic generation of HK packets. + PERIODIC, + //! Housekeeping packet will be generated if values have changed. + UPDATE_HK, + //! Update notification will be sent out as message. + UPDATE_NOTIFICATION, + //! Notification will be sent out as message and a snapshot of the + //! current data will be generated. + UPDATE_SNAPSHOT, + }; + + /** + * Different data types are possible in the HK receiver map. + * For example, updates can be requested for full datasets or + * for single pool variables. Periodic reporting is only possible for + * data sets. + */ + enum class DataType: uint8_t { + LOCAL_POOL_VARIABLE, + DATA_SET + }; + + /* Copying forbidden */ + LocalDataPoolManager(const LocalDataPoolManager &) = delete; + LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete; + +private: + LocalDataPool localPoolMap; + //! Every housekeeping data manager has a mutex to protect access + //! to it's data pool. + MutexIF* mutex = nullptr; + + /** The class which actually owns the manager (and its datapool). */ + HasLocalDataPoolIF* owner = nullptr; + + uint8_t nonDiagnosticIntervalFactor = 0; + + /** Default receiver for periodic HK packets */ + static object_id_t defaultHkDestination; + MessageQueueId_t hkDestinationId = MessageQueueIF::NO_QUEUE; + + union DataId { + DataId(): sid() {}; + sid_t sid; + lp_id_t localPoolId; + }; + + /** The data pool manager will keep an internal map of HK receivers. */ + struct HkReceiver { + /** Object ID of receiver */ + object_id_t objectId = objects::NO_OBJECT; + + DataType dataType = DataType::DATA_SET; + DataId dataId; + + ReportingType reportingType = ReportingType::PERIODIC; + MessageQueueId_t destinationQueue = MessageQueueIF::NO_QUEUE; + }; + + /** This vector will contain the list of HK receivers. */ + using HkReceivers = std::vector; + + HkReceivers hkReceiversMap; + + struct HkUpdateResetHelper { + DataType dataType = DataType::DATA_SET; + DataId dataId; + uint8_t updateCounter; + uint8_t currentUpdateCounter; + }; + + using HkUpdateResetList = std::vector; + // Will only be created when needed. + HkUpdateResetList* hkUpdateResetList = nullptr; + + /** This is the map holding the actual data. Should only be initialized + * once ! */ + bool mapInitialized = false; + /** This specifies whether a validity buffer is appended at the end + * of generated housekeeping packets. */ + bool appendValidityBuffer = true; + + /** + * @brief Queue used for communication, for example commands. + * Is also used to send messages. Can be set either in the constructor + * or in the initialize() function. + */ + MessageQueueIF* hkQueue = nullptr; + + /** Global IPC store is used to store all packets. */ + StorageManagerIF* ipcStore = nullptr; + /** + * Get the pointer to the mutex. Can be used to lock the data pool + * externally. Use with care and don't forget to unlock locked mutexes! + * For now, only friend classes can accss this function. + * @return + */ + MutexIF* getMutexHandle(); + + /** + * Read a variable by supplying its local pool ID and assign the pool + * entry to the supplied PoolEntry pointer. The type of the pool entry + * is deduced automatically. This call is not thread-safe! + * For now, only friend classes like LocalPoolVar may access this + * function. + * @tparam T Type of the pool entry + * @param localPoolId Pool ID of the variable to read + * @param poolVar [out] Corresponding pool entry will be assigned to the + * supplied pointer. + * @return + */ + template ReturnValue_t fetchPoolEntry(lp_id_t localPoolId, + PoolEntry **poolEntry); + + /** + * This function is used to fill the local data pool map with pool + * entries. It should only be called once by the pool owner. + * @param localDataPoolMap + * @return + */ + ReturnValue_t initializeHousekeepingPoolEntriesOnce(); + + ReturnValue_t serializeHkPacketIntoStore( + HousekeepingPacketDownlink& hkPacket, + store_address_t& storeId, bool forDownlink, size_t* serializedSize); + + void performPeriodicHkGeneration(HkReceiver& hkReceiver); + ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, + bool isDiagnostics); + ReturnValue_t changeCollectionInterval(sid_t sid, + float newCollectionInterval, bool isDiagnostics); + ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics); + + void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId); + void handleChangeResetLogic(DataType type, + DataId dataId, MarkChangedIF* toReset); + void resetHkUpdateResetHelper(); + + ReturnValue_t handleHkUpdate(HkReceiver& hkReceiver, + ReturnValue_t& status); + ReturnValue_t handleNotificationUpdate(HkReceiver& hkReceiver, + ReturnValue_t& status); + ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver, + ReturnValue_t& status); + ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket, + store_address_t& storeId); +}; + + +template inline +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; + } + + *poolEntry = dynamic_cast< PoolEntry* >(poolIter->second); + if(*poolEntry == nullptr) { + sif::debug << "HousekeepingManager::fetchPoolEntry:" + " Pool entry not found." << std::endl; + return POOL_ENTRY_TYPE_CONFLICT; + } + return HasReturnvaluesIF::RETURN_OK; +} + + +#endif /* FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ */ diff --git a/datapoollocal/LocalDataSet.cpp b/datapoollocal/LocalDataSet.cpp new file mode 100644 index 00000000..394a9abe --- /dev/null +++ b/datapoollocal/LocalDataSet.cpp @@ -0,0 +1,22 @@ +#include "LocalDataSet.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../serialize/SerializeAdapter.h" + +#include +#include + +LocalDataSet::LocalDataSet(HasLocalDataPoolIF *hkOwner, uint32_t setId, + const size_t maxNumberOfVariables): + LocalPoolDataSetBase(hkOwner, setId, nullptr, maxNumberOfVariables), + poolVarList(maxNumberOfVariables) { + this->setContainer(poolVarList.data()); +} + +LocalDataSet::LocalDataSet(sid_t sid, const size_t maxNumberOfVariables): + LocalPoolDataSetBase(sid, nullptr, maxNumberOfVariables), + poolVarList(maxNumberOfVariables) { + this->setContainer(poolVarList.data()); +} + +LocalDataSet::~LocalDataSet() {} + diff --git a/datapoollocal/LocalDataSet.h b/datapoollocal/LocalDataSet.h new file mode 100644 index 00000000..0368f26d --- /dev/null +++ b/datapoollocal/LocalDataSet.h @@ -0,0 +1,21 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALDATASET_H_ +#define FSFW_DATAPOOLLOCAL_LOCALDATASET_H_ + +#include "LocalPoolDataSetBase.h" +#include + +class LocalDataSet: public LocalPoolDataSetBase { +public: + LocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId, + const size_t maxSize); + LocalDataSet(sid_t sid, const size_t maxSize); + virtual~ LocalDataSet(); + + //! Copying forbidden for now. + LocalDataSet(const LocalDataSet&) = delete; + LocalDataSet& operator=(const LocalDataSet&) = delete; +private: + std::vector poolVarList; +}; + +#endif /* FSFW_DATAPOOLLOCAL_LOCALDATASET_H_ */ diff --git a/datapoollocal/LocalPoolDataSetBase.cpp b/datapoollocal/LocalPoolDataSetBase.cpp new file mode 100644 index 00000000..640956db --- /dev/null +++ b/datapoollocal/LocalPoolDataSetBase.cpp @@ -0,0 +1,278 @@ +#include "LocalPoolDataSetBase.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../housekeeping/PeriodicHousekeepingHelper.h" +#include "../serialize/SerializeAdapter.h" + +#include +#include + +LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, + uint32_t setId, PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables, bool noPeriodicHandling): + PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { + if(hkOwner == nullptr) { + // Configuration error. + sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " + << "invalid!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + 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) { + periodicHelper = new PeriodicHousekeepingHelper(this); + } +} + +LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, + PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables): + PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { + HasLocalDataPoolIF* hkOwner = objectManager->get( + sid.objectId); + if(hkOwner == nullptr) { + // Configuration error. + sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " + << "invalid!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + this->sid = sid; + + mutex = MutexFactory::instance()->createMutex(); +} + +LocalPoolDataSetBase::~LocalPoolDataSetBase() { +} + +ReturnValue_t LocalPoolDataSetBase::lockDataPool(uint32_t timeoutMs) { + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->lockMutex(MutexIF::TimeoutType::WAITING, timeoutMs); +} + +ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer, + size_t *size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + uint8_t validityMaskSize = std::ceil(static_cast(fillCount)/8.0); + uint8_t validityMask[validityMaskSize]; + uint8_t validBufferIndex = 0; + uint8_t validBufferIndexBit = 0; + for (uint16_t count = 0; count < fillCount; count++) { + if(registeredVariables[count]->isValid()) { + // set validity buffer here. + this->bitSetter(validityMask + validBufferIndex, + validBufferIndexBit); + if(validBufferIndexBit == 7) { + validBufferIndex ++; + validBufferIndexBit = 0; + } + else { + validBufferIndexBit ++; + } + } + result = registeredVariables[count]->serialize(buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + if(*size + validityMaskSize > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + // copy validity buffer to end + std::memcpy(*buffer, validityMask, validityMaskSize); + *size += validityMaskSize; + return result; +} + +ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer( + const uint8_t **buffer, size_t *size, + SerializeIF::Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->deSerialize(buffer, size, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + if(*size < std::ceil(static_cast(fillCount) / 8.0)) { + return SerializeIF::STREAM_TOO_SHORT; + } + + uint8_t validBufferIndex = 0; + uint8_t validBufferIndexBit = 0; + for (uint16_t count = 0; count < fillCount; count++) { + // set validity buffer here. + bool nextVarValid = this->bitGetter(*buffer + + validBufferIndex, validBufferIndexBit); + registeredVariables[count]->setValid(nextVarValid); + + if(validBufferIndexBit == 7) { + validBufferIndex ++; + validBufferIndexBit = 0; + } + else { + validBufferIndexBit ++; + } + } + return result; +} + +ReturnValue_t LocalPoolDataSetBase::unlockDataPool() { + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->unlockMutex(); +} + +ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer, + size_t* size, size_t maxSize,SerializeIF::Endianness streamEndianness, + bool serializeFillCount) const { + // Serialize as uint8_t + uint8_t fillCount = this->fillCount; + if(serializeFillCount) { + SerializeAdapter::serialize(&fillCount, buffer, size, maxSize, + streamEndianness); + } + for (uint16_t count = 0; count < fillCount; count++) { + lp_id_t currentPoolId = registeredVariables[count]->getDataPoolId(); + auto result = SerializeAdapter::serialize(¤tPoolId, buffer, + size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization" + " error!" << std::endl; + return result; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + + +uint8_t LocalPoolDataSetBase::getLocalPoolIdsSerializedSize( + bool serializeFillCount) const { + if(serializeFillCount) { + return fillCount * sizeof(lp_id_t) + sizeof(uint8_t); + } + else { + return fillCount * sizeof(lp_id_t); + } +} + +size_t LocalPoolDataSetBase::getSerializedSize() const { + if(withValidityBuffer) { + uint8_t validityMaskSize = std::ceil(static_cast(fillCount)/8.0); + return validityMaskSize + PoolDataSetBase::getSerializedSize(); + } + else { + return PoolDataSetBase::getSerializedSize(); + } +} + +void LocalPoolDataSetBase::setValidityBufferGeneration( + bool withValidityBuffer) { + this->withValidityBuffer = withValidityBuffer; +} + +ReturnValue_t LocalPoolDataSetBase::deSerialize(const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + if(withValidityBuffer) { + return this->deSerializeWithValidityBuffer(buffer, size, + streamEndianness); + } + else { + return PoolDataSetBase::deSerialize(buffer, size, streamEndianness); + } +} + +ReturnValue_t LocalPoolDataSetBase::serialize(uint8_t **buffer, size_t *size, + size_t maxSize, SerializeIF::Endianness streamEndianness) const { + if(withValidityBuffer) { + return this->serializeWithValidityBuffer(buffer, size, + maxSize, streamEndianness); + } + else { + return PoolDataSetBase::serialize(buffer, size, maxSize, + streamEndianness); + } +} + +void LocalPoolDataSetBase::bitSetter(uint8_t* byte, uint8_t position) const { + if(position > 7) { + sif::debug << "Pool Raw Access: Bit setting invalid position" + << std::endl; + return; + } + uint8_t shiftNumber = position + (7 - 2 * position); + *byte |= 1 << shiftNumber; +} + +void LocalPoolDataSetBase::setDiagnostic(bool isDiagnostics) { + this->diagnostic = isDiagnostics; +} + +bool LocalPoolDataSetBase::isDiagnostics() const { + return diagnostic; +} + +void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) { + this->reportingEnabled = reportingEnabled; +} + +bool LocalPoolDataSetBase::getReportingEnabled() const { + return reportingEnabled; +} + +void LocalPoolDataSetBase::initializePeriodicHelper( + float collectionInterval, dur_millis_t minimumPeriodicInterval, + bool isDiagnostics, uint8_t nonDiagIntervalFactor) { + periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, + isDiagnostics, nonDiagIntervalFactor); +} + +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; +} + +sid_t LocalPoolDataSetBase::getSid() const { + return sid; +} + +bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte, + uint8_t position) const { + if(position > 7) { + sif::debug << "Pool Raw Access: Bit setting invalid position" + << std::endl; + return false; + } + uint8_t shiftNumber = position + (7 - 2 * position); + return *byte & (1 << shiftNumber); +} + +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); + } + } + this->valid = valid; +} diff --git a/datapoollocal/LocalPoolDataSetBase.h b/datapoollocal/LocalPoolDataSetBase.h new file mode 100644 index 00000000..aa155bf1 --- /dev/null +++ b/datapoollocal/LocalPoolDataSetBase.h @@ -0,0 +1,198 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ + +#include "HasLocalDataPoolIF.h" +#include "MarkChangedIF.h" + +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolDataSetBase.h" +#include "../serialize/SerializeIF.h" + +#include + +class LocalDataPoolManager; +class PeriodicHousekeepingHelper; + +/** + * @brief The LocalDataSet class manages a set of locally checked out + * variables for local data pools + * @details + * Extends the PoolDataSetBase class for local data pools by introducing + * a validity state, a flag to mark the set as changed, and various other + * functions to make it usable by the LocalDataPoolManager class. + * + * This class manages a list, where a set of local variables (or pool variables) + * are registered. They are checked-out (i.e. their values are looked + * up and copied) with the read call. After the user finishes working with the + * pool variables, he can write back all variable values to the pool with + * the commit call. The data set manages locking and freeing the local data + * pools, to ensure thread-safety. + * + * Pool variables can be added to the dataset by using the constructor + * argument of the pool variable or using the #registerVariable member function. + * + * An internal state manages usage of this class. Variables may only be + * registered before any read call is made, and the commit call can only happen + * after the read call. + * + * If pool variables are writable and not committed until destruction + * of the set, the DataSet class automatically sets the valid flag in the + * data pool to invalid (without) changing the variable's value. + * + * @ingroup data_pool + */ +class LocalPoolDataSetBase: public PoolDataSetBase, + public MarkChangedIF { + friend class LocalDataPoolManager; + 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 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 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(); + + void setValidityBufferGeneration(bool withValidityBuffer); + + sid_t getSid() const; + + /** SerializeIF overrides */ + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + ReturnValue_t deSerialize(const uint8_t** buffer, size_t *size, + SerializeIF::Endianness streamEndianness) override; + size_t getSerializedSize() const override; + + /** + * Special version of the serilization function which appends a + * validity buffer at the end. Each bit of this validity buffer + * denotes whether the container data set entries are valid from left + * to right, MSB first. (length = ceil(N/8), N = number of pool variables) + * @param buffer + * @param size + * @param maxSize + * @param bigEndian + * @param withValidityBuffer + * @return + */ + ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const; + ReturnValue_t deSerializeWithValidityBuffer(const uint8_t** buffer, + size_t *size, SerializeIF::Endianness streamEndianness); + ReturnValue_t serializeLocalPoolIds(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness, + bool serializeFillCount = true) const; + uint8_t getLocalPoolIdsSerializedSize(bool serializeFillCount = true) const; + + /** + * Set the dataset valid or invalid. These calls are mutex protected. + * @param setEntriesRecursively + * If this is true, all contained datasets will also be set recursively. + */ + void setValidity(bool valid, bool setEntriesRecursively); + bool isValid() const override; + + /** + * These calls are mutex protected. + * @param changed + */ + void setChanged(bool changed) override; + bool hasChanged() const override; + +protected: + sid_t sid; + MutexIF* mutex = nullptr; + + bool diagnostic = false; + void setDiagnostic(bool diagnostics); + bool isDiagnostics() 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); + + /** + * If the valid state of a dataset is always relevant to the whole + * data set we can use this flag. + */ + bool valid = false; + + /** + * Can be used to mark the dataset as changed, which is used + * by the LocalDataPoolManager to send out update messages. + */ + bool changed = false; + + /** + * Specify whether the validity buffer is serialized too when serializing + * or deserializing the packet. Each bit of the validity buffer will + * contain the validity state of the pool variables from left to right. + * The size of validity buffer thus will be ceil(N / 8) with N = number of + * pool variables. + */ + bool withValidityBuffer = true; + + /** + * @brief This is a small helper function to facilitate locking + * the global data pool. + * @details + * It makes use of the lockDataPool method offered by the DataPool class. + */ + ReturnValue_t lockDataPool(uint32_t timeoutMs) override; + /** + * @brief This is a small helper function to facilitate + * unlocking the global data pool + * @details + * It makes use of the freeDataPoolLock method offered by the DataPool class. + */ + ReturnValue_t unlockDataPool() override; + + LocalDataPoolManager* hkManager; + + /** + * 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; + +}; + + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ */ diff --git a/datapoollocal/LocalPoolObjectBase.cpp b/datapoollocal/LocalPoolObjectBase.cpp new file mode 100644 index 00000000..b4d0e306 --- /dev/null +++ b/datapoollocal/LocalPoolObjectBase.cpp @@ -0,0 +1,73 @@ +#include "LocalPoolObjectBase.h" + +LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, + HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode): localPoolId(poolId), + readWriteMode(setReadWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " + << "which is the NO_PARAMETER value!" << std::endl; + } + if(hkOwner == nullptr) { + sif::error << "LocalPoolVar::LocalPoolVar: The supplied pool " + << "owner is a invalid!" << std::endl; + return; + } + hkManager = hkOwner->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) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " + << "which is the NO_PARAMETER value!" << std::endl; + } + HasLocalDataPoolIF* hkOwner = + objectManager->get(poolOwner); + if(hkOwner == nullptr) { + sif::error << "LocalPoolVariable: The supplied pool owner did not " + << "implement the correct interface" + << " HasLocalDataPoolIF!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + if(dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +pool_rwm_t LocalPoolObjectBase::getReadWriteMode() const { + return readWriteMode; +} + +bool LocalPoolObjectBase::isValid() const { + return valid; +} + +void LocalPoolObjectBase::setValid(bool valid) { + this->valid = valid; +} + +lp_id_t LocalPoolObjectBase::getDataPoolId() const { + return localPoolId; +} + +void LocalPoolObjectBase::setDataPoolId(lp_id_t poolId) { + this->localPoolId = poolId; +} + +void LocalPoolObjectBase::setChanged(bool changed) { + this->changed = changed; +} + +bool LocalPoolObjectBase::hasChanged() const { + return changed; +} + +void LocalPoolObjectBase::setReadWriteMode(pool_rwm_t newReadWriteMode) { + this->readWriteMode = newReadWriteMode; +} diff --git a/datapoollocal/LocalPoolObjectBase.h b/datapoollocal/LocalPoolObjectBase.h new file mode 100644 index 00000000..7165fc24 --- /dev/null +++ b/datapoollocal/LocalPoolObjectBase.h @@ -0,0 +1,63 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ + +#include "MarkChangedIF.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../datapool/PoolVariableIF.h" + + +class LocalPoolObjectBase: public PoolVariableIF, + public HasReturnvaluesIF, + public MarkChangedIF { +public: + LocalPoolObjectBase(lp_id_t poolId, + HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode); + + LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + void setReadWriteMode(pool_rwm_t newReadWriteMode); + pool_rwm_t getReadWriteMode() const; + + bool isValid() const override; + void setValid(bool valid) override; + + void setChanged(bool changed) override; + bool hasChanged() const override; + + lp_id_t getDataPoolId() const override; + void setDataPoolId(lp_id_t poolId); + +protected: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool id is stored. + */ + uint32_t localPoolId = PoolVariableIF::NO_PARAMETER; + /** + * @brief The valid information as it was stored in the data pool + * is copied to this attribute. + */ + bool valid = false; + + /** + * @brief A local pool variable can be marked as changed. + */ + bool changed = false; + + /** + * @brief The information whether the class is read-write or + * read-only is stored here. + */ + ReadWriteMode_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; + + //! @brief Pointer to the class which manages the HK pool. + LocalDataPoolManager* hkManager; + +}; + + + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ */ diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h new file mode 100644 index 00000000..c18d5443 --- /dev/null +++ b/datapoollocal/LocalPoolVariable.h @@ -0,0 +1,185 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ + +#include "LocalPoolObjectBase.h" +#include "HasLocalDataPoolIF.h" +#include "LocalDataPoolManager.h" + +#include "../datapool/PoolVariableIF.h" +#include "../datapool/DataSetIF.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../serialize/SerializeAdapter.h" + +/** + * @brief Local Pool Variable class which is used to access the local pools. + * @details + * This class is not stored in the map. Instead, it is used to access + * the pool entries by using a pointer to the map storing the pool + * entries. It can also be used to organize these pool entries into data sets. + * + * @tparam T The template parameter sets the type of the variable. Currently, + * all plain data types are supported, but in principle any type is possible. + * @ingroup data_pool + */ +template +class LocalPoolVar: public LocalPoolObjectBase { +public: + //! Default ctor is forbidden. + LocalPoolVar() = 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. + */ + LocalPoolVar(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. + * + */ + LocalPoolVar(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 + */ + LocalPoolVar(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + virtual~ LocalPoolVar() {}; + + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a simple local variable. + */ + T value = 0; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; + + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the data pool and copies all array values and the valid + * information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + * + */ + ReturnValue_t read(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; + + + LocalPoolVar &operator=(const T& newValue); + LocalPoolVar &operator=(const LocalPoolVar& newPoolVariable); + + //! Explicit type conversion operator. Allows casting the class to + //! its template type to perform operations on value. + explicit operator T() const; + + bool operator==(const LocalPoolVar& other) const; + bool operator==(const T& other) const; + + bool operator!=(const LocalPoolVar& other) const; + bool operator!=(const T& other) const; + + bool operator<(const LocalPoolVar& other) const; + bool operator<(const T& other) const; + + bool operator>(const LocalPoolVar& 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; + + // std::ostream is the type for object std::cout + template + friend std::ostream& operator<< (std::ostream &out, + const LocalPoolVar &var); + +private: +}; + +#include "LocalPoolVariable.tpp" + +template +using lp_var_t = LocalPoolVar; + +using lp_bool_t = LocalPoolVar; +using lp_uint8_t = LocalPoolVar; +using lp_uint16_t = LocalPoolVar; +using lp_uint32_t = LocalPoolVar; +using lp_uint64_t = LocalPoolVar; +using lp_int8_t = LocalPoolVar; +using lp_int16_t = LocalPoolVar; +using lp_int32_t = LocalPoolVar; +using lp_int64_t = LocalPoolVar; +using lp_float_t = LocalPoolVar; +using lp_double_t = LocalPoolVar; + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ */ diff --git a/datapoollocal/LocalPoolVariable.tpp b/datapoollocal/LocalPoolVariable.tpp new file mode 100644 index 00000000..b9f7b906 --- /dev/null +++ b/datapoollocal/LocalPoolVariable.tpp @@ -0,0 +1,169 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ + +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ +#error Include LocalPoolVariable.h before LocalPoolVariable.tpp! +#endif + +template +inline LocalPoolVar::LocalPoolVar(HasLocalDataPoolIF* hkOwner, + lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} + +template +inline LocalPoolVar::LocalPoolVar(object_id_t poolOwner, lp_id_t poolId, + DataSetIF *dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} + + +template +inline LocalPoolVar::LocalPoolVar(gp_id_t globalPoolId, DataSetIF *dataSet, + pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, + dataSet, setReadWriteMode){} + + +template +inline ReturnValue_t LocalPoolVar::read(dur_millis_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, + lockTimeout); + return readWithoutLock(); +} + +template +inline ReturnValue_t LocalPoolVar::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; + } + + 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; +} + +template +inline ReturnValue_t LocalPoolVar::commit(dur_millis_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, + lockTimeout); + return commitWithoutLock(); +} + +template +inline ReturnValue_t LocalPoolVar::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; +} + +template +inline ReturnValue_t LocalPoolVar::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 LocalPoolVar::getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&value); +} + +template +inline ReturnValue_t LocalPoolVar::deSerialize(const uint8_t** buffer, + size_t* size, SerializeIF::Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); +} + +template +inline std::ostream& operator<< (std::ostream &out, + const LocalPoolVar &var) { + out << var.value; + return out; +} + +template +inline LocalPoolVar::operator T() const { + return value; +} + +template +inline LocalPoolVar & LocalPoolVar::operator=(const T& newValue) { + value = newValue; + return *this; +} + +template +inline LocalPoolVar& LocalPoolVar::operator =( + const LocalPoolVar& newPoolVariable) { + value = newPoolVariable.value; + return *this; +} + +template +inline bool LocalPoolVar::operator ==(const LocalPoolVar &other) const { + return this->value == other.value; +} + +template +inline bool LocalPoolVar::operator ==(const T &other) const { + return this->value == other; +} + + +template +inline bool LocalPoolVar::operator !=(const LocalPoolVar &other) const { + return not (*this == other); +} + +template +inline bool LocalPoolVar::operator !=(const T &other) const { + return not (*this == other); +} + + +template +inline bool LocalPoolVar::operator <(const LocalPoolVar &other) const { + return this->value < other.value; +} + +template +inline bool LocalPoolVar::operator <(const T &other) const { + return this->value < other; +} + + +template +inline bool LocalPoolVar::operator >(const LocalPoolVar &other) const { + return not (*this < other); +} + +template +inline bool LocalPoolVar::operator >(const T &other) const { + return not (*this < other); +} + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */ diff --git a/datapoollocal/LocalPoolVector.h b/datapoollocal/LocalPoolVector.h new file mode 100644 index 00000000..58face3c --- /dev/null +++ b/datapoollocal/LocalPoolVector.h @@ -0,0 +1,174 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ + +#include "LocalPoolObjectBase.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" + + +/** + * @brief This is the access class for array-type data pool entries. + * @details + * To ensure safe usage of the data pool, operation is not done directly on the + * data pool entries, but on local copies. This class provides simple type- + * and length-safe access to vector-style data pool entries (i.e. entries with + * length > 1). The class can be instantiated as read-write and read only. + * + * It provides a commit-and-roll-back semantic, which means that no array + * entry in the data pool is changed until the commit call is executed. + * There are two template parameters: + * @tparam T + * This template parameter specifies the data type of an array entry. Currently, + * all plain data types are supported, but in principle any type is possible. + * @tparam vector_size + * This template parameter specifies the vector size of this entry. Using a + * template parameter for this is not perfect, but avoids + * dynamic memory allocation. + * @ingroup data_pool + */ +template +class LocalPoolVector: public LocalPoolObjectBase { +public: + LocalPoolVector() = delete; + /** + * This constructor is used by the data creators to have pool variable + * instances which can also be stored in datasets. + * It does not fetch the current value from the data pool. This is performed + * by the read() operation (which is not thread-safe). + * Datasets can be used to access local pool entires in a thread-safe way. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + /** + * This constructor is used by data users like controllers to have + * access to the local pool variables of data creators by supplying + * the respective creator object ID. + * It does not fetch the current value from the data pool. This is performed + * by the read() operation (which is not thread-safe). + * Datasets can be used to access local pool entires in a thread-safe way. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVector(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * Variation which takes the unique global identifier of a local pool + * vector. + * @param globalPoolId + * @param dataSet + * @param setReadWriteMode + */ + LocalPoolVector(gp_id_t globalPoolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + /** + * @brief This is the local copy of the data pool entry. + * @details + * The user can work on this attribute just like he would on a local + * array of this type. + */ + T value[vectorSize]; + /** + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~LocalPoolVector() {}; + /** + * @brief The operation returns the number of array entries + * in this variable. + */ + uint8_t getSize() { + return vectorSize; + } + + T& operator [](int i); + const T &operator [](int i) const; + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, + SerializeIF::Endianness streamEndiannes) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; + + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the data pool and copies all array values and the valid + * information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t read(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; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + +private: + + + // std::ostream is the type for object std::cout + template + friend std::ostream& operator<< (std::ostream &out, + const LocalPoolVector &var); + + +}; + +#include "LocalPoolVector.tpp" + +template +using lp_vec_t = LocalPoolVector; + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ */ diff --git a/datapoollocal/LocalPoolVector.tpp b/datapoollocal/LocalPoolVector.tpp new file mode 100644 index 00000000..46123ccc --- /dev/null +++ b/datapoollocal/LocalPoolVector.tpp @@ -0,0 +1,158 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ + +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#error Include LocalPoolVector.h before LocalPoolVector.tpp! +#endif + +template +inline LocalPoolVector::LocalPoolVector( + 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) {} + + +template +inline LocalPoolVector::LocalPoolVector(gp_id_t globalPoolId, + 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(); +} +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; + } + + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = hkManager->fetchPoolEntry(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; +} + +template +inline ReturnValue_t LocalPoolVector::commit( + uint32_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, + lockTimeout); + 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; +} + +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]; +} + +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]; +} + +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; +} + +template +inline size_t LocalPoolVector::getSerializedSize() const { + 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; +} + +template +inline std::ostream& operator<< (std::ostream &out, + const LocalPoolVector &var) { + out << "Vector: ["; + for(int i = 0;i < vectorSize; i++) { + out << var.value[i]; + if(i < vectorSize - 1) { + out << ", "; + } + } + out << "]"; + return out; +} + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ */ diff --git a/datapoollocal/MarkChangedIF.h b/datapoollocal/MarkChangedIF.h new file mode 100644 index 00000000..e575d1d3 --- /dev/null +++ b/datapoollocal/MarkChangedIF.h @@ -0,0 +1,17 @@ +#ifndef FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ +#define FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ + +/** + * Common interface for local pool entities which can be marked as changed. + */ +class MarkChangedIF { +public: + virtual~ MarkChangedIF() {}; + + virtual bool hasChanged() const = 0; + virtual void setChanged(bool changed) = 0; +}; + + + +#endif /* FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ */ diff --git a/datapoollocal/SharedLocalDataSet.cpp b/datapoollocal/SharedLocalDataSet.cpp new file mode 100644 index 00000000..dd1bdcc4 --- /dev/null +++ b/datapoollocal/SharedLocalDataSet.cpp @@ -0,0 +1,16 @@ +#include "SharedLocalDataSet.h" + +SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId, sid_t sid, + const size_t maxSize): SystemObject(objectId), + LocalPoolDataSetBase(sid, nullptr, maxSize) { + this->setContainer(poolVarVector.data()); + datasetLock = MutexFactory::instance()->createMutex(); +} + +ReturnValue_t SharedLocalDataSet::lockDataset(dur_millis_t mutexTimeout) { + return datasetLock->lockMutex(MutexIF::TimeoutType::WAITING, mutexTimeout); +} + +ReturnValue_t SharedLocalDataSet::unlockDataset() { + return datasetLock->unlockMutex(); +} diff --git a/datapoollocal/SharedLocalDataSet.h b/datapoollocal/SharedLocalDataSet.h new file mode 100644 index 00000000..2e5a76fa --- /dev/null +++ b/datapoollocal/SharedLocalDataSet.h @@ -0,0 +1,24 @@ +#ifndef FSFW_DATAPOOLLOCAL_SHAREDLOCALDATASET_H_ +#define FSFW_DATAPOOLLOCAL_SHAREDLOCALDATASET_H_ + +#include "LocalPoolDataSetBase.h" +#include "../datapool/SharedDataSetIF.h" +#include "../objectmanager/SystemObject.h" +#include + +class SharedLocalDataSet: public SystemObject, + public LocalPoolDataSetBase, + public SharedDataSetIF { +public: + SharedLocalDataSet(object_id_t objectId, sid_t sid, + const size_t maxSize); + ReturnValue_t lockDataset(dur_millis_t mutexTimeout) override; + ReturnValue_t unlockDataset() override; +private: + + MutexIF* datasetLock = nullptr; + std::vector poolVarVector; +}; + + +#endif /* FSFW_DATAPOOLLOCAL_SHAREDLOCALDATASET_H_ */ diff --git a/datapoollocal/StaticLocalDataSet.h b/datapoollocal/StaticLocalDataSet.h new file mode 100644 index 00000000..a637e360 --- /dev/null +++ b/datapoollocal/StaticLocalDataSet.h @@ -0,0 +1,50 @@ +#ifndef FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ +#define FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ + +#include "LocalPoolDataSetBase.h" +#include "../objectmanager/SystemObjectIF.h" +#include + +/** + * @brief This local dataset type is created on the stack. + * @details + * This will is the primary data structure to organize pool variables into + * sets which can be accessed via the housekeeping service interface or + * which can be sent to other software objects. + * + * It is recommended to read the documentation of the LocalPoolDataSetBase + * class for more information on how this class works and how to use it. + * @tparam capacity Capacity of the static dataset, which is usually known + * beforehand. + */ +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) { + this->setContainer(poolVarList.data()); + } + + /** + * Constructor used by data users like controllers. + * @param hkOwner + * @param setId + */ + StaticLocalDataSet(sid_t sid): LocalPoolDataSetBase(sid, nullptr, + NUM_VARIABLES) { + this->setContainer(poolVarList.data()); + } + +private: + std::array poolVarList; +}; + +#endif /* FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ */ diff --git a/datapoollocal/locPoolDefinitions.h b/datapoollocal/locPoolDefinitions.h new file mode 100644 index 00000000..6e74d349 --- /dev/null +++ b/datapoollocal/locPoolDefinitions.h @@ -0,0 +1,93 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ +#define FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ + +#include +#include "../objectmanager/SystemObjectIF.h" +#include "../objectmanager/frameworkObjects.h" + +/** + * @brief Type definition for local pool entries. + */ +using lp_id_t = uint32_t; + +namespace localpool { +static constexpr uint32_t INVALID_LPID = -1; +} + +/** + * Used as a unique identifier for data sets. + */ +union sid_t { + static constexpr uint64_t INVALID_SID = -1; + static constexpr uint32_t INVALID_OBJECT_ID = objects::NO_OBJECT; + static constexpr uint32_t INVALID_SET_ID = -1; + + + sid_t(): raw(INVALID_SID) {} + + sid_t(object_id_t objectId, uint32_t setId): + objectId(objectId), + ownerSetId(setId) {} + + struct { + object_id_t objectId ; + /** + * A generic 32 bit ID to identify unique HK packets for a single + * object. For example, the DeviceCommandId_t is used for + * DeviceHandlers + */ + uint32_t ownerSetId; + }; + /** + * Alternative access to the raw value. This is also the size of the type. + */ + uint64_t raw; + + bool notSet() const { + return raw == INVALID_SID; + } + + bool operator==(const sid_t& other) const { + return raw == other.raw; + } + + bool operator!=(const sid_t& other) const { + return not (raw == other.raw); + } +}; + +/** + * Used as a global unique identifier for local pool variables. + */ +union gp_id_t { + 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; + + gp_id_t(): raw(INVALID_GPID) {} + + gp_id_t(object_id_t objectId, lp_id_t localPoolId): + objectId(objectId), + localPoolId(localPoolId) {} + + struct { + object_id_t objectId; + lp_id_t localPoolId; + }; + + uint64_t raw; + + bool notSet() const { + return raw == INVALID_GPID; + } + + bool operator==(const sid_t& other) const { + return raw == other.raw; + } + + bool operator!=(const sid_t& other) const { + return not (raw == other.raw); + } +}; + +#endif /* FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ */ diff --git a/defaultcfg/fsfwconfig/CMakeLists.txt b/defaultcfg/fsfwconfig/CMakeLists.txt new file mode 100644 index 00000000..b8b41c93 --- /dev/null +++ b/defaultcfg/fsfwconfig/CMakeLists.txt @@ -0,0 +1,15 @@ +target_sources(${TARGET_NAME} + PRIVATE +) + +# Add include paths for the executable +target_include_directories(${TARGET_NAME} + PUBLIC + ${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 diff --git a/defaultcfg/config/FSFWConfig.h b/defaultcfg/fsfwconfig/FSFWConfig.h similarity index 81% rename from defaultcfg/config/FSFWConfig.h rename to defaultcfg/fsfwconfig/FSFWConfig.h index ea86152c..1386bf66 100644 --- a/defaultcfg/config/FSFWConfig.h +++ b/defaultcfg/fsfwconfig/FSFWConfig.h @@ -1,19 +1,19 @@ #ifndef CONFIG_FSFWCONFIG_H_ #define CONFIG_FSFWCONFIG_H_ -#include #include +#include //! Used to determine whether C++ ostreams are used //! Those can lead to code bloat. #define FSFW_CPP_OSTREAM_ENABLED 1 -//! Reduced printout to further decrese code size +//! Reduced printout to further decrease code size //! Be careful, this also turns off most diagnostic prinouts! -#define FSFW_REDUCED_PRINTOUT 0 +#define FSFW_ENHANCED_PRINTOUT 0 -//! Can be used to enable debugging printouts for developing the FSFW -#define FSFW_DEBUGGING 0 +//! Can be used to enable additional debugging printouts for developing the FSFW +#define FSFW_PRINT_VERBOSITY_LEVEL 0 //! Defines the FIFO depth of each commanding service base which //! also determines how many commands a CSB service can handle in one cycle @@ -38,7 +38,10 @@ //! When using the newlib nano library, C99 support for stdio facilities //! will not be provided. This define should be set to 1 if this is the case. -#define FSFW_NO_C99_IO 1 +#define FSFW_NO_C99_IO 1 + +//! Specify whether a special mode store is used for Subsystem components. +#define FSFW_USE_MODESTORE 0 namespace fsfwconfig { //! Default timestamp size. The default timestamp will be an eight byte CDC diff --git a/defaultcfg/config/OBSWConfig.h b/defaultcfg/fsfwconfig/OBSWConfig.h similarity index 100% rename from defaultcfg/config/OBSWConfig.h rename to defaultcfg/fsfwconfig/OBSWConfig.h diff --git a/defaultcfg/config/OBSWVersion.h b/defaultcfg/fsfwconfig/OBSWVersion.h similarity index 100% rename from defaultcfg/config/OBSWVersion.h rename to defaultcfg/fsfwconfig/OBSWVersion.h diff --git a/defaultcfg/config/devices/logicalAddresses.cpp b/defaultcfg/fsfwconfig/devices/logicalAddresses.cpp similarity index 100% rename from defaultcfg/config/devices/logicalAddresses.cpp rename to defaultcfg/fsfwconfig/devices/logicalAddresses.cpp diff --git a/defaultcfg/config/devices/logicalAddresses.h b/defaultcfg/fsfwconfig/devices/logicalAddresses.h similarity index 89% rename from defaultcfg/config/devices/logicalAddresses.h rename to defaultcfg/fsfwconfig/devices/logicalAddresses.h index 174fa788..e0827ba3 100644 --- a/defaultcfg/config/devices/logicalAddresses.h +++ b/defaultcfg/fsfwconfig/devices/logicalAddresses.h @@ -1,8 +1,8 @@ #ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_ #define CONFIG_DEVICES_LOGICALADDRESSES_H_ -#include #include +#include "../objects/systemObjectList.h" #include /** diff --git a/defaultcfg/config/devices/powerSwitcherList.cpp b/defaultcfg/fsfwconfig/devices/powerSwitcherList.cpp similarity index 100% rename from defaultcfg/config/devices/powerSwitcherList.cpp rename to defaultcfg/fsfwconfig/devices/powerSwitcherList.cpp diff --git a/defaultcfg/config/devices/powerSwitcherList.h b/defaultcfg/fsfwconfig/devices/powerSwitcherList.h similarity index 100% rename from defaultcfg/config/devices/powerSwitcherList.h rename to defaultcfg/fsfwconfig/devices/powerSwitcherList.h diff --git a/defaultcfg/config/events/subsystemIdRanges.h b/defaultcfg/fsfwconfig/events/subsystemIdRanges.h similarity index 100% rename from defaultcfg/config/events/subsystemIdRanges.h rename to defaultcfg/fsfwconfig/events/subsystemIdRanges.h diff --git a/defaultcfg/config/config.mk b/defaultcfg/fsfwconfig/fsfwconfig.mk similarity index 100% rename from defaultcfg/config/config.mk rename to defaultcfg/fsfwconfig/fsfwconfig.mk diff --git a/defaultcfg/config/ipc/missionMessageTypes.cpp b/defaultcfg/fsfwconfig/ipc/missionMessageTypes.cpp similarity index 79% rename from defaultcfg/config/ipc/missionMessageTypes.cpp rename to defaultcfg/fsfwconfig/ipc/missionMessageTypes.cpp index e2edbf9c..b41b87ba 100644 --- a/defaultcfg/config/ipc/missionMessageTypes.cpp +++ b/defaultcfg/fsfwconfig/ipc/missionMessageTypes.cpp @@ -1,4 +1,5 @@ -#include +#include "missionMessageTypes.h" + #include void messagetypes::clearMissionMessage(CommandMessage* message) { diff --git a/defaultcfg/config/ipc/missionMessageTypes.h b/defaultcfg/fsfwconfig/ipc/missionMessageTypes.h similarity index 100% rename from defaultcfg/config/ipc/missionMessageTypes.h rename to defaultcfg/fsfwconfig/ipc/missionMessageTypes.h diff --git a/defaultcfg/config/objects/Factory.cpp b/defaultcfg/fsfwconfig/objects/Factory.cpp similarity index 75% rename from defaultcfg/config/objects/Factory.cpp rename to defaultcfg/fsfwconfig/objects/Factory.cpp index 51dd6130..41333b1c 100644 --- a/defaultcfg/config/objects/Factory.cpp +++ b/defaultcfg/fsfwconfig/objects/Factory.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -31,15 +32,15 @@ void Factory::produce(void) { setStaticFrameworkObjectIds(); new EventManager(objects::EVENT_MANAGER); new HealthTable(objects::HEALTH_TABLE); - //new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); + new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); } void Factory::setStaticFrameworkObjectIds() { - PusServiceBase::packetSource = objects::PUS_PACKET_DISTRIBUTOR; - PusServiceBase::packetDestination = objects::TM_FUNNEL; + PusServiceBase::packetSource = objects::NO_OBJECT; + PusServiceBase::packetDestination = objects::NO_OBJECT; - CommandingServiceBase::defaultPacketSource = objects::PUS_PACKET_DISTRIBUTOR; - CommandingServiceBase::defaultPacketDestination = objects::TM_FUNNEL; + CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT; + CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT; VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION; @@ -48,7 +49,6 @@ void Factory::setStaticFrameworkObjectIds() { DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; - TmPacketStored::timeStamperId = objects::PUS_TIME; - //TmFunnel::downlinkDestination = objects::NO_OBJECT; + TmPacketStored::timeStamperId = objects::NO_OBJECT; } diff --git a/defaultcfg/config/objects/Factory.h b/defaultcfg/fsfwconfig/objects/Factory.h similarity index 100% rename from defaultcfg/config/objects/Factory.h rename to defaultcfg/fsfwconfig/objects/Factory.h diff --git a/defaultcfg/config/objects/systemObjectList.h b/defaultcfg/fsfwconfig/objects/systemObjectList.h similarity index 100% rename from defaultcfg/config/objects/systemObjectList.h rename to defaultcfg/fsfwconfig/objects/systemObjectList.h diff --git a/defaultcfg/config/pollingsequence/PollingSequenceFactory.cpp b/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp similarity index 100% rename from defaultcfg/config/pollingsequence/PollingSequenceFactory.cpp rename to defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.cpp diff --git a/defaultcfg/config/pollingsequence/PollingSequenceFactory.h b/defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.h similarity index 100% rename from defaultcfg/config/pollingsequence/PollingSequenceFactory.h rename to defaultcfg/fsfwconfig/pollingsequence/PollingSequenceFactory.h diff --git a/defaultcfg/config/returnvalues/classIds.h b/defaultcfg/fsfwconfig/returnvalues/classIds.h similarity index 100% rename from defaultcfg/config/returnvalues/classIds.h rename to defaultcfg/fsfwconfig/returnvalues/classIds.h diff --git a/defaultcfg/config/tmtc/apid.h b/defaultcfg/fsfwconfig/tmtc/apid.h similarity index 100% rename from defaultcfg/config/tmtc/apid.h rename to defaultcfg/fsfwconfig/tmtc/apid.h diff --git a/defaultcfg/config/tmtc/pusIds.h b/defaultcfg/fsfwconfig/tmtc/pusIds.h similarity index 100% rename from defaultcfg/config/tmtc/pusIds.h rename to defaultcfg/fsfwconfig/tmtc/pusIds.h diff --git a/devicehandlers/AcceptsDeviceResponsesIF.h b/devicehandlers/AcceptsDeviceResponsesIF.h index 8dc69de4..8e13ba0c 100644 --- a/devicehandlers/AcceptsDeviceResponsesIF.h +++ b/devicehandlers/AcceptsDeviceResponsesIF.h @@ -1,23 +1,19 @@ -/** - * @file AcceptsDeviceResponsesIF.h - * @brief This file defines the AcceptsDeviceResponsesIF class. - * @date 15.05.2013 - * @author baetz - */ - -#ifndef ACCEPTSDEVICERESPONSESIF_H_ -#define ACCEPTSDEVICERESPONSESIF_H_ +#ifndef FSFW_DEVICEHANDLERS_ACCEPTSDEVICERESPONSESIF_H_ +#define FSFW_DEVICEHANDLERS_ACCEPTSDEVICERESPONSESIF_H_ #include "../ipc/MessageQueueSenderIF.h" +/** + * This interface is used by the device handler to send a device response + * to the queue ID, which is returned in the implemented abstract method. + */ class AcceptsDeviceResponsesIF { public: /** * Default empty virtual destructor. */ - virtual ~AcceptsDeviceResponsesIF() { -} -virtual MessageQueueId_t getDeviceQueue() = 0; + virtual ~AcceptsDeviceResponsesIF() {} + virtual MessageQueueId_t getDeviceQueue() = 0; }; -#endif /* ACCEPTSDEVICERESPONSESIF_H_ */ +#endif /* FSFW_DEVICEHANDLERS_ACCEPTSDEVICERESPONSESIF_H_ */ diff --git a/devicehandlers/AssemblyBase.cpp b/devicehandlers/AssemblyBase.cpp index 8b3f7f4d..46b2211a 100644 --- a/devicehandlers/AssemblyBase.cpp +++ b/devicehandlers/AssemblyBase.cpp @@ -2,10 +2,10 @@ AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth) : - SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth), internalState( - STATE_NONE), recoveryState(RECOVERY_IDLE), recoveringDevice( - childrenMap.end()), targetMode(MODE_OFF), targetSubmode( - SUBMODE_NONE) { + SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth), + internalState(STATE_NONE), recoveryState(RECOVERY_IDLE), + recoveringDevice(childrenMap.end()), targetMode(MODE_OFF), + targetSubmode(SUBMODE_NONE) { recoveryOffTimer.setTimeout(POWER_OFF_TIME_MS); } @@ -165,9 +165,8 @@ ReturnValue_t AssemblyBase::checkChildrenState() { } ReturnValue_t AssemblyBase::checkChildrenStateOff() { - for (std::map::iterator iter = childrenMap.begin(); - iter != childrenMap.end(); iter++) { - if (checkChildOff(iter->first) != RETURN_OK) { + for (const auto& childIter: childrenMap) { + if (checkChildOff(childIter.first) != RETURN_OK) { return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE; } } diff --git a/devicehandlers/AssemblyBase.h b/devicehandlers/AssemblyBase.h index bd2e8fad..353d5f89 100644 --- a/devicehandlers/AssemblyBase.h +++ b/devicehandlers/AssemblyBase.h @@ -1,10 +1,30 @@ -#ifndef ASSEMBLYBASE_H_ -#define ASSEMBLYBASE_H_ +#ifndef FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ +#define FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ -#include "../container/FixedArrayList.h" #include "DeviceHandlerBase.h" +#include "../container/FixedArrayList.h" #include "../subsystem/SubsystemBase.h" +/** + * @brief Base class to implement reconfiguration and failure handling for + * redundant devices by monitoring their modes health states. + * @details + * Documentation: Dissertation Baetz p.156, 157. + * + * This class reduces the complexity of controller components which would + * otherwise be needed for the handling of redundant devices. + * + * The template class monitors mode and health state of its children + * and checks availability of devices on every detected change. + * AssemblyBase does not implement any redundancy logic by itself, but provides + * adaptation points for implementations to do so. Since most monitoring + * activities rely on mode and health state only and are therefore + * generic, it is sufficient for subclasses to provide: + * + * 1. check logic when active-> checkChildrenStateOn + * 2. transition logic to change the mode -> commandChildren + * + */ class AssemblyBase: public SubsystemBase { public: static const uint8_t INTERFACE_ID = CLASS_ID::ASSEMBLY_BASE; @@ -16,10 +36,41 @@ public: static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE = MAKE_RETURN_CODE(0xa1); - AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth = 8); + AssemblyBase(object_id_t objectId, object_id_t parentId, + uint16_t commandQueueDepth = 8); virtual ~AssemblyBase(); protected: + + // SHOULDDO: Change that OVERWRITE_HEALTH may be returned + // (or return internalState directly?) + /** + * Command children to reach [mode,submode] combination + * Can be done by setting #commandsOutstanding correctly, + * or using executeTable() + * @param mode + * @param submode + * @return + * - @c RETURN_OK if ok + * - @c NEED_SECOND_STEP if children need to be commanded again + */ + virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0; + + /** + * Check whether desired assembly mode was achieved by checking the modes + * or/and health states of child device handlers. + * The assembly template class will also call this function if a health + * or mode change of a child device handler was detected. + * @param wantedMode + * @param wantedSubmode + * @return + */ + virtual ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, + Submode_t wantedSubmode) = 0; + + virtual ReturnValue_t isModeCombinationValid(Mode_t mode, + Submode_t submode) = 0; + enum InternalState { STATE_NONE, STATE_OVERWRITE_HEALTH, @@ -36,6 +87,7 @@ protected: RECOVERY_WAIT } recoveryState; //!< Indicates if one of the children requested a recovery. ChildrenMap::iterator recoveringDevice; + /** * the mode the current transition is trying to achieve. * Can be different from the modehelper.commandedMode! @@ -61,8 +113,8 @@ protected: bool handleChildrenChanged(); /** - * This method is called if the children changed its mode in a way that the current - * mode can't be kept. + * This method is called if the children changed its mode in a way that + * the current mode can't be kept. * Default behavior is to go to MODE_OFF. * @param result The failure code which was returned by checkChildrenState. */ @@ -75,9 +127,6 @@ protected: ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode); - virtual ReturnValue_t isModeCombinationValid(Mode_t mode, - Submode_t submode) = 0; - virtual void startTransition(Mode_t mode, Submode_t submode); virtual void doStartTransition(Mode_t mode, Submode_t submode); @@ -90,24 +139,6 @@ protected: void sendHealthCommand(MessageQueueId_t sendTo, HealthState health); - //SHOULDDO: Change that OVERWRITE_HEALTH may be returned (or return internalState directly?) - /** - * command children to reach mode,submode - * - * set #commandsOutstanding correctly, or use executeTable() - * - * @param mode - * @param submode - * @return - * - @c RETURN_OK if ok - * - @c NEED_SECOND_STEP if children need to be commanded again - */ - virtual ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) = 0; - - //SHOULDDO: Remove wantedMode, wantedSubmode, as targetMode/submode is available? - virtual ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, - Submode_t wantedSubmode) = 0; - virtual ReturnValue_t checkChildrenStateOff(); ReturnValue_t checkChildrenState(); @@ -125,8 +156,9 @@ protected: * Also sets state to STATE_OVERWRITE_HEATH. * @param objectId Must be a registered child. */ - void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth); + void overwriteDeviceHealth(object_id_t objectId, + HasHealthIF::HealthState oldHealth); }; -#endif /* ASSEMBLYBASE_H_ */ +#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */ diff --git a/devicehandlers/CMakeLists.txt b/devicehandlers/CMakeLists.txt new file mode 100644 index 00000000..50c1008f --- /dev/null +++ b/devicehandlers/CMakeLists.txt @@ -0,0 +1,11 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + AssemblyBase.cpp + ChildHandlerBase.cpp + ChildHandlerFDIR.cpp + DeviceHandlerBase.cpp + DeviceHandlerFailureIsolation.cpp + DeviceHandlerMessage.cpp + DeviceTmReportingWrapper.cpp + HealthDevice.cpp +) \ No newline at end of file diff --git a/devicehandlers/ChildHandlerBase.cpp b/devicehandlers/ChildHandlerBase.cpp index e800cd56..d4ef67ad 100644 --- a/devicehandlers/ChildHandlerBase.cpp +++ b/devicehandlers/ChildHandlerBase.cpp @@ -1,16 +1,18 @@ +#include "ChildHandlerBase.h" #include "../subsystem/SubsystemBase.h" -#include "../devicehandlers/ChildHandlerBase.h" #include "../subsystem/SubsystemBase.h" ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF * cookie, - uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, - object_id_t parent, FailureIsolationBase* customFdir, - size_t cmdQueueSize) : + object_id_t hkDestination, uint32_t thermalStatePoolId, + uint32_t thermalRequestPoolId, + object_id_t parent, + FailureIsolationBase* customFdir, size_t cmdQueueSize) : DeviceHandlerBase(setObjectId, deviceCommunication, cookie, (customFdir == nullptr? &childHandlerFdir : customFdir), cmdQueueSize), parentId(parent), childHandlerFdir(setObjectId) { + this->setHkDestination(hkDestination); this->setThermalStateRequestPoolIds(thermalStatePoolId, thermalRequestPoolId); diff --git a/devicehandlers/ChildHandlerBase.h b/devicehandlers/ChildHandlerBase.h index f6bf318a..eed4c95e 100644 --- a/devicehandlers/ChildHandlerBase.h +++ b/devicehandlers/ChildHandlerBase.h @@ -1,17 +1,18 @@ -#ifndef FSFW_DEVICES_CHILDHANDLERBASE_H_ -#define FSFW_DEVICES_CHILDHANDLERBASE_H_ +#ifndef FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_ +#define FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_ -#include "ChildHandlerFDIR.h" #include "DeviceHandlerBase.h" +#include "ChildHandlerFDIR.h" class ChildHandlerBase: public DeviceHandlerBase { public: ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, - CookieIF * cookie, uint32_t thermalStatePoolId, - uint32_t thermalRequestPoolId, + CookieIF * cookie, object_id_t hkDestination, + uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId, object_id_t parent = objects::NO_OBJECT, FailureIsolationBase* customFdir = nullptr, size_t cmdQueueSize = 20); + virtual ~ChildHandlerBase(); virtual ReturnValue_t initialize(); @@ -22,5 +23,4 @@ protected: }; -#endif /* FSFW_DEVICES_CHILDHANDLERBASE_H_ */ - +#endif /* FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_ */ diff --git a/devicehandlers/ChildHandlerFDIR.cpp b/devicehandlers/ChildHandlerFDIR.cpp index 14043a77..cb4c75ea 100644 --- a/devicehandlers/ChildHandlerFDIR.cpp +++ b/devicehandlers/ChildHandlerFDIR.cpp @@ -1,6 +1,7 @@ #include "ChildHandlerFDIR.h" -ChildHandlerFDIR::ChildHandlerFDIR(object_id_t owner, object_id_t faultTreeParent, uint32_t recoveryCount) : +ChildHandlerFDIR::ChildHandlerFDIR(object_id_t owner, + object_id_t faultTreeParent, uint32_t recoveryCount) : DeviceHandlerFailureIsolation(owner, faultTreeParent) { recoveryCounter.setFailureThreshold(recoveryCount); } diff --git a/devicehandlers/ChildHandlerFDIR.h b/devicehandlers/ChildHandlerFDIR.h index ce844518..13d1345c 100644 --- a/devicehandlers/ChildHandlerFDIR.h +++ b/devicehandlers/ChildHandlerFDIR.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ -#define FRAMEWORK_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ +#ifndef FSFW_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ +#define FSFW_DEVICEHANDLERS_CHILDHANDLERFDIR_H_ #include "DeviceHandlerFailureIsolation.h" diff --git a/devicehandlers/CookieIF.h b/devicehandlers/CookieIF.h index 496cf0d2..5911bfdb 100644 --- a/devicehandlers/CookieIF.h +++ b/devicehandlers/CookieIF.h @@ -1,11 +1,12 @@ -#ifndef COOKIE_H_ -#define COOKIE_H_ +#ifndef FSFW_DEVICEHANDLER_COOKIE_H_ +#define FSFW_DEVICEHANDLER_COOKIE_H_ + #include /** * @brief Physical address type */ -typedef std::uint32_t address_t; +using address_t = uint32_t; /** * @brief This datatype is used to identify different connection over a @@ -16,7 +17,6 @@ typedef std::uint32_t address_t; * calling @code{.cpp} CookieIF* childCookie = new ChildCookie(...) * @endcode . * - * [not implemented yet] * This cookie is then passed to the child device handlers, which stores the * pointer and passes it to the communication interface functions. * @@ -31,4 +31,4 @@ public: virtual ~CookieIF() {}; }; -#endif /* COOKIE_H_ */ +#endif /* FSFW_DEVICEHANDLER_COOKIE_H_ */ diff --git a/devicehandlers/DeviceCommunicationIF.h b/devicehandlers/DeviceCommunicationIF.h index 11960d8e..e0b473d3 100644 --- a/devicehandlers/DeviceCommunicationIF.h +++ b/devicehandlers/DeviceCommunicationIF.h @@ -1,9 +1,10 @@ -#ifndef DEVICECOMMUNICATIONIF_H_ -#define DEVICECOMMUNICATIONIF_H_ +#ifndef FSFW_DEVICES_DEVICECOMMUNICATIONIF_H_ +#define FSFW_DEVICES_DEVICECOMMUNICATIONIF_H_ #include "CookieIF.h" +#include "DeviceHandlerIF.h" + #include "../returnvalues/HasReturnvaluesIF.h" -#include /** * @defgroup interfaces Interfaces * @brief Interfaces for flight software objects @@ -19,8 +20,8 @@ * the device handler to allow reuse of these components. * @details * Documentation: Dissertation Baetz p.138. - * It works with the assumption that received data - * is polled by a component. There are four generic steps of device communication: + * It works with the assumption that received data is polled by a component. + * There are four generic steps of device communication: * * 1. Send data to a device * 2. Get acknowledgement for sending @@ -38,24 +39,20 @@ class DeviceCommunicationIF: public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_COMMUNICATION_IF; - //! Standard Error Codes + //! This is returned in readReceivedMessage() if no reply was reived. + static const ReturnValue_t NO_REPLY_RECEIVED = MAKE_RETURN_CODE(0x01); + //! General protocol error. Define more concrete errors in child handler - static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t PROTOCOL_ERROR = MAKE_RETURN_CODE(0x02); //! If cookie is a null pointer - static const ReturnValue_t NULLPOINTER = MAKE_RETURN_CODE(0x02); - static const ReturnValue_t INVALID_COOKIE_TYPE = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t NULLPOINTER = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t INVALID_COOKIE_TYPE = MAKE_RETURN_CODE(0x04); // is this needed if there is no open/close call? static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05); - static const ReturnValue_t INVALID_ADDRESS = MAKE_RETURN_CODE(0x06); - static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x07); - static const ReturnValue_t CANT_CHANGE_REPLY_LEN = MAKE_RETURN_CODE(0x08); - - //! Can be used in readReceivedMessage() if no reply was received. - static const ReturnValue_t NO_REPLY_RECEIVED = MAKE_RETURN_CODE(0xA1); + static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06); virtual ~DeviceCommunicationIF() {} - /** * @brief Device specific initialization, using the cookie. * @details @@ -76,13 +73,13 @@ public: * by implementing and calling related drivers or wrapper functions. * @param cookie * @param data - * @param len + * @param len If this is 0, nothing shall be sent. * @return * - @c RETURN_OK for successfull send * - Everything else triggers failure event with returnvalue as parameter 1 */ - virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, - size_t sendLen) = 0; + virtual ReturnValue_t sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) = 0; /** * Called by DHB in the GET_WRITE doGetWrite(). @@ -108,7 +105,7 @@ public: * returnvalue as parameter 1 */ virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, - size_t requestLen) = 0; + size_t requestLen) = 0; /** * Called by DHB in the GET_WRITE doGetRead(). @@ -124,8 +121,8 @@ public: * - Everything else triggers failure event with * returnvalue as parameter 1 */ - virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, - size_t *size) = 0; + virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, + uint8_t **buffer, size_t *size) = 0; }; -#endif /* DEVICECOMMUNICATIONIF_H_ */ +#endif /* FSFW_DEVICES_DEVICECOMMUNICATIONIF_H_ */ diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 710e8a83..f095834e 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -2,18 +2,20 @@ #include "AcceptsDeviceResponsesIF.h" #include "DeviceTmReportingWrapper.h" +#include "../serviceinterface/ServiceInterfaceStream.h" #include "../objectmanager/ObjectManager.h" #include "../storagemanager/StorageManagerIF.h" #include "../thermal/ThermalComponentIF.h" -#include "../datapool/DataSet.h" -#include "../datapool/PoolVariable.h" #include "../globalfunctions/CRC.h" -#include "../subsystem/SubsystemBase.h" +#include "../housekeeping/HousekeepingMessage.h" +#include "../ipc/MessageQueueMessage.h" #include "../ipc/QueueFactory.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#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; @@ -25,10 +27,11 @@ 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), childTransitionFailure(RETURN_OK), - fdirInstance(fdirInstance), hkSwitcher(this), - defaultFDIRUsed(fdirInstance == nullptr), switchOffWasReported(false), - childTransitionDelay(5000), transitionSourceMode(_MODE_POWER_DOWN), + actionHelper(this, nullptr), hkManager(this, nullptr), + childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), + hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), + switchOffWasReported(false), childTransitionDelay(5000), + transitionSourceMode(_MODE_POWER_DOWN), transitionSourceSubMode(SUBMODE_NONE) { commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE); @@ -48,10 +51,15 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, } } +void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) { + this->hkDestination = hkDestination; +} + void DeviceHandlerBase::setThermalStateRequestPoolIds( - uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId) { - this->deviceThermalRequestPoolId = thermalStatePoolId; - this->deviceThermalRequestPoolId = thermalRequestPoolId; + lp_id_t thermalStatePoolId, lp_id_t heaterRequestPoolId, + uint32_t thermalSetId) { + thermalSet = new DeviceHandlerThermalSet(this, thermalSetId, + thermalStatePoolId, heaterRequestPoolId); } @@ -65,8 +73,13 @@ DeviceHandlerBase::~DeviceHandlerBase() { ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { this->pstStep = counter; + this->lastStep = this->pstStep; - if (getComAction() == SEND_WRITE) { + if (getComAction() == CommunicationAction::NOTHING) { + return HasReturnvaluesIF::RETURN_OK; + } + + if (getComAction() == CommunicationAction::PERFORM_OPERATION) { cookieInfo.state = COOKIE_UNUSED; readCommandQueue(); doStateMachine(); @@ -75,26 +88,32 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { fdirInstance->checkForFailures(); hkSwitcher.performOperation(); performOperationHook(); + return RETURN_OK; } + if (mode == MODE_OFF) { return RETURN_OK; } + switch (getComAction()) { - case SEND_WRITE: - if ((cookieInfo.state == COOKIE_UNUSED)) { + case CommunicationAction::SEND_WRITE: + if (cookieInfo.state == COOKIE_UNUSED) { + // if no external command was specified, build internal command. buildInternalCommand(); } doSendWrite(); break; - case GET_WRITE: + case CommunicationAction::GET_WRITE: doGetWrite(); break; - case SEND_READ: + case CommunicationAction::SEND_READ: doSendRead(); break; - case GET_READ: + case CommunicationAction::GET_READ: doGetRead(); - cookieInfo.state = COOKIE_UNUSED; + // This will be performed after datasets have been updated by the + // custom device implementation. + hkManager.performHkOperation(); break; default: break; @@ -120,7 +139,9 @@ ReturnValue_t DeviceHandlerBase::initialize() { result = communicationInterface->initializeInterface(comCookie); if (result != RETURN_OK) { - return result; + sif::error << "DeviceHandlerBase::initialize: Initializing " + "communication interface failed!" << std::endl; + return result; } IPCStore = objectManager->get(objects::IPC_STORE); @@ -183,18 +204,25 @@ ReturnValue_t DeviceHandlerBase::initialize() { return result; } + result = hkManager.initialize(commandQueue); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + fillCommandAndReplyMap(); - //Set temperature target state to NON_OP. - DataSet mySet; - db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet, - PoolVariableIF::VAR_WRITE); - mySet.read(); - thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; - mySet.commit(PoolVariableIF::VALID); + if(thermalSet != nullptr) { + //Set temperature target state to NON_OP. + result = thermalSet->read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + thermalSet->heaterRequest.value = + ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; + thermalSet->commit(PoolVariableIF::VALID); + } + + } return RETURN_OK; - } void DeviceHandlerBase::decrementDeviceReplyMap() { @@ -245,10 +273,10 @@ void DeviceHandlerBase::readCommandQueue() { return; } -// result = hkManager.handleHousekeepingMessage(&command); -// if (result == RETURN_OK) { -// return; -// } + result = hkManager.handleHousekeepingMessage(&command); + if (result == RETURN_OK) { + return; + } result = handleDeviceHandlerMessage(&command); if (result == RETURN_OK) { @@ -376,24 +404,28 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, - size_t replyLen, bool periodic, bool hasDifferentReplyId, - DeviceCommandId_t replyId) { + LocalPoolDataSetBase* replyDataSet, size_t replyLen, bool periodic, + bool hasDifferentReplyId, DeviceCommandId_t replyId) { //No need to check, as we may try to insert multiple times. insertInCommandMap(deviceCommand); if (hasDifferentReplyId) { - return insertInReplyMap(replyId, maxDelayCycles, replyLen, periodic); + return insertInReplyMap(replyId, maxDelayCycles, + replyDataSet, replyLen, periodic); } else { - return insertInReplyMap(deviceCommand, maxDelayCycles, replyLen, periodic); + return insertInReplyMap(deviceCommand, maxDelayCycles, + replyDataSet, replyLen, periodic); } } ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, - uint16_t maxDelayCycles, size_t replyLen, bool periodic) { + uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet, + size_t replyLen, bool periodic) { DeviceReplyInfo info; info.maxDelayCycles = maxDelayCycles; info.periodic = periodic; info.delayCycles = 0; info.replyLen = replyLen; + info.dataSet = dataSet; info.command = deviceCommandMap.end(); auto resultPair = deviceReplyMap.emplace(replyId, info); if (resultPair.second) { @@ -419,13 +451,12 @@ ReturnValue_t DeviceHandlerBase::insertInCommandMap( ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic) { - std::map::iterator iter = - deviceReplyMap.find(deviceReply); - if (iter == deviceReplyMap.end()) { + auto replyIter = deviceReplyMap.find(deviceReply); + if (replyIter == deviceReplyMap.end()) { triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); return RETURN_FAILED; } else { - DeviceReplyInfo *info = &(iter->second); + DeviceReplyInfo *info = &(replyIter->second); if (maxDelayCycles != 0) { info->maxDelayCycles = maxDelayCycles; } @@ -435,6 +466,17 @@ ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceRep } } + +ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId, + LocalPoolDataSetBase *dataSet) { + auto replyIter = deviceReplyMap.find(replyId); + if(replyIter == deviceReplyMap.end()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + replyIter->second.dataSet = dataSet; + return HasReturnvaluesIF::RETURN_OK; +} + void DeviceHandlerBase::callChildStatemachine() { if (mode == _MODE_START_UP) { doStartUp(); @@ -468,15 +510,17 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) { } Clock::getUptime(&timeoutStart); - if (mode == MODE_OFF) { - DataSet mySet; - db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - mySet.read(); - if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { - thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; + if (mode == MODE_OFF and thermalSet != nullptr) { + ReturnValue_t result = thermalSet->read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + if (thermalSet->heaterRequest.value != + ThermalComponentIF::STATE_REQUEST_IGNORE) { + thermalSet->heaterRequest.value = ThermalComponentIF:: + STATE_REQUEST_NON_OPERATIONAL; + } + thermalSet->heaterRequest.commit(PoolVariableIF::VALID); } - mySet.commit(PoolVariableIF::VALID); + } changeHK(mode, submode, true); } @@ -649,7 +693,7 @@ void DeviceHandlerBase::doGetRead() { void DeviceHandlerBase::parseReply(const uint8_t* receivedData, size_t receivedDataLen) { ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - DeviceCommandId_t foundId = 0xFFFFFFFF; + DeviceCommandId_t foundId = DeviceHandlerIF::NO_COMMAND; size_t foundLen = 0; // The loop may not execute more often than the number of received bytes // (worst case). This approach avoids infinite loops due to buggy @@ -661,18 +705,26 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData, switch (result) { case RETURN_OK: handleReply(receivedData, foundId, foundLen); + if(foundLen == 0) { + sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" + " Packet parsing will be stuck." << std::endl; + } break; case APERIODIC_REPLY: { result = interpretDeviceReply(foundId, receivedData); if (result != RETURN_OK) { - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, - foundId); + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, + foundId); + } + if(foundLen == 0) { + sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" + " Packet parsing will be stuck." << std::endl; } - } - break; - case IGNORE_REPLY_DATA: break; + } + case IGNORE_REPLY_DATA: + continue; case IGNORE_FULL_PACKET: return; default: @@ -704,16 +756,19 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceReplyInfo *info = &(iter->second); if (info->delayCycles != 0) { + result = interpretDeviceReply(foundId, receivedData); - if (info->periodic != false) { + if(result == IGNORE_REPLY_DATA) { + return; + } + + if (info->periodic) { info->delayCycles = info->maxDelayCycles; } else { info->delayCycles = 0; } - result = interpretDeviceReply(foundId, receivedData); - if (result != RETURN_OK) { // Report failed interpretation to FDIR. replyRawReplyIfnotWiretapped(receivedData, foundLen); @@ -781,24 +836,27 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, } //Default child implementations -DeviceHandlerIF::CommunicationAction_t DeviceHandlerBase::getComAction() { +DeviceHandlerIF::CommunicationAction DeviceHandlerBase::getComAction() { switch (pstStep) { case 0: - return SEND_WRITE; + return CommunicationAction::PERFORM_OPERATION; break; case 1: - return GET_WRITE; - break; + return CommunicationAction::SEND_WRITE; + break; case 2: - return SEND_READ; + return CommunicationAction::GET_WRITE; break; case 3: - return GET_READ; + return CommunicationAction::SEND_READ; + break; + case 4: + return CommunicationAction::GET_READ; break; default: break; } - return NOTHING; + return CommunicationAction::NOTHING; } MessageQueueId_t DeviceHandlerBase::getCommandQueue() const { @@ -925,17 +983,15 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, } if ((commandedMode == MODE_ON) && (mode == MODE_OFF) - && (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) { - DataSet mySet; - db_int8_t thermalState(deviceThermalStatePoolId, &mySet, - PoolVariableIF::VAR_READ); - db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet, - PoolVariableIF::VAR_READ); - mySet.read(); - if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { - if (!ThermalComponentIF::isOperational(thermalState)) { + and (thermalSet != nullptr)) { + ReturnValue_t result = thermalSet->read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + if((thermalSet->heaterRequest.value != + ThermalComponentIF::STATE_REQUEST_IGNORE) and (not + ThermalComponentIF::isOperational( + thermalSet->thermalState.value))) { triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, - thermalState); + thermalSet->thermalState.value); return NON_OP_TEMPERATURE; } } @@ -948,32 +1004,15 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commandedSubmode) { switch (commandedMode) { case MODE_ON: - if (mode == MODE_OFF) { - transitionSourceMode = _MODE_POWER_DOWN; - transitionSourceSubMode = SUBMODE_NONE; - setMode(_MODE_POWER_ON, commandedSubmode); - //already set the delay for the child transition so we don't need to call it twice - childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, - MODE_ON); - triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); - DataSet mySet; - db_int8_t thermalRequest(deviceThermalRequestPoolId, - &mySet, PoolVariableIF::VAR_READ_WRITE); - mySet.read(); - if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { - thermalRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL; - mySet.commit(PoolVariableIF::VALID); - } - } else { - setTransition(MODE_ON, commandedSubmode); - } + handleTransitionToOnMode(commandedMode, commandedSubmode); break; case MODE_OFF: if (mode == MODE_OFF) { triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); setMode(_MODE_POWER_DOWN, commandedSubmode); } else { - //already set the delay for the child transition so we don't need to call it twice + // already set the delay for the child transition + // so we don't need to call it twice childTransitionDelay = getTransitionDelayMs(mode, _MODE_POWER_DOWN); transitionSourceMode = _MODE_POWER_DOWN; transitionSourceSubMode = commandedSubmode; @@ -999,6 +1038,33 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, } } +void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, + Submode_t commandedSubmode) { + if (mode == MODE_OFF) { + transitionSourceMode = _MODE_POWER_DOWN; + transitionSourceSubMode = SUBMODE_NONE; + setMode(_MODE_POWER_ON, commandedSubmode); + // already set the delay for the child transition so we don't + // need to call it twice + childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, + MODE_ON); + triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); + if(thermalSet != nullptr) { + ReturnValue_t result = thermalSet->read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + if(thermalSet->heaterRequest != + ThermalComponentIF::STATE_REQUEST_IGNORE) { + thermalSet->heaterRequest = + ThermalComponentIF::STATE_REQUEST_OPERATIONAL; + thermalSet->commit(); + } + } + } + } else { + setTransition(MODE_ON, commandedSubmode); + } +} + void DeviceHandlerBase::getMode(Mode_t* mode, Submode_t* submode) { *mode = this->mode; *submode = this->submode; @@ -1089,19 +1155,6 @@ ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( } replyReturnvalueToCommand(RETURN_OK); return RETURN_OK; -// case DeviceHandlerMessage::CMD_SWITCH_IOBOARD: -// if (mode != MODE_OFF) { -// replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); -// } else { -// result = switchCookieChannel( -// DeviceHandlerMessage::getIoBoardObjectId(message)); -// if (result == RETURN_OK) { -// replyReturnvalueToCommand(RETURN_OK); -// } else { -// replyReturnvalueToCommand(CANT_SWITCH_IO_ADDRESS); -// } -// } -// return RETURN_OK; case DeviceHandlerMessage::CMD_RAW: if ((mode != MODE_RAW)) { DeviceHandlerMessage::clear(message); @@ -1184,10 +1237,12 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, } } //Try to cast to GlobDataSet and commit data. - if (!neverInDataPool) { - DataSet* dataSet = dynamic_cast(data); - if (dataSet != NULL) { - dataSet->commit(PoolVariableIF::VALID); + if (not neverInDataPool) { + LocalPoolDataSetBase* dataSet = + dynamic_cast(data); + if (dataSet != nullptr) { + dataSet->setValidity(true, true); + dataSet->commit(); } } } @@ -1224,7 +1279,8 @@ void DeviceHandlerBase::buildInternalCommand(void) { if (result == BUSY) { //so we can track misconfigurations sif::debug << std::hex << getObjectId() - << ": DHB::buildInternalCommand: Busy" << std::dec << std::endl; + << ": DHB::buildInternalCommand: Busy" << std::dec + << std::endl; result = NOTHING_TO_SEND; //no need to report this } } @@ -1248,10 +1304,14 @@ 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::endl; //so we can track misconfigurations - return; //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 + << deviceCommandId << " isExecuting" << std::dec + << std::endl; + // 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; } else { iter->second.sendReplyTo = NO_COMMANDER; iter->second.isExecuting = true; @@ -1329,8 +1389,8 @@ bool DeviceHandlerBase::commandIsExecuting(DeviceCommandId_t commandId) { void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { } -void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ - executingTask = task_; +void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task){ + executingTask = task; } // Default implementations empty. @@ -1340,12 +1400,62 @@ void DeviceHandlerBase::debugInterface(uint8_t positionTracker, void DeviceHandlerBase::performOperationHook() { } +ReturnValue_t DeviceHandlerBase::initializeLocalDataPool( + LocalDataPool &localDataPoolMap, + LocalDataPoolManager& poolManager) { + if(thermalSet != nullptr) { + localDataPoolMap.emplace(thermalSet->thermalStatePoolId, + new PoolEntry); + localDataPoolMap.emplace(thermalSet->heaterRequestPoolId, + new PoolEntry); + } + 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(); + + if(setStartupImmediately) { + startTransition(MODE_ON, SUBMODE_NONE); + } return HasReturnvaluesIF::RETURN_OK; } +LocalPoolDataSetBase* DeviceHandlerBase::getDataSetHandle(sid_t sid) { + auto iter = deviceReplyMap.find(sid.ownerSetId); + if(iter != deviceReplyMap.end()) { + return iter->second.dataSet; + } + else { + return nullptr; + } +} + +object_id_t DeviceHandlerBase::getObjectId() const { + return SystemObject::getObjectId(); +} + +void DeviceHandlerBase::setStartUpImmediately() { + this->setStartupImmediately = true; +} + +dur_millis_t DeviceHandlerBase::getPeriodicOperationFrequency() const { + return pstIntervalMs; +} + +DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const { + if(cookieInfo.pendingCommand != deviceCommandMap.end()) { + return cookieInfo.pendingCommand->first; + } + return DeviceHandlerIF::NO_COMMAND; +} diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 5666f35e..9a5287e0 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -1,12 +1,12 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ -#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ +#ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ +#define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ #include "DeviceHandlerIF.h" #include "DeviceCommunicationIF.h" #include "DeviceHandlerFailureIsolation.h" +#include "DeviceHandlerThermalSet.h" #include "../objectmanager/SystemObject.h" -#include "../tasks/PeriodicTaskIF.h" #include "../tasks/ExecutableObjectIF.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../action/HasActionsIF.h" @@ -14,10 +14,13 @@ #include "../modes/HasModesIF.h" #include "../power/PowerSwitchIF.h" #include "../ipc/MessageQueueIF.h" +#include "../tasks/PeriodicTaskIF.h" #include "../action/ActionHelper.h" #include "../health/HealthHelper.h" #include "../parameters/ParameterHelper.h" #include "../datapool/HkSwitchHelper.h" +#include "../datapoollocal/HasLocalDataPoolIF.h" +#include "../datapoollocal/LocalDataPoolManager.h" #include @@ -38,17 +41,16 @@ class StorageManagerIF; * Documentation: Dissertation Baetz p.138,139, p.141-149 * * It features handling of @link DeviceHandlerIF::Mode_t Modes @endlink, - * communication with physical devices, using the @link DeviceCommunicationIF @endlink, - * and communication with commanding objects. - * It inherits SystemObject and thus can be created by the ObjectManagerIF. + * communication with physical devices, using the + * @link DeviceCommunicationIF @endlink, and communication with commanding + * objects. It inherits SystemObject and thus can be created by the + * ObjectManagerIF. * - * This class uses the opcode of ExecutableObjectIF to perform a step-wise execution. - * For each step an RMAP action is selected and executed. - * If data has been received (GET_READ), the data will be interpreted. - * The action for each step can be defined by the child class but as most - * device handlers share a 4-call (sendRead-getRead-sendWrite-getWrite) structure, - * a default implementation is provided. - * NOTE: RMAP is a standard which is used for FLP. + * This class uses the opcode of ExecutableObjectIF to perform a + * step-wise execution. For each step a different action is selected and + * executed. Currently, the device handler base performs a 4-step + * execution related to 4 communication steps (based on RMAP). + * NOTE: RMAP is a standard which is used for Flying Laptop. * RMAP communication is not mandatory for projects implementing the FSFW. * However, the communication principles are similar to RMAP as there are * two write and two send calls involved. @@ -69,9 +71,6 @@ class StorageManagerIF; * * Other important virtual methods with a default implementation * are the getTransitionDelayMs() function and the getSwitches() function. - * Please ensure that getSwitches() returns DeviceHandlerIF::NO_SWITCHES if - * power switches are not implemented yet. Otherwise, the device handler will - * not transition to MODE_ON, even if setMode(MODE_ON) is called. * If a transition to MODE_ON is desired without commanding, override the * intialize() function and call setMode(_MODE_START_UP) before calling * DeviceHandlerBase::initialize(). @@ -85,20 +84,18 @@ class DeviceHandlerBase: public DeviceHandlerIF, public HasModesIF, public HasHealthIF, public HasActionsIF, - public ReceivesParameterMessagesIF { + public ReceivesParameterMessagesIF, + public HasLocalDataPoolIF { friend void (Factory::setStaticFrameworkObjectIds)(); public: /** * The constructor passes the objectId to the SystemObject(). * * @param setObjectId the ObjectId to pass to the SystemObject() Constructor - * @param maxDeviceReplyLen the length the RMAP getRead call will be sent with - * @param setDeviceSwitch the switch the device is connected to, - * for devices using two switches, overwrite getSwitches() * @param deviceCommuncation Communcation Interface object which is used * to implement communication functions - * @param thermalStatePoolId - * @param thermalRequestPoolId + * @param comCookie This object will be passed to the communication inter- + * face and can contain user-defined information about the communication. * @param fdirInstance * @param cmdQueueSize */ @@ -106,8 +103,34 @@ public: CookieIF * comCookie, FailureIsolationBase* fdirInstance = nullptr, size_t cmdQueueSize = 20); - void setThermalStateRequestPoolIds(uint32_t thermalStatePoolId, - uint32_t thermalRequestPoolId); + void setHkDestination(object_id_t hkDestination); + + /** + * If the device handler is controlled by the FSFW thermal building blocks, + * this function should be called to initialize all required components. + * The device handler will then take care of creating local pool entries + * for the device thermal state and device heating request. + * Custom local pool IDs can be assigned as well. + * @param thermalStatePoolId + * @param thermalRequestPoolId + */ + void setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId = + DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, + lp_id_t thermalRequestPoolId = + DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID, + uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID); + /** + * @brief Helper function to ease device handler development. + * This will instruct the transition to MODE_ON immediately + * (leading to doStartUp() being called for the transition to the ON mode), + * so external mode commanding is not necessary anymore. + * + * This has to be called before the task is started! + * (e.g. in the task factory). This is only a helper function for + * development. Regular mode commanding should be performed by commanding + * the AssemblyBase or Subsystem objects resposible for the device handler. + */ + void setStartUpImmediately(); /** * @brief This function is the device handler base core component and is @@ -153,6 +176,14 @@ public: * @return */ virtual ReturnValue_t initialize(); + + /** + * @brief Intialization steps performed after all tasks have been created. + * This function will be called by the executing task. + * @return + */ + virtual ReturnValue_t initializeAfterTaskCreation() override; + /** Destructor. */ virtual ~DeviceHandlerBase(); @@ -320,6 +351,8 @@ protected: * @param packet * @return * - @c RETURN_OK when the reply was interpreted. + * - @c IGNORE_REPLY_DATA Ignore the reply and don't reset reply cycle + * counter. * - @c RETURN_FAILED when the reply could not be interpreted, * e.g. logical errors or range violations occurred */ @@ -347,22 +380,10 @@ protected: * set to the maximum expected number of PST cycles between two replies * (also a tolerance should be added, as an FDIR message will be * generated if it is missed). - * - * (Robin) This part confuses me. "must do as soon as" implies that - * the developer must do something somewhere else in the code. Is - * that really the case? If I understood correctly, DHB performs - * almost everything (e.g. in erirm function) as long as the commands - * are inserted correctly. - * - * As soon as the replies are enabled, DeviceCommandInfo.periodic must - * be set to true, DeviceCommandInfo.delayCycles to - * DeviceCommandInfo.maxDelayCycles. * From then on, the base class handles the reception. * Then, scanForReply returns the id of the reply or the placeholder id * and the base class will take care of checking that all replies are * received and the interval is correct. - * When the replies are disabled, DeviceCommandInfo.periodic must be set - * to 0, DeviceCommandInfo.delayCycles to 0; * * - Aperiodic, unrequested replies. These are replies that are sent * by the device without any preceding command and not in a defined @@ -376,13 +397,17 @@ protected: * @param deviceCommand Identifier of the command to add. * @param maxDelayCycles The maximum number of delay cycles the command * waits until it times out. + * @param replyLen Will be supplied to the requestReceiveMessage call of + * the communication interface. * @param periodic Indicates if the command is periodic (i.e. it is sent * by the device repeatedly without request) or not. Default is aperiodic (0) * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false, + uint16_t maxDelayCycles, + LocalPoolDataSetBase* replyDataSet = nullptr, + size_t replyLen = 0, bool periodic = false, bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); /** @@ -396,7 +421,8 @@ protected: * - @c RETURN_FAILED else. */ ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false); + uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet = nullptr, + size_t replyLen = 0, bool periodic = false); /** * @brief A simple command to add a command to the commandList. @@ -424,6 +450,9 @@ protected: uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic = false); + ReturnValue_t setReplyDataset(DeviceCommandId_t replyId, + LocalPoolDataSetBase* dataset); + /** * @brief Can be implemented by child handler to * perform debugging @@ -477,18 +506,22 @@ protected: * @param localDataPoolMap * @return */ - //virtual ReturnValue_t initializePoolEntries( - // LocalDataPool& localDataPoolMap) override; + virtual ReturnValue_t initializeLocalDataPool(LocalDataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; /** Get the HK manager object handle */ - //virtual LocalDataPoolManager* getHkManagerHandle() override; + virtual LocalDataPoolManager* getHkManagerHandle() override; /** * @brief Hook function for child handlers which is called once per * performOperation(). Default implementation is empty. */ virtual void performOperationHook(); + public: + /** Explicit interface implementation of getObjectId */ + virtual object_id_t getObjectId() const override; + /** * @param parentQueueId */ @@ -558,6 +591,7 @@ protected: /** This is the counter value from performOperation(). */ uint8_t pstStep = 0; + uint8_t lastStep = 0; uint32_t pstIntervalMs = 0; /** @@ -608,7 +642,7 @@ protected: /** Action helper for HasActionsIF */ ActionHelper actionHelper; /** Housekeeping Manager */ - //LocalDataPoolManager hkManager; + LocalDataPoolManager hkManager; /** * @brief Information about commands @@ -647,7 +681,7 @@ protected: //! The dataset used to access housekeeping data related to the //! respective device reply. Will point to a dataset held by //! the child handler (if one is specified) - // DataSetIF* dataSet = nullptr; + LocalPoolDataSetBase* dataSet; //! The command that expects this reply. DeviceCommandMap::iterator command; }; @@ -674,29 +708,21 @@ protected: //! and to send replies. MessageQueueIF* commandQueue = nullptr; - /** - * this is the datapool variable with the thermal state of the device - * - * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking - */ - uint32_t deviceThermalStatePoolId = PoolVariableIF::NO_PARAMETER; + DeviceHandlerThermalSet* thermalSet = nullptr; /** - * this is the datapool variable with the thermal request of the device - * - * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking - */ - uint32_t deviceThermalRequestPoolId = PoolVariableIF::NO_PARAMETER; - - /** - * Optional Error code - * Can be set in doStartUp(), doShutDown() and doTransition() to signal cause for Transition failure. + * Optional Error code. Can be set in doStartUp(), doShutDown() and + * doTransition() to signal cause for Transition failure. */ ReturnValue_t childTransitionFailure; - uint32_t ignoreMissedRepliesCount = 0; //!< Counts if communication channel lost a reply, so some missed replys can be ignored. + /** Counts if communication channel lost a reply, so some missed + * replys can be ignored. */ + uint32_t ignoreMissedRepliesCount = 0; - FailureIsolationBase* fdirInstance; //!< Pointer to the used FDIR instance. If not provided by child, default class is instantiated. + /** Pointer to the used FDIR instance. If not provided by child, + * default class is instantiated. */ + FailureIsolationBase* fdirInstance; HkSwitchHelper hkSwitcher; @@ -708,15 +734,28 @@ protected: //! before setTaskIF was called. PeriodicTaskIF* executingTask = nullptr; - static object_id_t powerSwitcherId; //!< Object which switches power on and off. + //!< Object which switches power on and off. + static object_id_t powerSwitcherId; - static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default. + //!< Object which receives RAW data by default. + static object_id_t rawDataReceiverId; + + //!< Object which may be the root cause of an identified fault. + static object_id_t defaultFdirParentId; + + /** + * Helper function to get pending command. This is useful for devices + * like SPI sensors to identify the last sent command. + * This only returns the command sent in the last SEND_WRITE cycle. + * @return + */ + DeviceCommandId_t getPendingCommand() const; - static object_id_t defaultFdirParentId; //!< Object which may be the root cause of an identified fault. /** * Helper function to report a missed reply * - * Can be overwritten by children to act on missed replies or to fake reporting Id. + * Can be overwritten by children to act on missed replies or to fake + * reporting Id. * * @param id of the missed reply */ @@ -818,20 +857,23 @@ protected: * @return The Rmap action to execute in this step */ - virtual CommunicationAction_t getComAction(); + virtual CommunicationAction getComAction(); /** * Build the device command to send for raw mode. * - * This is only called in @c MODE_RAW. It is for the rare case that in raw mode packets - * are to be sent by the handler itself. It is NOT needed for the raw commanding service. - * Its only current use is in the STR handler which gets its raw packets from a different - * source. - * Also it can be used for transitional commands, to get the device ready for @c MODE_RAW + * This is only called in @c MODE_RAW. It is for the rare case that in + * raw mode packets are to be sent by the handler itself. It is NOT needed + * for the raw commanding service. Its only current use is in the STR + * handler which gets its raw packets from a different source. + * Also it can be used for transitional commands, to get the device ready + * for @c MODE_RAW * - * As it is almost never used, there is a default implementation returning @c NOTHING_TO_SEND. + * As it is almost never used, there is a default implementation + * returning @c NOTHING_TO_SEND. * - * #rawPacket and #rawPacketLen must be set by this method to the packet to be sent. + * #rawPacket and #rawPacketLen must be set by this method to the packet + * to be sent. * * @param[out] id the device command id built * @return @@ -844,7 +886,9 @@ protected: * Returns the delay cycle count of a reply. * A count != 0 indicates that the command is already executed. * @param deviceCommand The command to look for - * @return The current delay count. If the command does not exist (should never happen) it returns 0. + * @return + * The current delay count. If the command does not exist (should never + * happen) it returns 0. */ uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand); @@ -854,20 +898,22 @@ protected: * It gets space in the #IPCStore, copies data there, then sends a raw reply * containing the store address. * - * This method is virtual, as the STR has a different channel to send raw replies - * and overwrites it accordingly. + * This method is virtual, as the STR has a different channel to send + * raw replies and overwrites it accordingly. * * @param data data to send * @param len length of @c data * @param sendTo the messageQueueId of the one to send to - * @param isCommand marks the raw data as a command, the message then will be of type raw_command + * @param isCommand marks the raw data as a command, the message then + * will be of type raw_command */ virtual void replyRawData(const uint8_t *data, size_t len, MessageQueueId_t sendTo, bool isCommand = false); /** - * Calls replyRawData() with #defaultRawReceiver, but checks if wiretapping is active and if so, - * does not send the Data as the wiretapping will have sent it already + * Calls replyRawData() with #defaultRawReceiver, but checks if wiretapping + * is active and if so, does not send the data as the wiretapping will have + * sent it already */ void replyRawReplyIfnotWiretapped(const uint8_t *data, size_t len); @@ -879,17 +925,19 @@ protected: /** * Enable the reply checking for a command * - * Is only called, if the command was sent (ie the getWriteReply was successful). - * Must ensure that all replies are activated and correctly linked to the command that initiated it. - * The default implementation looks for a reply with the same id as the command id in the replyMap or - * uses the alternativeReplyId if flagged so. - * When found, copies maxDelayCycles to delayCycles in the reply information and sets the command to - * expect one reply. + * Is only called, if the command was sent (i.e. the getWriteReply was + * successful). Must ensure that all replies are activated and correctly + * linked to the command that initiated it. + * The default implementation looks for a reply with the same id as the + * command id in the replyMap or uses the alternativeReplyId if flagged so. + * When found, copies maxDelayCycles to delayCycles in the reply information + * and sets the command to expect one reply. * * Can be overwritten by the child, if a command activates multiple replies * or replyId differs from commandId. * Notes for child implementations: - * - If the command was not found in the reply map, NO_REPLY_EXPECTED MUST be returned. + * - If the command was not found in the reply map, + * NO_REPLY_EXPECTED MUST be returned. * - A failure code may be returned if something went fundamentally wrong. * * @param deviceCommand @@ -905,17 +953,20 @@ protected: * get the state of the PCDU switches in the datapool * * @return - * - @c PowerSwitchIF::SWITCH_ON if all switches specified by #switches are on - * - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by #switches are off - * - @c PowerSwitchIF::RETURN_FAILED if an error occured + * - @c PowerSwitchIF::SWITCH_ON if all switches specified + * by #switches are on + * - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by + * #switches are off + * - @c PowerSwitchIF::RETURN_FAILED if an error occured */ ReturnValue_t getStateOfSwitches(void); /** - * set all datapool variables that are update periodically in normal mode invalid - * - * Child classes should provide an implementation which sets all those variables invalid - * which are set periodically during any normal mode. + * @brief Set all datapool variables that are update periodically in + * normal mode invalid + * @details TODO: Use local pools + * Child classes should provide an implementation which sets all those + * variables invalid which are set periodically during any normal mode. */ virtual void setNormalDatapoolEntriesInvalid() = 0; @@ -925,11 +976,12 @@ protected: virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); /** - * Children can overwrite this function to suppress checking of the command Queue + * Children can overwrite this function to suppress checking of the + * command Queue * - * This can be used when the child does not want to receive a command in a certain - * situation. Care must be taken that checking is not permanentely disabled as this - * would render the handler unusable. + * This can be used when the child does not want to receive a command in + * a certain situation. Care must be taken that checking is not + * permanentely disabled as this would render the handler unusable. * * @return whether checking the queue should NOT be done */ @@ -944,14 +996,17 @@ protected: virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode); - virtual void startTransition(Mode_t mode, Submode_t submode); - virtual void setToExternalControl(); - virtual void announceMode(bool recursive); + + /* HasModesIF overrides */ + virtual void startTransition(Mode_t mode, Submode_t submode) override; + virtual void setToExternalControl() override; + virtual void announceMode(bool recursive) override; virtual ReturnValue_t letChildHandleMessage(CommandMessage *message); /** - * Overwrites SystemObject::triggerEvent in order to inform FDIR"Helper" faster about executed events. + * Overwrites SystemObject::triggerEvent in order to inform FDIR"Helper" + * faster about executed events. * This is a bit sneaky, but improves responsiveness of the device FDIR. * @param event The event to be thrown * @param parameter1 Optional parameter 1 @@ -965,17 +1020,20 @@ protected: virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const; /** - * Checks state of switches in conjunction with mode and triggers an event if they don't fit. + * Checks state of switches in conjunction with mode and triggers an event + * if they don't fit. */ virtual void checkSwitchState(); /** - * Reserved for the rare case where a device needs to perform additional operation cyclically in OFF mode. + * Reserved for the rare case where a device needs to perform additional + * operation cyclically in OFF mode. */ virtual void doOffActivity(); /** - * Reserved for the rare case where a device needs to perform additional operation cyclically in ON mode. + * Reserved for the rare case where a device needs to perform additional + * operation cyclically in ON mode. */ virtual void doOnActivity(); @@ -1016,9 +1074,10 @@ private: /** * Information about a cookie. * - * This is stored in a map for each cookie, to not only track the state, but also information - * about the sent command. Tracking this information is needed as - * the state of a commandId (waiting for reply) is done when a RMAP write reply is received. + * This is stored in a map for each cookie, to not only track the state, + * but also information about the sent command. Tracking this information + * is needed as the state of a commandId (waiting for reply) is done when a + * write reply is received. */ struct CookieInfo { CookieState_t state; @@ -1034,12 +1093,17 @@ private: /** the object used to set power switches */ PowerSwitchIF *powerSwitcher = nullptr; + /** HK destination can also be set individually */ + object_id_t hkDestination = objects::NO_OBJECT; + /** * @brief Used for timing out mode transitions. * Set when setMode() is called. */ uint32_t timeoutStart = 0; + bool setStartupImmediately = false; + /** * Delay for the current mode transition, used for time out */ @@ -1070,34 +1134,34 @@ private: /** * Handle the device handler mode. * - * - checks whether commands are valid for the current mode, rejects them accordingly - * - checks whether commanded mode transitions are required and calls handleCommandedModeTransition() - * - does the necessary action for the current mode or calls doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF - * - actions that happen in transitions (eg setting a timeout) are handled in setMode() + * - checks whether commands are valid for the current mode, rejects + * them accordingly + * - checks whether commanded mode transitions are required and calls + * handleCommandedModeTransition() + * - does the necessary action for the current mode or calls + * doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF + * - actions that happen in transitions (e.g. setting a timeout) are + * handled in setMode() */ void doStateMachine(void); void buildRawDeviceCommand(CommandMessage* message); void buildInternalCommand(void); -// /** -// * Send a reply with the current mode and submode. -// */ -// void announceMode(void); - /** * Decrement the counter for the timout of replies. * - * This is called at the beginning of each cycle. It checks whether a reply has timed out (that means a reply was expected - * but not received). + * This is called at the beginning of each cycle. It checks whether a + * reply has timed out (that means a reply was expected but not received). */ void decrementDeviceReplyMap(void); /** * Convenience function to handle a reply. * - * Called after scanForReply() has found a packet. Checks if the found id is in the #deviceCommandMap, if so, - * calls interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) for further action. + * Called after scanForReply() has found a packet. Checks if the found ID + * is in the #deviceCommandMap, if so, calls + * #interpretDeviceReply for further action. * * It also resets the timeout counter for the command id. * @@ -1111,10 +1175,14 @@ private: /** * Build and send a command to the device. * - * This routine checks whether a raw or direct command has been received, checks the content of the received command and - * calls buildCommandFromCommand() for direct commands or sets #rawpacket to the received raw packet. - * If no external command is received or the received command is invalid and the current mode is @c MODE_NORMAL or a transitional mode, - * it asks the child class to build a command (via getNormalDeviceCommand() or getTransitionalDeviceCommand() and buildCommand()) and + * This routine checks whether a raw or direct command has been received, + * checks the content of the received command and calls + * buildCommandFromCommand() for direct commands or sets #rawpacket + * to the received raw packet. + * If no external command is received or the received command is invalid and + * the current mode is @c MODE_NORMAL or a transitional mode, it asks the + * child class to build a command (via getNormalDeviceCommand() or + * getTransitionalDeviceCommand() and buildCommand()) and * sends the command via RMAP. */ void doSendWrite(void); @@ -1153,13 +1221,12 @@ private: * @param[out] len * @return * - @c RETURN_OK @c data is valid - * - @c RETURN_FAILED IPCStore is NULL + * - @c RETURN_FAILED IPCStore is nullptr * - the return value from the IPCStore if it was not @c RETURN_OK */ ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, uint32_t *len); - /** * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW NOTHING ELSE!!! */ @@ -1170,25 +1237,17 @@ private: */ void callChildStatemachine(); - /** - * Switches the channel of the cookie used for the communication - * - * - * @param newChannel the object Id of the channel to switch to - * @return - * - @c RETURN_OK when cookie was changed - * - @c RETURN_FAILED when cookies could not be changed, eg because the newChannel is not enabled - * - @c returnvalues of RMAPChannelIF::isActive() - */ - ReturnValue_t switchCookieChannel(object_id_t newChannelId); - ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); - virtual ReturnValue_t initializeAfterTaskCreation() override; + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; - void parseReply(const uint8_t* receivedData, - size_t receivedDataLen); + virtual dur_millis_t getPeriodicOperationFrequency() const override; + + void parseReply(const uint8_t* receivedData, + size_t receivedDataLen); + + void handleTransitionToOnMode(Mode_t commandedMode, + Submode_t commandedSubmode); }; -#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */ - +#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */ diff --git a/devicehandlers/DeviceHandlerFailureIsolation.cpp b/devicehandlers/DeviceHandlerFailureIsolation.cpp index 9fbe71d8..9d0535bf 100644 --- a/devicehandlers/DeviceHandlerFailureIsolation.cpp +++ b/devicehandlers/DeviceHandlerFailureIsolation.cpp @@ -191,7 +191,7 @@ void DeviceHandlerFailureIsolation::triggerEvent(Event event, uint32_t parameter uint32_t parameter2) { //Do not throw error events if fdirState != none. //This will still forward MODE and HEALTH INFO events in any case. - if (fdirState == NONE || EVENT::getSeverity(event) == SEVERITY::INFO) { + if (fdirState == NONE || event::getSeverity(event) == severity::INFO) { FailureIsolationBase::triggerEvent(event, parameter1, parameter2); } } @@ -201,7 +201,7 @@ bool DeviceHandlerFailureIsolation::isFdirActionInProgress() { } void DeviceHandlerFailureIsolation::startRecovery(Event reason) { - throwFdirEvent(FDIR_STARTS_RECOVERY, EVENT::getEventId(reason)); + throwFdirEvent(FDIR_STARTS_RECOVERY, event::getEventId(reason)); setOwnerHealth(HasHealthIF::NEEDS_RECOVERY); setFdirState(RECOVERY_ONGOING); } @@ -228,7 +228,7 @@ ReturnValue_t DeviceHandlerFailureIsolation::getParameter(uint8_t domainId, } void DeviceHandlerFailureIsolation::setFaulty(Event reason) { - throwFdirEvent(FDIR_TURNS_OFF_DEVICE, EVENT::getEventId(reason)); + throwFdirEvent(FDIR_TURNS_OFF_DEVICE, event::getEventId(reason)); setOwnerHealth(HasHealthIF::FAULTY); setFdirState(AWAIT_SHUTDOWN); } @@ -247,6 +247,14 @@ bool DeviceHandlerFailureIsolation::isFdirInActionOrAreWeFaulty( } return true; } + + if (owner == nullptr) { + // Configuration error. + sif::error << "DeviceHandlerFailureIsolation::" + << "isFdirInActionOrAreWeFaulty: Owner not set!" << std::endl; + return false; + } + if (owner->getHealth() == HasHealthIF::FAULTY || owner->getHealth() == HasHealthIF::PERMANENT_FAULTY) { //Ignore all events in case device is already faulty. diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 10c9b89a..491a2c08 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -1,12 +1,19 @@ -#ifndef DEVICEHANDLERIF_H_ -#define DEVICEHANDLERIF_H_ +#ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ +#define FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ + +#include "DeviceHandlerMessage.h" #include "../action/HasActionsIF.h" -#include "DeviceHandlerMessage.h" #include "../events/Event.h" #include "../modes/HasModesIF.h" #include "../ipc/MessageQueueSenderIF.h" +/** + * This is used to uniquely identify commands that are sent to a device + * The values are defined in the device-specific implementations + */ +using DeviceCommandId_t = uint32_t; + /** * @brief This is the Interface used to communicate with a device handler. * @details Includes all expected return values, events and modes. @@ -15,10 +22,11 @@ class DeviceHandlerIF { public: + static const uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20; static const uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10; - static constexpr DeviceCommandId_t NO_COMMAND = 0xffffffff; + static constexpr Command_t NO_COMMAND = -1; /** * @brief This is the mode the device handler is in. @@ -49,6 +57,8 @@ public: //! This is a transitional state which can not be commanded. //! The device handler performs all actions and commands to get the device //! shut down. When the device is off, the mode changes to @c MODE_OFF. + //! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off + //! transition if available. static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6; //! It is possible to set the mode to _MODE_TO_ON to use the to on //! transition if available. @@ -83,22 +93,22 @@ public: static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH; - static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, SEVERITY::LOW); - static const Event DEVICE_SENDING_COMMAND_FAILED = MAKE_EVENT(1, SEVERITY::LOW); - static const Event DEVICE_REQUESTING_REPLY_FAILED = MAKE_EVENT(2, SEVERITY::LOW); - static const Event DEVICE_READING_REPLY_FAILED = MAKE_EVENT(3, SEVERITY::LOW); - static const Event DEVICE_INTERPRETING_REPLY_FAILED = MAKE_EVENT(4, SEVERITY::LOW); - static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, SEVERITY::LOW); - static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, SEVERITY::LOW); - static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, SEVERITY::LOW); - static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, SEVERITY::LOW); //!< Indicates a SW bug in child class. - static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, SEVERITY::LOW); - static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, SEVERITY::HIGH); + static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, severity::LOW); + static const Event DEVICE_SENDING_COMMAND_FAILED = MAKE_EVENT(1, severity::LOW); + static const Event DEVICE_REQUESTING_REPLY_FAILED = MAKE_EVENT(2, severity::LOW); + static const Event DEVICE_READING_REPLY_FAILED = MAKE_EVENT(3, severity::LOW); + static const Event DEVICE_INTERPRETING_REPLY_FAILED = MAKE_EVENT(4, severity::LOW); + static const Event DEVICE_MISSED_REPLY = MAKE_EVENT(5, severity::LOW); + static const Event DEVICE_UNKNOWN_REPLY = MAKE_EVENT(6, severity::LOW); + static const Event DEVICE_UNREQUESTED_REPLY = MAKE_EVENT(7, severity::LOW); + static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW); //!< Indicates a SW bug in child class. + static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW); + static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH); static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF; // Standard codes used when building commands. - static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA0); //!< If the command size is 0. Checked in DHB + static const ReturnValue_t NO_COMMAND_DATA = MAKE_RETURN_CODE(0xA0); //!< If no command data was given when expected. static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA1); //!< Command ID not in commandMap. Checked in DHB static const ReturnValue_t COMMAND_ALREADY_SENT = MAKE_RETURN_CODE(0xA2); //!< Command was already executed. Checked in DHB static const ReturnValue_t COMMAND_WAS_NOT_SENT = MAKE_RETURN_CODE(0xA3); @@ -131,7 +141,8 @@ public: * * This is used by the child class to tell the base class what to do. */ - enum CommunicationAction_t: uint8_t { + enum CommunicationAction: uint8_t { + PERFORM_OPERATION, SEND_WRITE,//!< Send write GET_WRITE, //!< Get write SEND_READ, //!< Send read @@ -152,4 +163,4 @@ public: }; -#endif /* DEVICEHANDLERIF_H_ */ +#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */ diff --git a/devicehandlers/DeviceHandlerMessage.cpp b/devicehandlers/DeviceHandlerMessage.cpp index 564fae21..cb9043db 100644 --- a/devicehandlers/DeviceHandlerMessage.cpp +++ b/devicehandlers/DeviceHandlerMessage.cpp @@ -1,10 +1,6 @@ -#include "../objectmanager/ObjectManagerIF.h" #include "DeviceHandlerMessage.h" #include "../objectmanager/ObjectManagerIF.h" -DeviceHandlerMessage::DeviceHandlerMessage() { -} - store_address_t DeviceHandlerMessage::getStoreAddress( const CommandMessage* message) { return store_address_t(message->getParameter2()); @@ -25,14 +21,6 @@ uint8_t DeviceHandlerMessage::getWiretappingMode( return message->getParameter(); } -//void DeviceHandlerMessage::setDeviceHandlerDirectCommandMessage( -// CommandMessage* message, DeviceCommandId_t deviceCommand, -// store_address_t commandParametersStoreId) { -// message->setCommand(CMD_DIRECT); -// message->setParameter(deviceCommand); -// message->setParameter2(commandParametersStoreId.raw); -//} - void DeviceHandlerMessage::setDeviceHandlerRawCommandMessage( CommandMessage* message, store_address_t rawPacketStoreId) { message->setCommand(CMD_RAW); @@ -47,7 +35,7 @@ void DeviceHandlerMessage::setDeviceHandlerWiretappingMessage( void DeviceHandlerMessage::setDeviceHandlerSwitchIoBoardMessage( CommandMessage* message, uint32_t ioBoardIdentifier) { - message->setCommand(CMD_SWITCH_IOBOARD); + message->setCommand(CMD_SWITCH_ADDRESS); message->setParameter(ioBoardIdentifier); } @@ -79,18 +67,17 @@ void DeviceHandlerMessage::setDeviceHandlerDirectCommandReply( void DeviceHandlerMessage::clear(CommandMessage* message) { switch (message->getCommand()) { case CMD_RAW: -// case CMD_DIRECT: case REPLY_RAW_COMMAND: case REPLY_RAW_REPLY: case REPLY_DIRECT_COMMAND_DATA: { StorageManagerIF *ipcStore = objectManager->get( objects::IPC_STORE); - if (ipcStore != NULL) { + if (ipcStore != nullptr) { ipcStore->deleteData(getStoreAddress(message)); } } /* NO BREAK falls through*/ - case CMD_SWITCH_IOBOARD: + case CMD_SWITCH_ADDRESS: case CMD_WIRETAPPING: message->setCommand(CommandMessage::CMD_NONE); message->setParameter(0); diff --git a/devicehandlers/DeviceHandlerMessage.h b/devicehandlers/DeviceHandlerMessage.h index 8d1c94f4..e5da01c8 100644 --- a/devicehandlers/DeviceHandlerMessage.h +++ b/devicehandlers/DeviceHandlerMessage.h @@ -1,69 +1,56 @@ -#ifndef DEVICEHANDLERMESSAGE_H_ -#define DEVICEHANDLERMESSAGE_H_ +#ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERMESSAGE_H_ +#define FSFW_DEVICEHANDLERS_DEVICEHANDLERMESSAGE_H_ #include "../action/ActionMessage.h" #include "../ipc/CommandMessage.h" #include "../objectmanager/SystemObjectIF.h" #include "../storagemanager/StorageManagerIF.h" -//SHOULDDO: rework the static constructors to name the type of command they are building, maybe even hide setting the commandID. +// SHOULDDO: rework the static constructors to name the type of command +// they are building, maybe even hide setting the commandID. + /** - * This is used to uniquely identify commands that are sent to a device - * - * The values are defined in the device-specific implementations - */ -typedef uint32_t DeviceCommandId_t; - -/** - * The DeviceHandlerMessage is used to send Commands to a DeviceHandlerIF + * @brief The DeviceHandlerMessage is used to send commands to classes + * implementing DeviceHandlerIF */ class DeviceHandlerMessage { -private: - DeviceHandlerMessage(); public: + /** + * Instantiation forbidden. Instead, use static functions to operate + * on messages. + */ + DeviceHandlerMessage() = delete; + virtual ~DeviceHandlerMessage() {} /** * These are the commands that can be sent to a DeviceHandlerBase */ static const uint8_t MESSAGE_ID = messagetypes::DEVICE_HANDLER_COMMAND; - static const Command_t CMD_RAW = MAKE_COMMAND_ID( 1 ); //!< Sends a raw command, setParameter is a ::store_id_t containing the raw packet to send -// static const Command_t CMD_DIRECT = MAKE_COMMAND_ID( 2 ); //!< Sends a direct command, setParameter is a ::DeviceCommandId_t, setParameter2 is a ::store_id_t containing the data needed for the command - static const Command_t CMD_SWITCH_IOBOARD = MAKE_COMMAND_ID( 3 ); //!< Requests a IO-Board switch, setParameter() is the IO-Board identifier - static const Command_t CMD_WIRETAPPING = MAKE_COMMAND_ID( 4 ); //!< (De)Activates the monitoring of all raw traffic in DeviceHandlers, setParameter is 0 to deactivate, 1 to activate + //! Sends a raw command, setParameter is a storeId containing the + //! raw packet to send + static const Command_t CMD_RAW = MAKE_COMMAND_ID(1); + //! Requests a IO-Board switch, setParameter() is the IO-Board identifier + static const Command_t CMD_SWITCH_ADDRESS = MAKE_COMMAND_ID(3); + //! (De)Activates the monitoring of all raw traffic in DeviceHandlers, + //! setParameter is 0 to deactivate, 1 to activate + static const Command_t CMD_WIRETAPPING = MAKE_COMMAND_ID(4); - /*static const Command_t REPLY_SWITCHED_IOBOARD = MAKE_COMMAND_ID(1 );//!< Reply to a @c CMD_SWITCH_IOBOARD, indicates switch was successful, getParameter() contains the board switched to (0: nominal, 1: redundant) - static const Command_t REPLY_CANT_SWITCH_IOBOARD = MAKE_COMMAND_ID( 2); //!< Reply to a @c CMD_SWITCH_IOBOARD, indicating the switch could not be performed, getParameter() contains the error message - static const Command_t REPLY_WIRETAPPING = MAKE_COMMAND_ID( 3); //!< Reply to a @c CMD_WIRETAPPING, getParameter() is the current state, 1 enabled, 0 disabled - - static const Command_t REPLY_COMMAND_WAS_SENT = MAKE_COMMAND_ID(4 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates the command was successfully sent to the device, getParameter() contains the ::DeviceCommandId_t - static const Command_t REPLY_COMMAND_NOT_SUPPORTED = MAKE_COMMAND_ID(5 );//!< Reply to a @c CMD_DIRECT, the requested ::DeviceCommand_t is not supported, getParameter() contains the requested ::DeviceCommand_t, getParameter2() contains the ::DeviceCommandId_t - static const Command_t REPLY_COMMAND_WAS_NOT_SENT = MAKE_COMMAND_ID(6 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates the command was not sent, getParameter contains the RMAP Return code (@see rmap.h), getParameter2() contains the ::DeviceCommandId_t - - static const Command_t REPLY_COMMAND_ALREADY_SENT = MAKE_COMMAND_ID(7 );//!< Reply to a @c CMD_DIRECT, the requested ::DeviceCommand_t has already been sent to the device and not ye been answered - static const Command_t REPLY_WRONG_MODE_FOR_CMD = MAKE_COMMAND_ID(8 );//!< Reply to a @c CMD_RAW or @c CMD_DIRECT, indicates that the requested command can not be sent in the curent mode, getParameter() contains the DeviceHandlerCommand_t - static const Command_t REPLY_NO_DATA = MAKE_COMMAND_ID(9 ); //!< Reply to a CMD_RAW or @c CMD_DIRECT, indicates that the ::store_id_t was invalid, getParameter() contains the ::DeviceCommandId_t, getPrameter2() contains the error code - */ - static const Command_t REPLY_DIRECT_COMMAND_SENT = ActionMessage::STEP_SUCCESS; //!< Signals that a direct command was sent - static const Command_t REPLY_RAW_COMMAND = MAKE_COMMAND_ID(0x11 ); //!< Contains a raw command sent to the Device - static const Command_t REPLY_RAW_REPLY = MAKE_COMMAND_ID( 0x12); //!< Contains a raw reply from the Device, getParameter() is the ObjcetId of the sender, getParameter2() is a ::store_id_t containing the raw packet received + //! Signals that a direct command was sent + static const Command_t REPLY_DIRECT_COMMAND_SENT = ActionMessage::STEP_SUCCESS; + //! Contains a raw command sent to the Device + static const Command_t REPLY_RAW_COMMAND = MAKE_COMMAND_ID(0x11); + //! Contains a raw reply from the Device, getParameter() is the ObjcetId + //! of the sender, getParameter2() is a ::store_id_t containing the + //! raw packet received + static const Command_t REPLY_RAW_REPLY = MAKE_COMMAND_ID(0x12); static const Command_t REPLY_DIRECT_COMMAND_DATA = ActionMessage::DATA_REPLY; - /** - * Default Destructor - */ - virtual ~DeviceHandlerMessage() { - } - static store_address_t getStoreAddress(const CommandMessage* message); static uint32_t getDeviceCommandId(const CommandMessage* message); static object_id_t getDeviceObjectId(const CommandMessage *message); static object_id_t getIoBoardObjectId(const CommandMessage* message); static uint8_t getWiretappingMode(const CommandMessage* message); -// static void setDeviceHandlerDirectCommandMessage(CommandMessage* message, -// DeviceCommandId_t deviceCommand, -// store_address_t commandParametersStoreId); - static void setDeviceHandlerDirectCommandReply(CommandMessage* message, object_id_t deviceObjectid, store_address_t commandParametersStoreId); @@ -75,11 +62,6 @@ public: object_id_t deviceObjectid, store_address_t rawPacketStoreId, bool isCommand); -// static void setDeviceHandlerMessage(CommandMessage* message, -// Command_t command, DeviceCommandId_t deviceCommand, -// store_address_t commandParametersStoreId); -// static void setDeviceHandlerMessage(CommandMessage* message, -// Command_t command, store_address_t rawPacketStoreId); static void setDeviceHandlerWiretappingMessage(CommandMessage* message, uint8_t wiretappingMode); static void setDeviceHandlerSwitchIoBoardMessage(CommandMessage* message, @@ -88,4 +70,4 @@ public: static void clear(CommandMessage* message); }; -#endif /* DEVICEHANDLERMESSAGE_H_ */ +#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERMESSAGE_H_ */ diff --git a/devicehandlers/DeviceTmReportingWrapper.cpp b/devicehandlers/DeviceTmReportingWrapper.cpp index 84f926f0..c70f57d6 100644 --- a/devicehandlers/DeviceTmReportingWrapper.cpp +++ b/devicehandlers/DeviceTmReportingWrapper.cpp @@ -1,4 +1,3 @@ -#include "../serialize/SerializeAdapter.h" #include "DeviceTmReportingWrapper.h" #include "../serialize/SerializeAdapter.h" diff --git a/devicehandlers/DeviceTmReportingWrapper.h b/devicehandlers/DeviceTmReportingWrapper.h index a14c4261..447e95f2 100644 --- a/devicehandlers/DeviceTmReportingWrapper.h +++ b/devicehandlers/DeviceTmReportingWrapper.h @@ -1,5 +1,5 @@ -#ifndef DEVICETMREPORTINGWRAPPER_H_ -#define DEVICETMREPORTINGWRAPPER_H_ +#ifndef FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_ +#define FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_ #include "../action/HasActionsIF.h" #include "../objectmanager/SystemObjectIF.h" @@ -24,4 +24,4 @@ private: SerializeIF *data; }; -#endif /* DEVICETMREPORTINGWRAPPER_H_ */ +#endif /* FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_ */ diff --git a/devicehandlers/HealthDevice.cpp b/devicehandlers/HealthDevice.cpp index b15e5d2b..418ed257 100644 --- a/devicehandlers/HealthDevice.cpp +++ b/devicehandlers/HealthDevice.cpp @@ -13,10 +13,10 @@ HealthDevice::~HealthDevice() { } ReturnValue_t HealthDevice::performOperation(uint8_t opCode) { - CommandMessage message; - ReturnValue_t result = commandQueue->receiveMessage(&message); + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); if (result == HasReturnvaluesIF::RETURN_OK) { - healthHelper.handleHealthCommand(&message); + healthHelper.handleHealthCommand(&command); } return HasReturnvaluesIF::RETURN_OK; } diff --git a/devicehandlers/HealthDevice.h b/devicehandlers/HealthDevice.h index 53b0ab09..738f0c7e 100644 --- a/devicehandlers/HealthDevice.h +++ b/devicehandlers/HealthDevice.h @@ -1,5 +1,5 @@ -#ifndef HEALTHDEVICE_H_ -#define HEALTHDEVICE_H_ +#ifndef FSFW_DEVICEHANDLERS_HEALTHDEVICE_H_ +#define FSFW_DEVICEHANDLERS_HEALTHDEVICE_H_ #include "../health/HasHealthIF.h" #include "../health/HealthHelper.h" @@ -37,4 +37,4 @@ public: HealthHelper healthHelper; }; -#endif /* HEALTHDEVICE_H_ */ +#endif /* FSFW_DEVICEHANDLERS_HEALTHDEVICE_H_ */ diff --git a/events/CMakeLists.txt b/events/CMakeLists.txt new file mode 100644 index 00000000..9e63deb8 --- /dev/null +++ b/events/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + Event.cpp + EventManager.cpp + EventMessage.cpp +) + +add_subdirectory(eventmatching) \ No newline at end of file diff --git a/events/Event.cpp b/events/Event.cpp deleted file mode 100644 index ea3d46fe..00000000 --- a/events/Event.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Event.h" -namespace EVENT { -EventId_t getEventId(Event event) { - return (event & 0xFFFF); -} - -EventSeverity_t getSeverity(Event event) { - return ((event >> 16) & 0xFF); -} - -Event makeEvent(EventId_t eventId, EventSeverity_t eventSeverity) { - return (eventSeverity << 16) + (eventId & 0xFFFF); -} -} diff --git a/events/Event.h b/events/Event.h index f8410f32..aebc4bc5 100644 --- a/events/Event.h +++ b/events/Event.h @@ -3,8 +3,8 @@ #include #include "fwSubsystemIdRanges.h" -//could be move to more suitable location -#include +// could be moved to more suitable location +#include typedef uint16_t EventId_t; typedef uint8_t EventSeverity_t; @@ -13,32 +13,28 @@ typedef uint8_t EventSeverity_t; typedef uint32_t Event; -namespace EVENT { -EventId_t getEventId(Event event); +namespace event { -EventSeverity_t getSeverity(Event event); - -Event makeEvent(EventId_t eventId, EventSeverity_t eventSeverity); - -} -namespace SEVERITY { - static const EventSeverity_t INFO = 1; - static const EventSeverity_t LOW = 2; - static const EventSeverity_t MEDIUM = 3; - static const EventSeverity_t HIGH = 4; +constexpr EventId_t getEventId(Event event) { + return (event & 0xFFFF); } -//Unfortunately, this does not work nicely because of the inability to define static classes in headers. -//struct Event { -// Event(uint8_t domain, uint8_t counter, EventSeverity_t severity) : -// id(domain*100+counter), severity(severity) { -// } -// EventId_t id; -// EventSeverity_t severity; -// static const EventSeverity_t INFO = 1; -// static const EventSeverity_t LOW = 2; -// static const EventSeverity_t MEDIUM = 3; -// static const EventSeverity_t HIGH = 4; -//}; +constexpr EventSeverity_t getSeverity(Event event) { + return ((event >> 16) & 0xFF); +} + +constexpr Event makeEvent(uint8_t subsystemId, uint8_t uniqueEventId, + EventSeverity_t eventSeverity) { + return (eventSeverity << 16) + (subsystemId * 100) + uniqueEventId; +} + +} + +namespace severity { + static constexpr EventSeverity_t INFO = 1; + static constexpr EventSeverity_t LOW = 2; + static constexpr EventSeverity_t MEDIUM = 3; + static constexpr EventSeverity_t HIGH = 4; +} #endif /* EVENTOBJECT_EVENT_H_ */ diff --git a/events/EventManager.cpp b/events/EventManager.cpp index d171b591..001c2390 100644 --- a/events/EventManager.cpp +++ b/events/EventManager.cpp @@ -7,21 +7,22 @@ #include "../ipc/MutexFactory.h" -const uint16_t EventManager::POOL_SIZES[N_POOLS] = { - sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher), - sizeof(ReporterRangeMatcher) }; // If one checks registerListener calls, there are around 40 (to max 50) // objects registering for certain events. // Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. // So a good guess is 75 to a max of 100 pools required for each, which fits well. -const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { - fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES , - fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, - fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS }; +const LocalPool::LocalPoolConfig EventManager::poolConfig = { + {fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES, + sizeof(EventMatchTree::Node)}, + {fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, + sizeof(EventIdRangeMatcher)}, + {fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, + sizeof(ReporterRangeMatcher)} +}; EventManager::EventManager(object_id_t setObjectId) : SystemObject(setObjectId), - factoryBackend(0, POOL_SIZES, N_ELEMENTS, false, true) { + factoryBackend(0, poolConfig, false, true) { mutex = MutexFactory::instance()->createMutex(); eventReportQueue = QueueFactory::instance()->createMessageQueue( MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE); @@ -118,7 +119,7 @@ ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, void EventManager::printEvent(EventMessage* message) { const char *string = 0; switch (message->getSeverity()) { - case SEVERITY::INFO: + case severity::INFO: #ifdef DEBUG_INFO_EVENT string = translateObject(message->getReporter()); sif::info << "EVENT: "; diff --git a/events/EventManager.h b/events/EventManager.h index 5e1a8153..fe35d9d3 100644 --- a/events/EventManager.h +++ b/events/EventManager.h @@ -8,9 +8,11 @@ #include "../tasks/ExecutableObjectIF.h" #include "../ipc/MessageQueueIF.h" #include "../ipc/MutexIF.h" +#include + #include -#ifdef DEBUG +#if FSFW_DEBUG_OUTPUT == 1 // forward declaration, should be implemented by mission extern const char* translateObject(object_id_t object); extern const char* translateEvents(Event event); @@ -49,7 +51,9 @@ protected: MutexIF* mutex = nullptr; static const uint8_t N_POOLS = 3; - LocalPool factoryBackend; + LocalPool factoryBackend; + static const LocalPool::LocalPoolConfig poolConfig; + static const uint16_t POOL_SIZES[N_POOLS]; static const uint16_t N_ELEMENTS[N_POOLS]; diff --git a/events/EventMessage.cpp b/events/EventMessage.cpp index b911abab..bbc41e10 100644 --- a/events/EventMessage.cpp +++ b/events/EventMessage.cpp @@ -48,7 +48,7 @@ void EventMessage::setMessageId(uint8_t id) { EventSeverity_t EventMessage::getSeverity() { Event event; memcpy(&event, getData(), sizeof(Event)); - return EVENT::getSeverity(event); + return event::getSeverity(event); } void EventMessage::setSeverity(EventSeverity_t severity) { @@ -61,7 +61,7 @@ void EventMessage::setSeverity(EventSeverity_t severity) { EventId_t EventMessage::getEventId() { Event event; memcpy(&event, getData(), sizeof(Event)); - return EVENT::getEventId(event); + return event::getEventId(event); } void EventMessage::setEventId(EventId_t eventId) { diff --git a/events/eventmatching/CMakeLists.txt b/events/eventmatching/CMakeLists.txt new file mode 100644 index 00000000..81ff9ed8 --- /dev/null +++ b/events/eventmatching/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + EventIdRangeMatcher.cpp + EventMatchTree.cpp + ReporterRangeMatcher.cpp + SeverityRangeMatcher.cpp +) \ No newline at end of file diff --git a/fdir/CMakeLists.txt b/fdir/CMakeLists.txt new file mode 100644 index 00000000..f5ffbba8 --- /dev/null +++ b/fdir/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + EventCorrelation.cpp + FailureIsolationBase.cpp + FaultCounter.cpp +) \ No newline at end of file diff --git a/fdir/FailureIsolationBase.cpp b/fdir/FailureIsolationBase.cpp index f3b34f0f..a04a0313 100644 --- a/fdir/FailureIsolationBase.cpp +++ b/fdir/FailureIsolationBase.cpp @@ -139,7 +139,7 @@ void FailureIsolationBase::triggerEvent(Event event, uint32_t parameter1, uint32_t parameter2) { //With this mechanism, all events are disabled for a certain device. //That's not so good for visibility. - if (isFdirDisabledForSeverity(EVENT::getSeverity(event))) { + if (isFdirDisabledForSeverity(event::getSeverity(event))) { return; } EventMessage message(event, ownerId, parameter1, parameter2); @@ -148,7 +148,7 @@ void FailureIsolationBase::triggerEvent(Event event, uint32_t parameter1, } bool FailureIsolationBase::isFdirDisabledForSeverity(EventSeverity_t severity) { - if ((owner != NULL) && (severity != SEVERITY::INFO)) { + if ((owner != NULL) && (severity != severity::INFO)) { if (owner->getHealth() == HasHealthIF::EXTERNAL_CONTROL) { //External control disables handling of fault messages. return true; diff --git a/fdir/FailureIsolationBase.h b/fdir/FailureIsolationBase.h index 5b2c099a..4a3f5adf 100644 --- a/fdir/FailureIsolationBase.h +++ b/fdir/FailureIsolationBase.h @@ -14,9 +14,9 @@ class FailureIsolationBase: public HasReturnvaluesIF, public HasParametersIF { public: static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1; - static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, SEVERITY::INFO); //!< FDIR has an internal state, which changed from par2 (oldState) to par1 (newState). - static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, SEVERITY::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery. - static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, SEVERITY::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery. + static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2 (oldState) to par1 (newState). + static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery. + static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery. FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT, diff --git a/fsfw.mk b/fsfw.mk index f2cdd7ab..c5847554 100644 --- a/fsfw.mk +++ b/fsfw.mk @@ -9,6 +9,9 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/controller/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/coordinates/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapool/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoolglob/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/housekeeping/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/eventmatching/*.cpp) @@ -70,5 +73,3 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/packetmatcher/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/pus/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcservices/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/pus/*.cpp) - -INCLUDES += $(CURRENTPATH) diff --git a/globalfunctions/CMakeLists.txt b/globalfunctions/CMakeLists.txt new file mode 100644 index 00000000..2b3dcf8e --- /dev/null +++ b/globalfunctions/CMakeLists.txt @@ -0,0 +1,12 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + arrayprinter.cpp + AsciiConverter.cpp + CRC.cpp + DleEncoder.cpp + PeriodicOperationDivider.cpp + timevalOperations.cpp + Type.cpp +) + +add_subdirectory(math) \ No newline at end of file diff --git a/globalfunctions/PeriodicOperationDivider.cpp b/globalfunctions/PeriodicOperationDivider.cpp index ad3b8bbd..28e98feb 100644 --- a/globalfunctions/PeriodicOperationDivider.cpp +++ b/globalfunctions/PeriodicOperationDivider.cpp @@ -7,16 +7,26 @@ PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider, } bool PeriodicOperationDivider::checkAndIncrement() { - if(counter >= divider) { + bool opNecessary = check(); + if(opNecessary) { if(resetAutomatically) { counter = 0; } - return true; + return opNecessary; } counter ++; + return opNecessary; +} + +bool PeriodicOperationDivider::check() { + if(counter >= divider) { + return true; + } return false; } + + void PeriodicOperationDivider::resetCounter() { counter = 0; } diff --git a/globalfunctions/PeriodicOperationDivider.h b/globalfunctions/PeriodicOperationDivider.h index dd970fb8..7f7fb469 100644 --- a/globalfunctions/PeriodicOperationDivider.h +++ b/globalfunctions/PeriodicOperationDivider.h @@ -21,17 +21,27 @@ public: */ PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true); + /** * Check whether operation is necessary. * If an operation is necessary and the class has been * configured to be reset automatically, the counter will be reset. - * If not, the counter will be incremented. + * * @return * -@c true if the counter is larger or equal to the divider * -@c false otherwise */ bool checkAndIncrement(); + /** + * Checks whether an operation is necessary. + * This function will not increment the counter! + * @return + * -@c true if the counter is larger or equal to the divider + * -@c false otherwise + */ + bool check(); + /** * Can be used to reset the counter to 0 manually. */ diff --git a/globalfunctions/math/CMakeLists.txt b/globalfunctions/math/CMakeLists.txt new file mode 100644 index 00000000..a9c4ded7 --- /dev/null +++ b/globalfunctions/math/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + QuaternionOperations.cpp +) diff --git a/health/CMakeLists.txt b/health/CMakeLists.txt new file mode 100644 index 00000000..d5f3ccd3 --- /dev/null +++ b/health/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + HealthHelper.cpp + HealthMessage.cpp + HealthTable.cpp +) \ No newline at end of file diff --git a/health/HasHealthIF.h b/health/HasHealthIF.h index 86863ea8..a6254e39 100644 --- a/health/HasHealthIF.h +++ b/health/HasHealthIF.h @@ -21,13 +21,13 @@ public: static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2); static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1; - static const Event HEALTH_INFO = MAKE_EVENT(6, SEVERITY::INFO); - static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, SEVERITY::INFO); - static const Event CHILD_PROBLEMS = MAKE_EVENT(8, SEVERITY::LOW); - static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, SEVERITY::LOW); //!< Assembly overwrites health information of children to keep satellite alive. - static const Event TRYING_RECOVERY = MAKE_EVENT(10, SEVERITY::MEDIUM); //!< Someone starts a recovery of a component (typically power-cycle). No parameters. - static const Event RECOVERY_STEP = MAKE_EVENT(11, SEVERITY::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1: 0 for the first, 1 for the second event. P2: 0 - static const Event RECOVERY_DONE = MAKE_EVENT(12, SEVERITY::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters. + static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO); + static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO); + static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW); + static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep satellite alive. + static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically power-cycle). No parameters. + static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1: 0 for the first, 1 for the second event. P2: 0 + static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters. virtual ~HasHealthIF() { } diff --git a/housekeeping/AcceptsHkPacketsIF.h b/housekeeping/AcceptsHkPacketsIF.h new file mode 100644 index 00000000..6fa151b1 --- /dev/null +++ b/housekeeping/AcceptsHkPacketsIF.h @@ -0,0 +1,12 @@ +#ifndef FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ +#define FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ + +#include "../ipc/MessageQueueMessageIF.h" + +class AcceptsHkPacketsIF { +public: + virtual~ AcceptsHkPacketsIF() {}; + virtual MessageQueueId_t getHkQueue() const = 0; +}; + +#endif /* FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ */ diff --git a/housekeeping/HousekeepingMessage.cpp b/housekeeping/HousekeepingMessage.cpp new file mode 100644 index 00000000..221f0a6f --- /dev/null +++ b/housekeeping/HousekeepingMessage.cpp @@ -0,0 +1,215 @@ +#include "HousekeepingMessage.h" + +#include "../objectmanager/ObjectManagerIF.h" +#include + +HousekeepingMessage::~HousekeepingMessage() {} + +void HousekeepingMessage::setHkReportReply(CommandMessage* message, sid_t sid, + store_address_t storeId) { + message->setCommand(HK_REPORT); + message->setMessageSize(HK_MESSAGE_SIZE); + setSid(message, sid); + message->setParameter3(storeId.raw); +} + +void HousekeepingMessage::setHkDiagnosticsReply(CommandMessage* message, + sid_t sid, store_address_t storeId) { + message->setCommand(DIAGNOSTICS_REPORT); + message->setMessageSize(HK_MESSAGE_SIZE); + setSid(message, sid); + message->setParameter3(storeId.raw); +} + +sid_t HousekeepingMessage::getHkDataReply(const CommandMessage *message, + store_address_t *storeIdToSet) { + if(storeIdToSet != nullptr) { + *storeIdToSet = message->getParameter3(); + } + return getSid(message); +} + +void HousekeepingMessage::setToggleReportingCommand(CommandMessage *message, + sid_t sid, bool enableReporting, bool isDiagnostics) { + if(isDiagnostics) { + if(enableReporting) { + message->setCommand(ENABLE_PERIODIC_DIAGNOSTICS_GENERATION); + } + else { + message->setCommand(DISABLE_PERIODIC_DIAGNOSTICS_GENERATION); + } + } + else { + if(enableReporting) { + message->setCommand(ENABLE_PERIODIC_HK_REPORT_GENERATION); + } + else { + message->setCommand(DISABLE_PERIODIC_HK_REPORT_GENERATION); + } + } + + setSid(message, sid); +} + +void HousekeepingMessage::setStructureReportingCommand(CommandMessage *command, + sid_t sid, bool isDiagnostics) { + if(isDiagnostics) { + command->setCommand(REPORT_DIAGNOSTICS_REPORT_STRUCTURES); + } + else { + command->setCommand(REPORT_HK_REPORT_STRUCTURES); + } + + setSid(command, sid); +} + +void HousekeepingMessage::setOneShotReportCommand(CommandMessage *command, + sid_t sid, bool isDiagnostics) { + if(isDiagnostics) { + command->setCommand(GENERATE_ONE_DIAGNOSTICS_REPORT); + } + else { + command->setCommand(GENERATE_ONE_PARAMETER_REPORT); + } + + setSid(command, sid); +} + +void HousekeepingMessage::setCollectionIntervalModificationCommand( + CommandMessage *command, sid_t sid, float collectionInterval, + bool isDiagnostics) { + if(isDiagnostics) { + command->setCommand(MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL); + } + else { + command->setCommand(MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL); + } + command->setParameter3(collectionInterval); + + setSid(command, sid); +} + +sid_t HousekeepingMessage::getCollectionIntervalModificationCommand( + const CommandMessage* command, float* newCollectionInterval) { + if(newCollectionInterval != nullptr) { + *newCollectionInterval = command->getParameter3(); + } + + return getSid(command); +} + +void HousekeepingMessage::setHkRequestSuccessReply(CommandMessage *reply, + sid_t sid) { + setSid(reply, sid); + reply->setCommand(HK_REQUEST_SUCCESS); +} + +void HousekeepingMessage::setHkRequestFailureReply(CommandMessage *reply, + sid_t sid, ReturnValue_t error) { + setSid(reply, sid); + reply->setCommand(HK_REQUEST_FAILURE); + reply->setParameter3(error); +} + +sid_t HousekeepingMessage::getHkRequestFailureReply(const CommandMessage *reply, + ReturnValue_t *error) { + if(error != nullptr) { + *error = reply->getParameter3(); + } + return getSid(reply); +} + +sid_t HousekeepingMessage::getSid(const CommandMessage* message) { + sid_t sid; + std::memcpy(&sid.raw, message->getData(), sizeof(sid.raw)); + return sid; +} + +void HousekeepingMessage::setSid(CommandMessage *message, sid_t sid) { + std::memcpy(message->getData(), &sid.raw, sizeof(sid.raw)); +} + +void HousekeepingMessage::setHkStuctureReportReply(CommandMessage *reply, + sid_t sid, store_address_t storeId) { + reply->setCommand(HK_DEFINITIONS_REPORT); + setSid(reply, sid); + reply->setParameter3(storeId.raw); +} + +void HousekeepingMessage::setDiagnosticsStuctureReportReply( + CommandMessage *reply, sid_t sid, store_address_t storeId) { + reply->setCommand(DIAGNOSTICS_DEFINITION_REPORT); + setSid(reply, sid); + reply->setParameter3(storeId.raw); +} + +void HousekeepingMessage::clear(CommandMessage* message) { + switch(message->getCommand()) { + case(HK_REPORT): + case(DIAGNOSTICS_REPORT): + case(HK_DEFINITIONS_REPORT): + case(DIAGNOSTICS_DEFINITION_REPORT): + case(UPDATE_SNAPSHOT_SET): { + store_address_t storeId; + getHkDataReply(message, &storeId); + StorageManagerIF *ipcStore = objectManager->get( + objects::IPC_STORE); + if (ipcStore != nullptr) { + ipcStore->deleteData(storeId); + } + } + } + message->setCommand(CommandMessage::CMD_NONE); +} + +void HousekeepingMessage::setUpdateNotificationSetCommand( + CommandMessage *command, sid_t sid) { + command->setCommand(UPDATE_NOTIFICATION_SET); + setSid(command, sid); +} + +void HousekeepingMessage::setUpdateNotificationVariableCommand( + CommandMessage *command, lp_id_t localPoolId) { + command->setCommand(UPDATE_NOTIFICATION_VARIABLE); + command->setParameter(localPoolId); +} + +void HousekeepingMessage::setUpdateSnapshotSetCommand(CommandMessage *command, + sid_t sid, store_address_t storeId) { + command->setCommand(UPDATE_SNAPSHOT_VARIABLE); + setSid(command, sid); + command->setParameter3(storeId.raw); +} + +void HousekeepingMessage::setUpdateSnapshotVariableCommand( + CommandMessage *command, lp_id_t localPoolId, store_address_t storeId) { + command->setCommand(UPDATE_SNAPSHOT_VARIABLE); + command->setParameter(localPoolId); + command->setParameter3(storeId.raw); +} + +sid_t HousekeepingMessage::getUpdateNotificationSetCommand( + const CommandMessage *command) { + return getSid(command); +} + +lp_id_t HousekeepingMessage::getUpdateNotificationVariableCommand( + const CommandMessage *command) { + return command->getParameter(); +} + +sid_t HousekeepingMessage::getUpdateSnapshotSetCommand( + const CommandMessage *command, store_address_t *storeId) { + if(storeId != nullptr) { + *storeId = command->getParameter3(); + } + return getSid(command); +} + +lp_id_t HousekeepingMessage::getUpdateSnapshotVariableCommand( + const CommandMessage *command, store_address_t *storeId) { + if(storeId != nullptr) { + *storeId = command->getParameter3(); + } + return command->getParameter(); +} diff --git a/housekeeping/HousekeepingMessage.h b/housekeeping/HousekeepingMessage.h new file mode 100644 index 00000000..90bbe594 --- /dev/null +++ b/housekeeping/HousekeepingMessage.h @@ -0,0 +1,149 @@ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ + +#include "../datapoollocal/locPoolDefinitions.h" +#include "../ipc/CommandMessage.h" +#include "../ipc/FwMessageTypes.h" +#include "../objectmanager/frameworkObjects.h" +#include "../storagemanager/StorageManagerIF.h" + + +/** + * @brief Special command message type for housekeeping messages + * @details + * This message is slightly larger than regular command messages to accomodate + * the uint64_t structure ID (SID). + */ +class HousekeepingMessage { +public: + + static constexpr size_t HK_MESSAGE_SIZE = CommandMessageIF::HEADER_SIZE + + sizeof(sid_t) + sizeof(uint32_t); + + /** + * Concrete instance is not used, instead this class operates on + * command message instances. + */ + HousekeepingMessage() = delete; + virtual ~HousekeepingMessage(); + + static constexpr uint8_t MESSAGE_ID = messagetypes::HOUSEKEEPING; + + static constexpr Command_t ENABLE_PERIODIC_HK_REPORT_GENERATION = + MAKE_COMMAND_ID(5); + static constexpr Command_t DISABLE_PERIODIC_HK_REPORT_GENERATION = + MAKE_COMMAND_ID(6); + + static constexpr Command_t ENABLE_PERIODIC_DIAGNOSTICS_GENERATION = + MAKE_COMMAND_ID(7); + static constexpr Command_t DISABLE_PERIODIC_DIAGNOSTICS_GENERATION = + MAKE_COMMAND_ID(8); + + static constexpr Command_t REPORT_HK_REPORT_STRUCTURES = MAKE_COMMAND_ID(9); + static constexpr Command_t REPORT_DIAGNOSTICS_REPORT_STRUCTURES = + MAKE_COMMAND_ID(11); + + static constexpr Command_t HK_DEFINITIONS_REPORT = MAKE_COMMAND_ID(10); + static constexpr Command_t DIAGNOSTICS_DEFINITION_REPORT = MAKE_COMMAND_ID(12); + + static constexpr Command_t HK_REPORT = MAKE_COMMAND_ID(25); + static constexpr Command_t DIAGNOSTICS_REPORT = MAKE_COMMAND_ID(26); + + static constexpr Command_t GENERATE_ONE_PARAMETER_REPORT = + MAKE_COMMAND_ID(27); + static constexpr Command_t GENERATE_ONE_DIAGNOSTICS_REPORT = + MAKE_COMMAND_ID(28); + + static constexpr Command_t MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL = + MAKE_COMMAND_ID(31); + static constexpr Command_t MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL = + MAKE_COMMAND_ID(32); + + static constexpr Command_t HK_REQUEST_SUCCESS = + MAKE_COMMAND_ID(128); + static constexpr Command_t HK_REQUEST_FAILURE = + MAKE_COMMAND_ID(129); + + static constexpr Command_t UPDATE_NOTIFICATION_SET = + MAKE_COMMAND_ID(130); + static constexpr Command_t UPDATE_NOTIFICATION_VARIABLE = + MAKE_COMMAND_ID(131); + + static constexpr Command_t UPDATE_SNAPSHOT_SET = MAKE_COMMAND_ID(132); + static constexpr Command_t UPDATE_SNAPSHOT_VARIABLE = MAKE_COMMAND_ID(133); + + //static constexpr Command_t UPDATE_HK_REPORT = MAKE_COMMAND_ID(134); + + static sid_t getSid(const CommandMessage* message); + + /* Housekeeping Interface Messages */ + + static void setToggleReportingCommand(CommandMessage* command, sid_t sid, + bool enableReporting, bool isDiagnostics); + static void setStructureReportingCommand(CommandMessage* command, sid_t sid, + bool isDiagnostics); + static void setOneShotReportCommand(CommandMessage* command, sid_t sid, + bool isDiagnostics); + static void setCollectionIntervalModificationCommand( + CommandMessage* command, sid_t sid, float collectionInterval, + bool isDiagnostics); + + static void setHkReportReply(CommandMessage* reply, sid_t sid, + store_address_t storeId); + static void setHkDiagnosticsReply(CommandMessage* reply, sid_t sid, + store_address_t storeId); + + static void setHkRequestSuccessReply(CommandMessage* reply, sid_t sid); + static void setHkRequestFailureReply(CommandMessage* reply, sid_t sid, + ReturnValue_t error); + + static void setHkStuctureReportReply(CommandMessage* reply, + sid_t sid, store_address_t storeId); + static void setDiagnosticsStuctureReportReply(CommandMessage* reply, + sid_t sid, store_address_t storeId); + + static sid_t getHkRequestFailureReply(const CommandMessage* reply, + ReturnValue_t* error); + + /** + * @brief Generic getter function for housekeeping data replies + * @details + * Command ID can be used beforehand to distinguish between diagnostics and + * regular HK packets. This getter function should be used for the + * command IDs 10, 12, 25 and 26. + */ + static sid_t getHkDataReply(const CommandMessage* message, + store_address_t * storeIdToSet); + static sid_t getCollectionIntervalModificationCommand( + const CommandMessage* command, float* newCollectionInterval); + + + /* Update Notification Messages */ + + static void setUpdateNotificationSetCommand(CommandMessage* command, + sid_t sid); + static void setUpdateNotificationVariableCommand(CommandMessage* command, + lp_id_t localPoolId); + + static void setUpdateSnapshotSetCommand(CommandMessage* command, sid_t sid, + store_address_t storeId); + static void setUpdateSnapshotVariableCommand(CommandMessage* command, + lp_id_t localPoolId, store_address_t storeId); + + static sid_t getUpdateNotificationSetCommand(const CommandMessage* command); + static lp_id_t getUpdateNotificationVariableCommand( + const CommandMessage* command); + + static sid_t getUpdateSnapshotSetCommand(const CommandMessage* command, + store_address_t* storeId); + static lp_id_t getUpdateSnapshotVariableCommand(const CommandMessage* command, + store_address_t* storeId); + + /** Utility */ + static void clear(CommandMessage* message); +private: + static void setSid(CommandMessage* message, sid_t sid); +}; + + +#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ */ diff --git a/housekeeping/HousekeepingPacketDownlink.h b/housekeeping/HousekeepingPacketDownlink.h new file mode 100644 index 00000000..ae0cc988 --- /dev/null +++ b/housekeeping/HousekeepingPacketDownlink.h @@ -0,0 +1,34 @@ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETDOWNLINK_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETDOWNLINK_H_ + +#include "../datapoollocal/LocalPoolDataSetBase.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../storagemanager/StorageManagerIF.h" + +/** + * @brief This class will be used to serialize general housekeeping packets + * which are destined to be downlinked into the store. + * @details + * The housekeeping packets are stored into the IPC store and forwarded + * to the designated housekeeping handler. + */ +class HousekeepingPacketDownlink: public SerialLinkedListAdapter { +public: + HousekeepingPacketDownlink(sid_t sid, LocalPoolDataSetBase* dataSetPtr): + sourceId(sid.objectId), setId(sid.ownerSetId), hkData(dataSetPtr) { + setLinks(); + } + +private: + void setLinks() { + setStart(&sourceId); + sourceId.setNext(&setId); + setId.setNext(&hkData); + } + + SerializeElement sourceId; + SerializeElement setId; + LinkedElement hkData; +}; + +#endif /* FRAMEWORK_HOUSEKEEPING_HOUSEKEEPINGPACKETDOWNLINK_H_ */ diff --git a/housekeeping/HousekeepingPacketUpdate.h b/housekeeping/HousekeepingPacketUpdate.h new file mode 100644 index 00000000..43ec0619 --- /dev/null +++ b/housekeeping/HousekeepingPacketUpdate.h @@ -0,0 +1,92 @@ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ + +#include "../serialize/SerialBufferAdapter.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../datapoollocal/LocalPoolDataSetBase.h" + +/** + * @brief This helper class will be used to serialize and deserialize + * update housekeeping packets into the store. + */ +class HousekeepingPacketUpdate: public SerializeIF { +public: + /** + * Update packet constructor for datasets + * @param timeStamp + * @param timeStampSize + * @param hkData + * @param hkDataSize + */ + HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, + LocalPoolDataSetBase* dataSetPtr): + timeStamp(timeStamp), timeStampSize(timeStampSize), + updateData(dataSetPtr) {}; + + /** + * Update packet constructor for pool variables. + * @param timeStamp + * @param timeStampSize + * @param dataSetPtr + */ + HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, + LocalPoolObjectBase* dataSetPtr): + timeStamp(timeStamp), timeStampSize(timeStampSize), + updateData(dataSetPtr) {}; + + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const { + if(timeStamp != nullptr) { + /* Endianness will always be MACHINE, so we can simply use memcpy + here. */ + std::memcpy(*buffer, timeStamp, timeStampSize); + *size += timeStampSize; + *buffer += timeStampSize; + } + if(updateData == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + return updateData->serialize(buffer, size, maxSize, streamEndianness); + } + + virtual size_t getSerializedSize() const { + if(updateData == nullptr) { + return 0; + } + return timeStampSize + updateData->getSerializedSize(); + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override { + if(*size < timeStampSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + + if(timeStamp != nullptr) { + /* Endianness will always be MACHINE, so we can simply use memcpy + here. */ + std::memcpy(timeStamp, *buffer, timeStampSize); + *size -= timeStampSize; + *buffer += timeStampSize; + } + + if(updateData == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size < updateData->getSerializedSize()) { + return SerializeIF::STREAM_TOO_SHORT; + } + + return updateData->deSerialize(buffer, size, streamEndianness); + } + +private: + uint8_t* timeStamp = nullptr; + size_t timeStampSize = 0; + + SerializeIF* updateData = nullptr; +}; + + +#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ */ diff --git a/housekeeping/HousekeepingSetPacket.h b/housekeeping/HousekeepingSetPacket.h new file mode 100644 index 00000000..f94720d4 --- /dev/null +++ b/housekeeping/HousekeepingSetPacket.h @@ -0,0 +1,59 @@ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGSETPACKET_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGSETPACKET_H_ + +#include "../housekeeping/HousekeepingMessage.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../datapoollocal/LocalPoolDataSetBase.h" + +class HousekeepingSetPacket: public SerialLinkedListAdapter { +public: + HousekeepingSetPacket(sid_t sid, bool reportingEnabled, bool valid, + float collectionInterval, LocalPoolDataSetBase* dataSetPtr): + objectId(sid.objectId), setId(sid.ownerSetId), + reportingEnabled(reportingEnabled), valid(valid), + collectionIntervalSeconds(collectionInterval), dataSet(dataSetPtr) { + setLinks(); + } + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override { + ReturnValue_t result = SerialLinkedListAdapter::serialize(buffer, size, + maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return dataSet->serializeLocalPoolIds(buffer, size ,maxSize, + streamEndianness); + } + + size_t getSerializedSize() const override { + size_t linkedSize = SerialLinkedListAdapter::getSerializedSize(); + linkedSize += dataSet->getLocalPoolIdsSerializedSize(); + return linkedSize; + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_OK; + } + +private: + + void setLinks() { + setStart(&objectId); + objectId.setNext(&setId); + setId.setNext(&reportingEnabled); + reportingEnabled.setNext(&valid); + valid.setNext(&collectionIntervalSeconds); + collectionIntervalSeconds.setEnd(); + } + + SerializeElement objectId; + SerializeElement setId; + SerializeElement reportingEnabled; + SerializeElement valid; + SerializeElement collectionIntervalSeconds; + LocalPoolDataSetBase* dataSet; +}; + +#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGSETPACKET_H_ */ diff --git a/housekeeping/PeriodicHousekeepingHelper.cpp b/housekeeping/PeriodicHousekeepingHelper.cpp new file mode 100644 index 00000000..365f0004 --- /dev/null +++ b/housekeeping/PeriodicHousekeepingHelper.cpp @@ -0,0 +1,49 @@ +#include "PeriodicHousekeepingHelper.h" + +#include "../datapoollocal/LocalPoolDataSetBase.h" +#include + +PeriodicHousekeepingHelper::PeriodicHousekeepingHelper( + LocalPoolDataSetBase* owner): owner(owner) {} + + +void PeriodicHousekeepingHelper::initialize(float collectionInterval, + dur_millis_t minimumPeriodicInterval, bool isDiagnostics, + uint8_t nonDiagIntervalFactor) { + this->minimumPeriodicInterval = minimumPeriodicInterval; + if(not isDiagnostics) { + this->minimumPeriodicInterval = this->minimumPeriodicInterval * + nonDiagIntervalFactor; + } + collectionIntervalTicks = intervalSecondsToInterval(collectionInterval); +} + +float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() { + return intervalToIntervalSeconds(collectionIntervalTicks); +} + +bool PeriodicHousekeepingHelper::checkOpNecessary() { + if(internalTickCounter >= collectionIntervalTicks) { + internalTickCounter = 1; + return true; + } + internalTickCounter++; + return false; +} + +uint32_t PeriodicHousekeepingHelper::intervalSecondsToInterval( + float collectionIntervalSeconds) { + return std::ceil(collectionIntervalSeconds * 1000 + / minimumPeriodicInterval); +} + +float PeriodicHousekeepingHelper::intervalToIntervalSeconds( + uint32_t collectionInterval) { + return static_cast(collectionInterval * + minimumPeriodicInterval); +} + +void PeriodicHousekeepingHelper::changeCollectionInterval( + float newIntervalSeconds) { + collectionIntervalTicks = intervalSecondsToInterval(newIntervalSeconds); +} diff --git a/housekeeping/PeriodicHousekeepingHelper.h b/housekeeping/PeriodicHousekeepingHelper.h new file mode 100644 index 00000000..d96eae1d --- /dev/null +++ b/housekeeping/PeriodicHousekeepingHelper.h @@ -0,0 +1,32 @@ +#ifndef FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ +#define FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ + +#include "../timemanager/Clock.h" +#include + +class LocalPoolDataSetBase; + +class PeriodicHousekeepingHelper { +public: + PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner); + + void initialize(float collectionInterval, + dur_millis_t minimumPeriodicInterval, bool isDiagnostics, + uint8_t nonDiagIntervalFactor); + + void changeCollectionInterval(float newInterval); + float getCollectionIntervalInSeconds(); + bool checkOpNecessary(); +private: + LocalPoolDataSetBase* owner = nullptr; + + uint32_t intervalSecondsToInterval(float collectionIntervalSeconds); + float intervalToIntervalSeconds(uint32_t collectionInterval); + + dur_millis_t minimumPeriodicInterval = 0; + uint32_t internalTickCounter = 1; + uint32_t collectionIntervalTicks = 0; + +}; + +#endif /* FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ */ diff --git a/internalError/CMakeLists.txt b/internalError/CMakeLists.txt new file mode 100644 index 00000000..2b383914 --- /dev/null +++ b/internalError/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + InternalErrorReporter.cpp +) \ No newline at end of file diff --git a/internalError/InternalErrorDataset.h b/internalError/InternalErrorDataset.h new file mode 100644 index 00000000..fa91116d --- /dev/null +++ b/internalError/InternalErrorDataset.h @@ -0,0 +1,34 @@ +#ifndef FSFW_INTERNALERROR_INTERNALERRORDATASET_H_ +#define FSFW_INTERNALERROR_INTERNALERRORDATASET_H_ + +#include +#include + +enum errorPoolIds { + TM_HITS, + QUEUE_HITS, + STORE_HITS +}; + + +class InternalErrorDataset: public StaticLocalDataSet<3 * sizeof(uint32_t)> { +public: + static constexpr uint8_t ERROR_SET_ID = 0; + + InternalErrorDataset(HasLocalDataPoolIF* owner): + StaticLocalDataSet(owner, ERROR_SET_ID) {} + + InternalErrorDataset(object_id_t objectId): + StaticLocalDataSet(sid_t(objectId , ERROR_SET_ID)) {} + + lp_var_t tmHits = lp_var_t(hkManager->getOwner(), + TM_HITS, this); + lp_var_t queueHits = lp_var_t(hkManager->getOwner(), + QUEUE_HITS, this); + lp_var_t storeHits = lp_var_t(hkManager->getOwner(), + STORE_HITS, this); +}; + + + +#endif /* FSFW_INTERNALERROR_INTERNALERRORDATASET_H_ */ diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index 861e1595..bfb67289 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -1,17 +1,16 @@ #include "InternalErrorReporter.h" -#include "../datapool/DataSet.h" -#include "../datapool/PoolVariable.h" +#include "../ipc/QueueFactory.h" #include "../ipc/MutexFactory.h" - #include "../serviceinterface/ServiceInterfaceStream.h" InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, - uint32_t queuePoolId, uint32_t tmPoolId, uint32_t storePoolId) : - SystemObject(setObjectId), mutex(NULL), queuePoolId(queuePoolId), tmPoolId( - tmPoolId), storePoolId( - storePoolId), queueHits(0), tmHits(0), storeHits( - 0) { + uint32_t messageQueueDepth): SystemObject(setObjectId), + commandQueue(QueueFactory::instance()-> + createMessageQueue(messageQueueDepth)), + poolManager(this, commandQueue), + internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), + internalErrorDataset(this) { mutex = MutexFactory::instance()->createMutex(); } @@ -19,28 +18,42 @@ InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); } +void InternalErrorReporter::setDiagnosticPrintout(bool enable) { + this->diagnosticPrintout = enable; +} + ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { - - DataSet mySet; - PoolVariable queueHitsInPool(queuePoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - PoolVariable tmHitsInPool(tmPoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - - PoolVariable storeHitsInPool(storePoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - mySet.read(); + internalErrorDataset.read(INTERNAL_ERROR_MUTEX_TIMEOUT); uint32_t newQueueHits = getAndResetQueueHits(); uint32_t newTmHits = getAndResetTmHits(); uint32_t newStoreHits = getAndResetStoreHits(); - queueHitsInPool.value += newQueueHits; - tmHitsInPool.value += newTmHits; - storeHitsInPool.value += newStoreHits; +#ifdef DEBUG + if(diagnosticPrintout) { + if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) { + 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; + } + } +#endif - mySet.commit(PoolVariableIF::VALID); + internalErrorDataset.queueHits.value += newQueueHits; + internalErrorDataset.storeHits.value += newStoreHits; + internalErrorDataset.tmHits.value += newTmHits; + internalErrorDataset.commit(INTERNAL_ERROR_MUTEX_TIMEOUT); + + poolManager.performHkOperation(); + + CommandMessage message; + ReturnValue_t result = commandQueue->receiveMessage(&message); + if(result != MessageQueueIF::EMPTY) { + poolManager.handleHousekeepingMessage(&message); + } return HasReturnvaluesIF::RETURN_OK; } @@ -54,7 +67,7 @@ void InternalErrorReporter::lostTm() { uint32_t InternalErrorReporter::getAndResetQueueHits() { uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); value = queueHits; queueHits = 0; mutex->unlockMutex(); @@ -63,21 +76,21 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() { uint32_t InternalErrorReporter::getQueueHits() { uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); value = queueHits; mutex->unlockMutex(); return value; } void InternalErrorReporter::incrementQueueHits() { - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); queueHits++; mutex->unlockMutex(); } uint32_t InternalErrorReporter::getAndResetTmHits() { uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); value = tmHits; tmHits = 0; mutex->unlockMutex(); @@ -86,14 +99,14 @@ uint32_t InternalErrorReporter::getAndResetTmHits() { uint32_t InternalErrorReporter::getTmHits() { uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); value = tmHits; mutex->unlockMutex(); return value; } void InternalErrorReporter::incrementTmHits() { - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); tmHits++; mutex->unlockMutex(); } @@ -104,7 +117,7 @@ void InternalErrorReporter::storeFull() { uint32_t InternalErrorReporter::getAndResetStoreHits() { uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); value = storeHits; storeHits = 0; mutex->unlockMutex(); @@ -113,14 +126,65 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() { uint32_t InternalErrorReporter::getStoreHits() { uint32_t value; - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); value = storeHits; mutex->unlockMutex(); return value; } void InternalErrorReporter::incrementStoreHits() { - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); storeHits++; mutex->unlockMutex(); } + +object_id_t InternalErrorReporter::getObjectId() const { + return SystemObject::getObjectId(); +} + +MessageQueueId_t InternalErrorReporter::getCommandQueue() const { + return this->commandQueue->getId(); +} + +ReturnValue_t InternalErrorReporter::initializeLocalDataPool( + LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(errorPoolIds::TM_HITS, + new PoolEntry()); + localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, + new PoolEntry()); + localDataPoolMap.emplace(errorPoolIds::STORE_HITS, + new PoolEntry()); + poolManager.subscribeForPeriodicPacket(internalErrorSid, false, + getPeriodicOperationFrequency(), true); + internalErrorDataset.setValidity(true, true); + return HasReturnvaluesIF::RETURN_OK; +} + +LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() { + return &poolManager; +} + +dur_millis_t InternalErrorReporter::getPeriodicOperationFrequency() const { + return this->executingTask->getPeriodMs(); +} + +LocalPoolDataSetBase* InternalErrorReporter::getDataSetHandle(sid_t sid) { + return &internalErrorDataset; +} + +void InternalErrorReporter::setTaskIF(PeriodicTaskIF *task) { + this->executingTask = task; +} + +ReturnValue_t InternalErrorReporter::initialize() { + ReturnValue_t result = poolManager.initialize(commandQueue); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return SystemObject::initialize(); +} + +ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() { + return poolManager.initializeAfterTaskCreation(); +} + diff --git a/internalError/InternalErrorReporter.h b/internalError/InternalErrorReporter.h index 9aa24a0f..8d33c06e 100644 --- a/internalError/InternalErrorReporter.h +++ b/internalError/InternalErrorReporter.h @@ -1,37 +1,75 @@ -#ifndef INTERNALERRORREPORTER_H_ -#define INTERNALERRORREPORTER_H_ +#ifndef FSFW_INTERNALERROR_INTERNALERRORREPORTER_H_ +#define FSFW_INTERNALERROR_INTERNALERRORREPORTER_H_ #include "InternalErrorReporterIF.h" +#include "../tasks/PeriodicTaskIF.h" +#include "../internalError/InternalErrorDataset.h" +#include "../datapoollocal/LocalDataPoolManager.h" #include "../tasks/ExecutableObjectIF.h" #include "../objectmanager/SystemObject.h" #include "../ipc/MutexIF.h" +/** + * @brief This class is used to track internal errors like lost telemetry, + * failed message sending or a full store. + * @details + * All functions were kept virtual so this class can be extended easily + * to store custom internal errors (e.g. communication interface errors). + */ class InternalErrorReporter: public SystemObject, public ExecutableObjectIF, - public InternalErrorReporterIF { + public InternalErrorReporterIF, + public HasLocalDataPoolIF { public: - InternalErrorReporter(object_id_t setObjectId, uint32_t queuePoolId, - uint32_t tmPoolId, uint32_t storePoolId); + static constexpr uint8_t INTERNAL_ERROR_MUTEX_TIMEOUT = 20; + + InternalErrorReporter(object_id_t setObjectId, + uint32_t messageQueueDepth = 5); + + /** + * Enable diagnostic printout. Please note that this feature will + * only work if DEBUG has been supplied to the build defines. + * @param enable + */ + void setDiagnosticPrintout(bool enable); + virtual ~InternalErrorReporter(); - virtual ReturnValue_t performOperation(uint8_t opCode); + virtual object_id_t getObjectId() const override; + virtual MessageQueueId_t getCommandQueue() const override; + virtual ReturnValue_t initializeLocalDataPool( + LocalDataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + virtual LocalDataPoolManager* getHkManagerHandle() override; + virtual dur_millis_t getPeriodicOperationFrequency() const override; + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; + + virtual ReturnValue_t initialize() override; + virtual ReturnValue_t initializeAfterTaskCreation() override; + virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual void queueMessageNotSent(); virtual void lostTm(); virtual void storeFull(); + + virtual void setTaskIF(PeriodicTaskIF* task) override; protected: - MutexIF* mutex; + MessageQueueIF* commandQueue; + LocalDataPoolManager poolManager; - uint32_t queuePoolId; - uint32_t tmPoolId; - uint32_t storePoolId; + PeriodicTaskIF* executingTask = nullptr; + MutexIF* mutex = nullptr; + sid_t internalErrorSid; + InternalErrorDataset internalErrorDataset; - uint32_t queueHits; - uint32_t tmHits; - uint32_t storeHits; + bool diagnosticPrintout = true; + + uint32_t queueHits = 0; + uint32_t tmHits = 0; + uint32_t storeHits = 0; uint32_t getAndResetQueueHits(); uint32_t getQueueHits(); @@ -47,4 +85,4 @@ protected: }; -#endif /* INTERNALERRORREPORTER_H_ */ +#endif /* FSFW_INTERNALERROR_INTERNALERRORREPORTER_H_ */ diff --git a/ipc/CMakeLists.txt b/ipc/CMakeLists.txt new file mode 100644 index 00000000..6a3afe33 --- /dev/null +++ b/ipc/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + CommandMessage.cpp + CommandMessageCleaner.cpp + MessageQueueMessage.cpp +) \ No newline at end of file diff --git a/ipc/FwMessageTypes.h b/ipc/FwMessageTypes.h index e820b1df..8b49c122 100644 --- a/ipc/FwMessageTypes.h +++ b/ipc/FwMessageTypes.h @@ -3,7 +3,7 @@ namespace messagetypes { //Remember to add new Message Types to the clearCommandMessage function! -enum FW_MESSAGE_TYPE { +enum FsfwMessageTypes { COMMAND = 0, MODE_COMMAND, HEALTH_COMMAND, @@ -14,7 +14,10 @@ enum FW_MESSAGE_TYPE { MONITORING, MEMORY, PARAMETER, - FW_MESSAGES_COUNT + FILE_SYSTEM_MESSAGE, + HOUSEKEEPING, + + FW_MESSAGES_COUNT, }; } diff --git a/logo/FSFW_Logo_V3.png b/logo/FSFW_Logo_V3.png new file mode 100644 index 00000000..2ac710dd Binary files /dev/null and b/logo/FSFW_Logo_V3.png differ diff --git a/logo/FSFW_Logo_V3.svg b/logo/FSFW_Logo_V3.svg new file mode 100644 index 00000000..da561d1e --- /dev/null +++ b/logo/FSFW_Logo_V3.svg @@ -0,0 +1,711 @@ + + + + + + + + + + + + + + + + + + + + + + + + fs fw + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + fs fw + + + + + + + + + + + + + fs fw + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/logo/FSFW_Logo_V3_bw.png b/logo/FSFW_Logo_V3_bw.png new file mode 100644 index 00000000..99b9b4f9 Binary files /dev/null and b/logo/FSFW_Logo_V3_bw.png differ diff --git a/memory/CMakeLists.txt b/memory/CMakeLists.txt new file mode 100644 index 00000000..9edb9031 --- /dev/null +++ b/memory/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + MemoryHelper.cpp + MemoryMessage.cpp +) \ No newline at end of file diff --git a/memory/HasFileSystemIF.h b/memory/HasFileSystemIF.h new file mode 100644 index 00000000..dcec6346 --- /dev/null +++ b/memory/HasFileSystemIF.h @@ -0,0 +1,80 @@ +#ifndef FSFW_MEMORY_HASFILESYSTEMIF_H_ +#define FSFW_MEMORY_HASFILESYSTEMIF_H_ + +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../returnvalues/FwClassIds.h" +#include "../ipc/messageQueueDefinitions.h" + +#include + +/** + * @brief Generic interface for objects which expose a file system to enable + * message based file handling. + * @author J. Meier, R. Mueller + */ +class HasFileSystemIF { +public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::FILE_SYSTEM; + + static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x00); + static constexpr ReturnValue_t FILE_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01); + static constexpr ReturnValue_t FILE_LOCKED = MAKE_RETURN_CODE(0x02); + + static constexpr ReturnValue_t DIRECTORY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); + static constexpr ReturnValue_t DIRECTORY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x04); + static constexpr ReturnValue_t DIRECTORY_NOT_EMPTY = MAKE_RETURN_CODE(0x05); + + + static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_WRITE = MAKE_RETURN_CODE(0x06); //! P1: Sequence number missing + static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_READ = MAKE_RETURN_CODE(0x07); //! P1: Sequence number missing + + virtual ~HasFileSystemIF() {} + /** + * Function to get the MessageQueueId_t of the implementing object + * @return MessageQueueId_t of the object + */ + virtual MessageQueueId_t getCommandQueue() const = 0; + + /** + * Generic function to append to file. + * @param dirname Directory of the file + * @param filename The filename of the file + * @param data The data to write to the file + * @param size The size of the data to write + * @param packetNumber Current packet number. Can be used to verify that + * there are no missing packets. + * @param args Any other arguments which an implementation might require. + * @param bytesWritten Actual bytes written to file + * For large files the write procedure must be split in multiple calls + * to writeToFile + */ + virtual ReturnValue_t appendToFile(const char* repositoryPath, + const char* filename, const uint8_t* data, size_t size, + uint16_t packetNumber, void* args = nullptr) = 0; + + /** + * Generic function to create a new file. + * @param repositoryPath + * @param filename + * @param data + * @param size + * @param args Any other arguments which an implementation might require. + * @return + */ + virtual ReturnValue_t createFile(const char* repositoryPath, + const char* filename, const uint8_t* data = nullptr, + size_t size = 0, void* args = nullptr) = 0; + + /** + * Generic function to delete a file. + * @param repositoryPath + * @param filename + * @param args + * @return + */ + virtual ReturnValue_t deleteFile(const char* repositoryPath, + const char* filename, void* args = nullptr) = 0; +}; + + +#endif /* FSFW_MEMORY_HASFILESYSTEMIF_H_ */ diff --git a/modes/CMakeLists.txt b/modes/CMakeLists.txt new file mode 100644 index 00000000..8e5c719b --- /dev/null +++ b/modes/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ModeHelper.cpp + ModeMessage.cpp +) \ No newline at end of file diff --git a/modes/HasModesIF.h b/modes/HasModesIF.h index 34a15937..c29a0a96 100644 --- a/modes/HasModesIF.h +++ b/modes/HasModesIF.h @@ -18,14 +18,14 @@ public: static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04); static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER; - static const Event CHANGING_MODE = MAKE_EVENT(0, SEVERITY::INFO); //!< An object announces changing the mode. p1: target mode. p2: target submode - static const Event MODE_INFO = MAKE_EVENT(1, SEVERITY::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode - static const Event FALLBACK_FAILED = MAKE_EVENT(2, SEVERITY::HIGH); - static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, SEVERITY::LOW); - static const Event CANT_KEEP_MODE = MAKE_EVENT(4, SEVERITY::HIGH); - static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, SEVERITY::LOW); //!< Indicates a bug or configuration failure: Object is in a mode it should never be in. - static const Event FORCING_MODE = MAKE_EVENT(6, SEVERITY::MEDIUM); //!< The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode - static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, SEVERITY::LOW); //!< A mode command was rejected by the called object. Par1: called object id, Par2: return code. + static const Event CHANGING_MODE = MAKE_EVENT(0, severity::INFO); //!< An object announces changing the mode. p1: target mode. p2: target submode + static const Event MODE_INFO = MAKE_EVENT(1, severity::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode + static const Event FALLBACK_FAILED = MAKE_EVENT(2, severity::HIGH); + static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, severity::LOW); + static const Event CANT_KEEP_MODE = MAKE_EVENT(4, severity::HIGH); + static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, severity::LOW); //!< Indicates a bug or configuration failure: Object is in a mode it should never be in. + static const Event FORCING_MODE = MAKE_EVENT(6, severity::MEDIUM); //!< The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode + static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, severity::LOW); //!< A mode command was rejected by the called object. Par1: called object id, Par2: return code. static const Mode_t MODE_ON = 1; //!< The device is powered and ready to perform operations. In this mode, no commands are sent by the device handler itself, but direct commands van be commanded and will be interpreted static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in this mode is a mode change to on. diff --git a/monitoring/AbsLimitMonitor.h b/monitoring/AbsLimitMonitor.h index 2e60f6f8..5feb369c 100644 --- a/monitoring/AbsLimitMonitor.h +++ b/monitoring/AbsLimitMonitor.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ -#define FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ +#ifndef FSFW_MONITORING_ABSLIMITMONITOR_H_ +#define FSFW_MONITORING_ABSLIMITMONITOR_H_ #include "MonitorBase.h" #include @@ -7,9 +7,14 @@ template class AbsLimitMonitor: public MonitorBase { public: - AbsLimitMonitor(object_id_t reporterId, uint8_t monitorId, uint32_t parameterId, - uint16_t confirmationLimit, T limit, Event violationEvent = MonitoringIF::VALUE_OUT_OF_RANGE, bool aboveIsViolation = true) : - MonitorBase(reporterId, monitorId, parameterId, confirmationLimit), limit(limit), violationEvent(violationEvent), aboveIsViolation(aboveIsViolation) { + AbsLimitMonitor(object_id_t reporterId, uint8_t monitorId, + gp_id_t globalPoolId, uint16_t confirmationLimit, T limit, + Event violationEvent = MonitoringIF::VALUE_OUT_OF_RANGE, + bool aboveIsViolation = true) : + MonitorBase(reporterId, monitorId, globalPoolId, + confirmationLimit), + limit(limit), violationEvent(violationEvent), + aboveIsViolation(aboveIsViolation) { } virtual ~AbsLimitMonitor() { } @@ -32,8 +37,9 @@ public: const ParameterWrapper *newValues, uint16_t startAtIndex) { ReturnValue_t result = this->MonitorBase::getParameter(domainId, parameterId, parameterWrapper, newValues, startAtIndex); - //We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there. - if (result != this->INVALID_MATRIX_ID) { + // We'll reuse the DOMAIN_ID of MonitorReporter, + // as we know the parameterIds used there. + if (result != this->INVALID_IDENTIFIER_ID) { return result; } switch (parameterId) { @@ -41,7 +47,7 @@ public: parameterWrapper->set(this->limit); break; default: - return this->INVALID_MATRIX_ID; + return this->INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } @@ -59,7 +65,9 @@ protected: void sendTransitionEvent(T currentValue, ReturnValue_t state) { switch (state) { case MonitoringIF::OUT_OF_RANGE: - EventManagerIF::triggerEvent(this->reportingId, violationEvent, this->parameterId); + EventManagerIF::triggerEvent(this->reportingId, + violationEvent, this->globalPoolId.objectId, + this->globalPoolId.localPoolId); break; default: break; @@ -70,4 +78,4 @@ protected: const bool aboveIsViolation; }; -#endif /* FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ */ +#endif /* FSFW_MONITORING_ABSLIMITMONITOR_H_ */ diff --git a/monitoring/CMakeLists.txt b/monitoring/CMakeLists.txt new file mode 100644 index 00000000..d26e807c --- /dev/null +++ b/monitoring/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + LimitViolationReporter.cpp + MonitoringMessage.cpp +) \ No newline at end of file diff --git a/monitoring/HasMonitorsIF.h b/monitoring/HasMonitorsIF.h index 85d92b6b..04f63437 100644 --- a/monitoring/HasMonitorsIF.h +++ b/monitoring/HasMonitorsIF.h @@ -1,11 +1,5 @@ -/** - * @file HasMonitorsIF.h - * @brief This file defines the HasMonitorsIF class. - * @date 28.07.2014 - * @author baetz - */ -#ifndef HASMONITORSIF_H_ -#define HASMONITORSIF_H_ +#ifndef FSFW_MONITORING_HASMONITORSIF_H_ +#define FSFW_MONITORING_HASMONITORSIF_H_ #include "../events/EventReportingProxyIF.h" #include "../objectmanager/ObjectManagerIF.h" @@ -27,4 +21,4 @@ public: } }; -#endif /* HASMONITORSIF_H_ */ +#endif /* FSFW_MONITORING_HASMONITORSIF_H_ */ diff --git a/monitoring/LimitMonitor.h b/monitoring/LimitMonitor.h index 66e6725e..c4448ced 100644 --- a/monitoring/LimitMonitor.h +++ b/monitoring/LimitMonitor.h @@ -12,13 +12,15 @@ template class LimitMonitor: public MonitorBase { public: - LimitMonitor(object_id_t reporterId, uint8_t monitorId, uint32_t parameterId, - uint16_t confirmationLimit, T lowerLimit, T upperLimit, - Event belowLowEvent = MonitoringIF::VALUE_BELOW_LOW_LIMIT, + LimitMonitor(object_id_t reporterId, uint8_t monitorId, + gp_id_t globalPoolId, uint16_t confirmationLimit, T lowerLimit, + T upperLimit, Event belowLowEvent = + MonitoringIF::VALUE_BELOW_LOW_LIMIT, Event aboveHighEvent = MonitoringIF::VALUE_ABOVE_HIGH_LIMIT) : - MonitorBase(reporterId, monitorId, parameterId, confirmationLimit), lowerLimit( - lowerLimit), upperLimit(upperLimit), belowLowEvent( - belowLowEvent), aboveHighEvent(aboveHighEvent) { + MonitorBase(reporterId, monitorId, globalPoolId, + confirmationLimit), + lowerLimit(lowerLimit), upperLimit(upperLimit), + belowLowEvent(belowLowEvent), aboveHighEvent(aboveHighEvent) { } virtual ~LimitMonitor() { } @@ -41,7 +43,7 @@ public: ReturnValue_t result = this->MonitorBase::getParameter(domainId, parameterId, parameterWrapper, newValues, startAtIndex); //We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there. - if (result != this->INVALID_MATRIX_ID) { + if (result != this->INVALID_IDENTIFIER_ID) { return result; } switch (parameterId) { @@ -52,12 +54,13 @@ public: parameterWrapper->set(this->upperLimit); break; default: - return this->INVALID_MATRIX_ID; + return this->INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } bool isOutOfLimits() { - if (this->oldState == MonitoringIF::ABOVE_HIGH_LIMIT || this->oldState == MonitoringIF::BELOW_LOW_LIMIT) { + if (this->oldState == MonitoringIF::ABOVE_HIGH_LIMIT or + this->oldState == MonitoringIF::BELOW_LOW_LIMIT) { return true; } else { return false; @@ -76,10 +79,12 @@ protected: void sendTransitionEvent(T currentValue, ReturnValue_t state) { switch (state) { case MonitoringIF::BELOW_LOW_LIMIT: - EventManagerIF::triggerEvent(this->reportingId, belowLowEvent, this->parameterId); + EventManagerIF::triggerEvent(this->reportingId, belowLowEvent, + this->globalPoolId.objectId, this->globalPoolId.localPoolId); break; case MonitoringIF::ABOVE_HIGH_LIMIT: - EventManagerIF::triggerEvent(this->reportingId, aboveHighEvent, this->parameterId); + EventManagerIF::triggerEvent(this->reportingId, aboveHighEvent, + this->globalPoolId.objectId, this->globalPoolId.localPoolId); break; default: break; diff --git a/monitoring/MonitorBase.h b/monitoring/MonitorBase.h index b2d0e6cb..530a3840 100644 --- a/monitoring/MonitorBase.h +++ b/monitoring/MonitorBase.h @@ -1,39 +1,50 @@ -#ifndef MONITORBASE_H_ -#define MONITORBASE_H_ +#ifndef FSFW_MONITORING_MONITORBASE_H_ +#define FSFW_MONITORING_MONITORBASE_H_ -#include "../datapool/DataSet.h" -#include "../datapool/PIDReader.h" #include "LimitViolationReporter.h" #include "MonitoringIF.h" #include "MonitoringMessageContent.h" #include "MonitorReporter.h" +#include "../datapoollocal/LocalPoolVariable.h" + + /** - * Base class for monitoring of parameters. - * Can be used anywhere, specializations need to implement checkSample and should override sendTransitionEvent. - * Manages state handling, enabling and disabling of events/reports and forwarding of transition - * reports via MonitorReporter. In addition, it provides default implementations for fetching the parameter sample from - * the data pool and a simple confirmation counter. + * @brief Base class for monitoring of parameters. + * @details + * Can be used anywhere, specializations need to implement checkSample and + * should override sendTransitionEvent. + * Manages state handling, enabling and disabling of events/reports and + * forwarding of transition reports via MonitorReporter. + * + * In addition, it provides default implementations for fetching the + * parameter sample from the data pool and a simple confirmation counter. */ template class MonitorBase: public MonitorReporter { public: + MonitorBase(object_id_t reporterId, uint8_t monitorId, - uint32_t parameterId, uint16_t confirmationLimit) : - MonitorReporter(reporterId, monitorId, parameterId, confirmationLimit) { + gp_id_t globalPoolId, uint16_t confirmationLimit): + MonitorReporter(reporterId, monitorId, globalPoolId, + confirmationLimit), + poolVariable(globalPoolId) { } + virtual ~MonitorBase() { } + virtual ReturnValue_t check() { - //1. Fetch sample of type T, return validity. + // 1. Fetch sample of type T, return validity. T sample = 0; ReturnValue_t validity = fetchSample(&sample); - //2. If returning from fetch != OK, parameter is invalid. Report (if oldState is != invalidity). + // 2. If returning from fetch != OK, parameter is invalid. + // Report (if oldState is != invalidity). if (validity != HasReturnvaluesIF::RETURN_OK) { this->monitorStateIs(validity, sample, 0); - //3. Otherwise, check sample. } else { + //3. Otherwise, check sample. this->oldState = doCheck(sample); } return this->oldState; @@ -43,20 +54,25 @@ public: ReturnValue_t currentState = checkSample(sample, &crossedLimit); return this->monitorStateIs(currentState,sample, crossedLimit); } - //Abstract or default. + + // Abstract or default. virtual ReturnValue_t checkSample(T sample, T* crossedLimit) = 0; protected: + virtual ReturnValue_t fetchSample(T* sample) { - DataSet mySet; - PIDReader parameter(this->parameterId, &mySet); - mySet.read(); - if (!parameter.isValid()) { - return MonitoringIF::INVALID; - } - *sample = parameter.value; - return HasReturnvaluesIF::RETURN_OK; + ReturnValue_t result = poolVariable.read(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (not poolVariable.isValid()) { + return MonitoringIF::INVALID; + } + *sample = poolVariable.value; + return HasReturnvaluesIF::RETURN_OK; } + + LocalPoolVar poolVariable; }; -#endif /* MONITORBASE_H_ */ +#endif /* FSFW_MONITORING_MONITORBASE_H_ */ diff --git a/monitoring/MonitorReporter.h b/monitoring/MonitorReporter.h index ca2b534b..9028e7e4 100644 --- a/monitoring/MonitorReporter.h +++ b/monitoring/MonitorReporter.h @@ -1,10 +1,12 @@ -#ifndef FRAMEWORK_MONITORING_MONITORREPORTER_H_ -#define FRAMEWORK_MONITORING_MONITORREPORTER_H_ +#ifndef FSFW_MONITORING_MONITORREPORTER_H_ +#define FSFW_MONITORING_MONITORREPORTER_H_ -#include "../events/EventManagerIF.h" #include "LimitViolationReporter.h" #include "MonitoringIF.h" #include "MonitoringMessageContent.h" + +#include "../datapoollocal/locPoolDefinitions.h" +#include "../events/EventManagerIF.h" #include "../parameters/HasParametersIF.h" template @@ -14,11 +16,14 @@ public: static const uint8_t ENABLED = 1; static const uint8_t DISABLED = 0; - MonitorReporter(object_id_t reportingId, uint8_t monitorId, uint32_t parameterId, uint16_t confirmationLimit) : - monitorId(monitorId), parameterId(parameterId), reportingId( - reportingId), oldState(MonitoringIF::UNCHECKED), reportingEnabled( - ENABLED), eventEnabled(ENABLED), currentCounter(0), confirmationLimit( - confirmationLimit) { + // TODO: Adapt to use SID instead of parameter ID. + + MonitorReporter(object_id_t reportingId, uint8_t monitorId, + gp_id_t globalPoolId, uint16_t confirmationLimit) : + monitorId(monitorId), globalPoolId(globalPoolId), + reportingId(reportingId), oldState(MonitoringIF::UNCHECKED), + reportingEnabled(ENABLED), eventEnabled(ENABLED), currentCounter(0), + confirmationLimit(confirmationLimit) { } virtual ~MonitorReporter() { @@ -63,7 +68,7 @@ public: parameterWrapper->set(this->eventEnabled); break; default: - return INVALID_MATRIX_ID; + return INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } @@ -91,7 +96,7 @@ public: protected: const uint8_t monitorId; - const uint32_t parameterId; + const gp_id_t globalPoolId; object_id_t reportingId; ReturnValue_t oldState; @@ -148,7 +153,8 @@ protected: case HasReturnvaluesIF::RETURN_OK: break; default: - EventManagerIF::triggerEvent(reportingId, MonitoringIF::MONITOR_CHANGED_STATE, state); + EventManagerIF::triggerEvent(reportingId, + MonitoringIF::MONITOR_CHANGED_STATE, state); break; } } @@ -159,14 +165,15 @@ protected: * @param crossedLimit The limit crossed (if applicable). * @param state Current state the monitor is in. */ - virtual void sendTransitionReport(T parameterValue, T crossedLimit, ReturnValue_t state) { - MonitoringReportContent report(parameterId, + virtual void sendTransitionReport(T parameterValue, T crossedLimit, + ReturnValue_t state) { + MonitoringReportContent report(globalPoolId, parameterValue, crossedLimit, oldState, state); LimitViolationReporter::sendLimitViolationReport(&report); } ReturnValue_t setToState(ReturnValue_t state) { if (oldState != state && reportingEnabled) { - MonitoringReportContent report(parameterId, 0, 0, oldState, + MonitoringReportContent report(globalPoolId, 0, 0, oldState, state); LimitViolationReporter::sendLimitViolationReport(&report); oldState = state; @@ -175,4 +182,4 @@ protected: } }; -#endif /* FRAMEWORK_MONITORING_MONITORREPORTER_H_ */ +#endif /* FSFW_MONITORING_MONITORREPORTER_H_ */ diff --git a/monitoring/MonitoringIF.h b/monitoring/MonitoringIF.h index 44218c36..32c62530 100644 --- a/monitoring/MonitoringIF.h +++ b/monitoring/MonitoringIF.h @@ -1,8 +1,8 @@ -#ifndef MONITORINGIF_H_ -#define MONITORINGIF_H_ +#ifndef FSFW_MONITORING_MONITORINGIF_H_ +#define FSFW_MONITORING_MONITORINGIF_H_ -#include "../memory/HasMemoryIF.h" #include "MonitoringMessage.h" +#include "../memory/HasMemoryIF.h" #include "../serialize/SerializeIF.h" class MonitoringIF : public SerializeIF { @@ -15,10 +15,10 @@ public: static const uint8_t LIMIT_TYPE_OBJECT = 128; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_2; - static const Event MONITOR_CHANGED_STATE = MAKE_EVENT(1, SEVERITY::LOW); - static const Event VALUE_BELOW_LOW_LIMIT = MAKE_EVENT(2, SEVERITY::LOW); - static const Event VALUE_ABOVE_HIGH_LIMIT = MAKE_EVENT(3, SEVERITY::LOW); - static const Event VALUE_OUT_OF_RANGE = MAKE_EVENT(4, SEVERITY::LOW); + static const Event MONITOR_CHANGED_STATE = MAKE_EVENT(1, severity::LOW); + static const Event VALUE_BELOW_LOW_LIMIT = MAKE_EVENT(2, severity::LOW); + static const Event VALUE_ABOVE_HIGH_LIMIT = MAKE_EVENT(3, severity::LOW); + static const Event VALUE_OUT_OF_RANGE = MAKE_EVENT(4, severity::LOW); static const uint8_t INTERFACE_ID = CLASS_ID::LIMITS_IF; static const ReturnValue_t UNCHECKED = MAKE_RETURN_CODE(1); @@ -64,4 +64,4 @@ public: -#endif /* MONITORINGIF_H_ */ +#endif /* FSFW_MONITORING_MONITORINGIF_H_ */ diff --git a/monitoring/MonitoringMessageContent.h b/monitoring/MonitoringMessageContent.h index c82506f3..44d32656 100644 --- a/monitoring/MonitoringMessageContent.h +++ b/monitoring/MonitoringMessageContent.h @@ -3,6 +3,7 @@ #include "HasMonitorsIF.h" #include "MonitoringIF.h" +#include "../datapoollocal/locPoolDefinitions.h" #include "../objectmanager/ObjectManagerIF.h" #include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialFixedArrayListAdapter.h" @@ -16,12 +17,17 @@ void setStaticFrameworkObjectIds(); } //PID(uint32_t), TYPE, LIMIT_ID, value,limitValue, previous, later, timestamp +/** + * @brief Does magic. + * @tparam T + */ template class MonitoringReportContent: public SerialLinkedListAdapter { friend void (Factory::setStaticFrameworkObjectIds)(); public: SerializeElement monitorId; - SerializeElement parameterId; + SerializeElement parameterObjectId; + SerializeElement localPoolId; SerializeElement parameterValue; SerializeElement limitValue; SerializeElement oldState; @@ -30,20 +36,23 @@ public: SerializeElement> timestampSerializer; TimeStamperIF* timeStamper; MonitoringReportContent() : - SerialLinkedListAdapter( - LinkedElement::Iterator(¶meterId)), monitorId(0), parameterId( - 0), parameterValue(0), limitValue(0), oldState(0), newState( - 0), rawTimestamp( { 0 }), timestampSerializer(rawTimestamp, + SerialLinkedListAdapter(¶meterObjectId), + monitorId(0), parameterObjectId(0), + localPoolId(0), parameterValue(0), + limitValue(0), oldState(0), newState(0), + rawTimestamp( { 0 }), timestampSerializer(rawTimestamp, sizeof(rawTimestamp)), timeStamper(NULL) { setAllNext(); } - MonitoringReportContent(uint32_t setPID, T value, T limitValue, + MonitoringReportContent(gp_id_t globalPoolId, T value, T limitValue, ReturnValue_t oldState, ReturnValue_t newState) : - SerialLinkedListAdapter( - LinkedElement::Iterator(¶meterId)), monitorId(0), parameterId( - setPID), parameterValue(value), limitValue(limitValue), oldState( - oldState), newState(newState), timestampSerializer(rawTimestamp, - sizeof(rawTimestamp)), timeStamper(NULL) { + SerialLinkedListAdapter(¶meterObjectId), + monitorId(0), parameterObjectId(globalPoolId.objectId), + localPoolId(globalPoolId.localPoolId), + parameterValue(value), limitValue(limitValue), + oldState(oldState), newState(newState), + timestampSerializer(rawTimestamp, sizeof(rawTimestamp)), + timeStamper(NULL) { setAllNext(); if (checkAndSetStamper()) { timeStamper->addTimeStamp(rawTimestamp, sizeof(rawTimestamp)); @@ -53,16 +62,16 @@ private: static object_id_t timeStamperId; void setAllNext() { - parameterId.setNext(¶meterValue); + parameterObjectId.setNext(¶meterValue); parameterValue.setNext(&limitValue); limitValue.setNext(&oldState); oldState.setNext(&newState); newState.setNext(×tampSerializer); } bool checkAndSetStamper() { - if (timeStamper == NULL) { + if (timeStamper == nullptr) { timeStamper = objectManager->get( timeStamperId ); - if ( timeStamper == NULL ) { + if ( timeStamper == nullptr ) { sif::error << "MonitoringReportContent::checkAndSetStamper: " "Stamper not found!" << std::endl; return false; diff --git a/monitoring/TriplexMonitor.h b/monitoring/TriplexMonitor.h index 9b60aeb6..c4b3c537 100644 --- a/monitoring/TriplexMonitor.h +++ b/monitoring/TriplexMonitor.h @@ -82,7 +82,7 @@ public: parameterWrapper->set(limit); break; default: - return INVALID_MATRIX_ID; + return INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/objectmanager/CMakeLists.txt b/objectmanager/CMakeLists.txt new file mode 100644 index 00000000..72aaec89 --- /dev/null +++ b/objectmanager/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ObjectManager.cpp + SystemObject.cpp +) \ No newline at end of file diff --git a/objectmanager/frameworkObjects.h b/objectmanager/frameworkObjects.h index 4d08f084..57783286 100644 --- a/objectmanager/frameworkObjects.h +++ b/objectmanager/frameworkObjects.h @@ -6,6 +6,7 @@ enum framework_objects { // Default verification reporter. PUS_SERVICE_1_VERIFICATION = 0x53000001, PUS_SERVICE_2_DEVICE_ACCESS = 0x53000002, + PUS_SERVICE_3_HOUSEKEEPING = 0x53000003, PUS_SERVICE_5_EVENT_REPORTING = 0x53000005, PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008, PUS_SERVICE_9_TIME_MGMT = 0x53000009, diff --git a/osal/CMakeLists.txt b/osal/CMakeLists.txt new file mode 100644 index 00000000..02ff2405 --- /dev/null +++ b/osal/CMakeLists.txt @@ -0,0 +1,34 @@ +# Check the OS_FSFW variable +if(${OS_FSFW} STREQUAL "freertos") + add_subdirectory(FreeRTOS) +elseif(${OS_FSFW} STREQUAL "rtems") + add_subdirectory(rtems) +elseif(${OS_FSFW} STREQUAL "linux") + add_subdirectory(linux) +elseif(${OS_FSFW} STREQUAL "host") + add_subdirectory(host) + if (WIN32) + add_subdirectory(windows) + elseif(UNIX) + target_sources(${LIB_FSFW_NAME} + PUBLIC + linux/TcUnixUdpPollingTask.cpp + linux/TmTcUnixUdpBridge.cpp + ) + endif () + +else() + + message(WARNING "The OS_FSFW variable was not set. Assuming host OS..") + # Not set. Assumuing this is a host build, try to determine host OS + if (WIN32) + add_subdirectory(host) + add_subdirectory(windows) + elseif (UNIX) + add_subdirectory(linux) + else () + # MacOS or other OSes have not been tested yet / are not supported. + message(FATAL_ERROR "The host OS could not be determined! Aborting.") + endif() + +endif() \ No newline at end of file diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index 4b7fe3eb..eb735185 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -13,7 +13,7 @@ extern "C" { * Architecture dependant portmacro.h function call. * Should be implemented in bsp. */ -extern void vRequestContextSwitchFromISR(); +extern "C" void vRequestContextSwitchFromISR(); /*! * Used by functions to tell if they are being called from diff --git a/osal/host/CMakeLists.txt b/osal/host/CMakeLists.txt new file mode 100644 index 00000000..d73e6f27 --- /dev/null +++ b/osal/host/CMakeLists.txt @@ -0,0 +1,21 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + Clock.cpp + FixedTimeslotTask.cpp + MessageQueue.cpp + Mutex.cpp + MutexFactory.cpp + PeriodicTask.cpp + QueueFactory.cpp + QueueMapManager.cpp + SemaphoreFactory.cpp + TaskFactory.cpp +) + +if(UNIX) + add_definitions(-pthread) + target_link_libraries(${LIB_FSFW_NAME} + PRIVATE + rt + ) +endif() \ No newline at end of file diff --git a/osal/host/FixedTimeslotTask.cpp b/osal/host/FixedTimeslotTask.cpp index e78c974a..9e892bb5 100644 --- a/osal/host/FixedTimeslotTask.cpp +++ b/osal/host/FixedTimeslotTask.cpp @@ -46,7 +46,7 @@ FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority, << GetLastError() << std::endl; } #elif defined(LINUX) - // we can just copy and paste the code from linux here. + // TODO: we can just copy and paste the code from the linux OSAL here. #endif } @@ -115,8 +115,9 @@ void FixedTimeslotTask::taskFunctionality() { this->pollingSeqTable.executeAndAdvance(); if (not pollingSeqTable.slotFollowsImmediately()) { // we need to wait before executing the current slot - //this gives us the time to wait: - interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs()); + // this gives us the time to wait: + interval = chron_ms( + this->pollingSeqTable.getIntervalToPreviousSlotMs()); delayForInterval(¤tStartTime, interval); //TODO deadline missed check } diff --git a/osal/host/FixedTimeslotTask.h b/osal/host/FixedTimeslotTask.h index 9985e2ee..f3fffd0f 100644 --- a/osal/host/FixedTimeslotTask.h +++ b/osal/host/FixedTimeslotTask.h @@ -74,7 +74,7 @@ protected: //!< Typedef for the List of objects. typedef std::vector ObjectList; std::thread mainThread; - std::atomic terminateThread = false; + std::atomic terminateThread { false }; //! Polling sequence table which contains the object to execute //! and information like the timeslots and the passed execution step. diff --git a/osal/host/MessageQueue.cpp b/osal/host/MessageQueue.cpp index bced3713..d662d782 100644 --- a/osal/host/MessageQueue.cpp +++ b/osal/host/MessageQueue.cpp @@ -34,7 +34,7 @@ ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, } ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { - if (this->lastPartner != 0) { + if (this->lastPartner != MessageQueueIF::NO_QUEUE) { return sendMessageFrom(this->lastPartner, message, this->getId()); } else { return MessageQueueIF::NO_REPLY_PARTNER; @@ -106,6 +106,7 @@ bool MessageQueue::isDefaultDestinationSet() const { ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault) { + message->setSender(sentFrom); if(message->getMessageSize() > message->getMaximumMessageSize()) { // Actually, this should never happen or an error will be emitted // in MessageQueueMessage. @@ -126,7 +127,6 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, // TODO: Better returnvalue return HasReturnvaluesIF::RETURN_FAILED; } - if(targetQueue->messageQueue.size() < targetQueue->messageDepth) { MutexHelper mutexLock(targetQueue->queueLock, MutexIF::TimeoutType::WAITING, 20); @@ -145,7 +145,6 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, else { return MessageQueueIF::FULL; } - message->setSender(sentFrom); return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/host/Mutex.cpp b/osal/host/Mutex.cpp index 8471cab8..ad8873df 100644 --- a/osal/host/Mutex.cpp +++ b/osal/host/Mutex.cpp @@ -4,21 +4,18 @@ Mutex::Mutex() {} ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) { - if(timeoutMs == MutexIF::BLOCKING) { + if(timeoutType == MutexIF::BLOCKING) { mutex.lock(); - locked = true; return HasReturnvaluesIF::RETURN_OK; } - else if(timeoutMs == MutexIF::POLLING) { + else if(timeoutType == MutexIF::POLLING) { if(mutex.try_lock()) { - locked = true; return HasReturnvaluesIF::RETURN_OK; } } else if(timeoutMs > MutexIF::POLLING){ auto chronoMs = std::chrono::milliseconds(timeoutMs); if(mutex.try_lock_for(chronoMs)) { - locked = true; return HasReturnvaluesIF::RETURN_OK; } } @@ -26,11 +23,7 @@ ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) { } ReturnValue_t Mutex::unlockMutex() { - if(not locked) { - return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX; - } mutex.unlock(); - locked = false; return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/host/Mutex.h b/osal/host/Mutex.h index 24dafbbd..c0fa19b7 100644 --- a/osal/host/Mutex.h +++ b/osal/host/Mutex.h @@ -22,7 +22,7 @@ public: std::timed_mutex* getMutexHandle(); private: - bool locked = false; + //bool locked = false; std::timed_mutex mutex; }; diff --git a/osal/host/PeriodicTask.cpp b/osal/host/PeriodicTask.cpp index f4ee079b..bfa6c3fd 100644 --- a/osal/host/PeriodicTask.cpp +++ b/osal/host/PeriodicTask.cpp @@ -89,25 +89,26 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { } void PeriodicTask::taskFunctionality() { + for (const auto& object: objectList) { + object->initializeAfterTaskCreation(); + } + std::chrono::milliseconds periodChrono(static_cast(period*1000)); auto currentStartTime { std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) }; - auto nextStartTime{ currentStartTime }; + auto nextStartTime { currentStartTime }; /* Enter the loop that defines the task behavior. */ for (;;) { if(terminateThread.load()) { break; } - for (ObjectList::iterator it = objectList.begin(); - it != objectList.end(); ++it) { - (*it)->performOperation(); + for (const auto& object: objectList) { + object->performOperation(); } if(not delayForInterval(¤tStartTime, periodChrono)) { - sif::warning << "PeriodicTask: " << taskName << - " missed deadline!\n" << std::flush; if(deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } @@ -121,6 +122,7 @@ ReturnValue_t PeriodicTask::addComponent(object_id_t object) { if (newObject == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } + newObject->setTaskIF(this); objectList.push_back(newObject); return HasReturnvaluesIF::RETURN_OK; } diff --git a/osal/host/PeriodicTask.h b/osal/host/PeriodicTask.h index 7689788a..00cb6a24 100644 --- a/osal/host/PeriodicTask.h +++ b/osal/host/PeriodicTask.h @@ -69,7 +69,7 @@ protected: //!< Typedef for the List of objects. typedef std::vector ObjectList; std::thread mainThread; - std::atomic terminateThread = false; + std::atomic terminateThread { false }; /** * @brief This attribute holds a list of objects to be executed. diff --git a/osal/host/QueueMapManager.cpp b/osal/host/QueueMapManager.cpp index 1b2094e9..621f46bc 100644 --- a/osal/host/QueueMapManager.cpp +++ b/osal/host/QueueMapManager.cpp @@ -44,7 +44,7 @@ MessageQueueIF* QueueMapManager::getMessageQueue( return queueIter->second; } else { - sif::warning << "QueueMapManager::getQueueHandle: The ID" << + sif::warning << "QueueMapManager::getQueueHandle: The ID " << messageQueueId << " does not exists in the map" << std::endl; return nullptr; } diff --git a/osal/linux/CMakeLists.txt b/osal/linux/CMakeLists.txt new file mode 100644 index 00000000..c0096e42 --- /dev/null +++ b/osal/linux/CMakeLists.txt @@ -0,0 +1,25 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + Clock.cpp + BinarySemaphore.cpp + CountingSemaphore.cpp + FixedTimeslotTask.cpp + InternalErrorCodes.cpp + MessageQueue.cpp + Mutex.cpp + MutexFactory.cpp + PeriodicPosixTask.cpp + PosixThread.cpp + QueueFactory.cpp + SemaphoreFactory.cpp + TaskFactory.cpp + TcUnixUdpPollingTask.cpp + TmTcUnixUdpBridge.cpp + Timer.cpp +) + +target_link_libraries(${LIB_FSFW_NAME} + PRIVATE + rt + pthread +) diff --git a/osal/linux/TcUnixUdpPollingTask.cpp b/osal/linux/TcUnixUdpPollingTask.cpp index 7df56a95..af99ec91 100644 --- a/osal/linux/TcUnixUdpPollingTask.cpp +++ b/osal/linux/TcUnixUdpPollingTask.cpp @@ -45,8 +45,8 @@ ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { continue; } - sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived - << " bytes received" << std::endl; +// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived +// << " bytes received" << std::endl; ReturnValue_t result = handleSuccessfullTcRead(bytesReceived); if(result != HasReturnvaluesIF::RETURN_FAILED) { diff --git a/osal/linux/TmTcUnixUdpBridge.cpp b/osal/linux/TmTcUnixUdpBridge.cpp index 71a39384..ab28623e 100644 --- a/osal/linux/TmTcUnixUdpBridge.cpp +++ b/osal/linux/TmTcUnixUdpBridge.cpp @@ -73,9 +73,9 @@ ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { clientAddressLen = sizeof(serverAddress); } - char ipAddress [15]; - sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, - &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; +// char ipAddress [15]; +// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, +// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags, reinterpret_cast(&clientAddress), clientAddressLen); diff --git a/osal/rtems/Clock.cpp b/osal/rtems/Clock.cpp index eeffd7f3..e5f37ec6 100644 --- a/osal/rtems/Clock.cpp +++ b/osal/rtems/Clock.cpp @@ -3,7 +3,7 @@ #include uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; +MutexIF* Clock::timeMutex = nullptr; uint32_t Clock::getTicksPerSecond(void){ rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); @@ -40,7 +40,7 @@ ReturnValue_t Clock::setClock(const timeval* time) { //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,NULL); + _TOD_Set(&newTime,nullptr); return HasReturnvaluesIF::RETURN_OK; } @@ -131,7 +131,7 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == NULL) { + if (timeMutex == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } @@ -157,40 +157,34 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + MutexHelper helper(timeMutex); + leapSeconds = leapSeconds_; - result = timeMutex->unlockMutex(); - return result; + + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { - if(timeMutex==NULL){ + if(timeMutex==nullptr){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::NO_TIMEOUT); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + MutexHelper helper(timeMutex); *leapSeconds_ = leapSeconds; - result = timeMutex->unlockMutex(); - return result; + return HasReturnvaluesIF::RETURN_OK; } 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/rtems/CpuUsage.cpp b/osal/rtems/CpuUsage.cpp index d49de4ad..6655c69b 100644 --- a/osal/rtems/CpuUsage.cpp +++ b/osal/rtems/CpuUsage.cpp @@ -158,7 +158,7 @@ uint32_t CpuUsage::ThreadData::getSerializedSize() const { } ReturnValue_t CpuUsage::ThreadData::deSerialize(const uint8_t** buffer, - int32_t* size, Endianness streamEndianness) { + size_t* size, Endianness streamEndianness) { ReturnValue_t result = SerializeAdapter::deSerialize(&id, buffer, size, streamEndianness); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/osal/rtems/InternalErrorCodes.cpp b/osal/rtems/InternalErrorCodes.cpp index 9346cf15..ddf365d5 100644 --- a/osal/rtems/InternalErrorCodes.cpp +++ b/osal/rtems/InternalErrorCodes.cpp @@ -12,8 +12,8 @@ ReturnValue_t InternalErrorCodes::translate(uint8_t code) { // return INVALID_WORKSPACE_ADDRESS; case INTERNAL_ERROR_TOO_LITTLE_WORKSPACE: return TOO_LITTLE_WORKSPACE; - case INTERNAL_ERROR_WORKSPACE_ALLOCATION: - return WORKSPACE_ALLOCATION; +// case INTERNAL_ERROR_WORKSPACE_ALLOCATION: +// return WORKSPACE_ALLOCATION; // case INTERNAL_ERROR_INTERRUPT_STACK_TOO_SMALL: // return INTERRUPT_STACK_TOO_SMALL; case INTERNAL_ERROR_THREAD_EXITTED: diff --git a/osal/rtems/Interrupt.cpp b/osal/rtems/Interrupt.cpp deleted file mode 100644 index b740f1ca..00000000 --- a/osal/rtems/Interrupt.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "Interrupt.h" -extern "C" { -#include -#include -} -#include "RtemsBasic.h" - - -ReturnValue_t Interrupt::enableInterrupt(InterruptNumber_t interruptNumber) { - volatile uint32_t* irqMask = hw_irq_mask; - uint32_t expectedValue = *irqMask | (1 << interruptNumber); - *irqMask = expectedValue; - uint32_t tempValue = *irqMask; - if (tempValue == expectedValue) { - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t Interrupt::setInterruptServiceRoutine(IsrHandler_t handler, - InterruptNumber_t interrupt, IsrHandler_t* oldHandler) { - IsrHandler_t oldHandler_local; - if (oldHandler == NULL) { - oldHandler = &oldHandler_local; - } - //+ 0x10 comes because of trap type assignment to IRQs in UT699 processor - rtems_status_code status = rtems_interrupt_catch(handler, interrupt + 0x10, - oldHandler); - switch(status){ - case RTEMS_SUCCESSFUL: - //ISR established successfully - return HasReturnvaluesIF::RETURN_OK; - case RTEMS_INVALID_NUMBER: - //illegal vector number - return HasReturnvaluesIF::RETURN_FAILED; - case RTEMS_INVALID_ADDRESS: - //illegal ISR entry point or invalid old_isr_handler - return HasReturnvaluesIF::RETURN_FAILED; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - -} - -ReturnValue_t Interrupt::disableInterrupt(InterruptNumber_t interruptNumber) { - //TODO Not implemented - return HasReturnvaluesIF::RETURN_FAILED; -} - -//SHOULDDO: Make default values (edge, polarity) settable? -ReturnValue_t Interrupt::enableGpioInterrupt(InterruptNumber_t interrupt) { - volatile uint32_t* irqMask = hw_irq_mask; - uint32_t expectedValue = *irqMask | (1 << interrupt); - *irqMask = expectedValue; - uint32_t tempValue = *irqMask; - if (tempValue == expectedValue) { - volatile hw_gpio_port_t* ioPorts = hw_gpio_port; - ioPorts->direction &= ~(1 << interrupt); //Direction In - ioPorts->interrupt_edge |= 1 << interrupt; //Edge triggered - ioPorts->interrupt_polarity |= 1 << interrupt; //Trigger on rising edge - ioPorts->interrupt_mask |= 1 << interrupt; //Enable - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -ReturnValue_t Interrupt::disableGpioInterrupt(InterruptNumber_t interrupt) { - volatile uint32_t* irqMask = hw_irq_mask; - uint32_t expectedValue = *irqMask & ~(1 << interrupt); - *irqMask = expectedValue; - uint32_t tempValue = *irqMask; - if (tempValue == expectedValue) { - //Disable gpio IRQ - volatile hw_gpio_port_t* ioPorts = hw_gpio_port; - ioPorts->interrupt_mask &= ~(1 << interrupt); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -bool Interrupt::isInterruptInProgress() { - return rtems_interrupt_is_in_progress(); -} diff --git a/osal/rtems/Interrupt.h b/osal/rtems/Interrupt.h deleted file mode 100644 index 2152e2f0..00000000 --- a/osal/rtems/Interrupt.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef OS_RTEMS_INTERRUPT_H_ -#define OS_RTEMS_INTERRUPT_H_ - -#include "../../returnvalues/HasReturnvaluesIF.h" -#include -#include - -typedef rtems_isr_entry IsrHandler_t; -typedef rtems_isr IsrReturn_t; -typedef rtems_vector_number InterruptNumber_t; - -class Interrupt { -public: - virtual ~Interrupt(){}; - - /** - * Establishes a new interrupt service routine. - * @param handler The service routine to establish - * @param interrupt The interrupt (NOT trap type) the routine shall react to. - * @return RETURN_OK on success. Otherwise, the OS failure code is returned. - */ - static ReturnValue_t setInterruptServiceRoutine(IsrHandler_t handler, - InterruptNumber_t interrupt, IsrHandler_t *oldHandler = NULL); - static ReturnValue_t enableInterrupt(InterruptNumber_t interruptNumber); - static ReturnValue_t disableInterrupt(InterruptNumber_t interruptNumber); - /** - * Enables the interrupt given. - * The function tests, if the InterruptMask register was written successfully. - * @param interrupt The interrupt to enable. - * @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else. - */ - static ReturnValue_t enableGpioInterrupt(InterruptNumber_t interrupt); - /** - * Disables the interrupt given. - * @param interrupt The interrupt to disable. - * @return RETURN_OK if the interrupt was set successfully. RETURN_FAILED else. - */ - static ReturnValue_t disableGpioInterrupt(InterruptNumber_t interrupt); - - - /** - * Checks if the current executing context is an ISR. - * @return true if handling an interrupt, false else. - */ - static bool isInterruptInProgress(); - -}; - - -#endif /* OS_RTEMS_INTERRUPT_H_ */ diff --git a/osal/rtems/MessageQueue.cpp b/osal/rtems/MessageQueue.cpp index 700db444..839182a6 100644 --- a/osal/rtems/MessageQueue.cpp +++ b/osal/rtems/MessageQueue.cpp @@ -1,14 +1,15 @@ #include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../objectmanager/ObjectManagerIF.h" #include "MessageQueue.h" #include "RtemsBasic.h" #include MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : - id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(NULL) { + id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) { rtems_name name = ('Q' << 24) + (queueCounter++ << 8); rtems_status_code status = rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id)); if (status != RTEMS_SUCCESSFUL) { - error << "MessageQueue::MessageQueue: Creating Queue " << std::hex + sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec << " failed with status:" << (uint32_t) status << std::endl; this->id = 0; @@ -20,15 +21,15 @@ MessageQueue::~MessageQueue() { } ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, bool ignoreFault) { + MessageQueueMessageIF* message, bool ignoreFault) { return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); } -ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { +ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { return sendToDefaultFrom(message, this->getId()); } -ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { +ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { if (this->lastPartner != 0) { return sendMessage(this->lastPartner, message, this->getId()); } else { @@ -36,27 +37,29 @@ ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { } } -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom) { ReturnValue_t status = this->receiveMessage(message); *receivedFrom = this->lastPartner; return status; } -ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { +ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { + size_t size = 0; rtems_status_code status = rtems_message_queue_receive(id, - message->getBuffer(), &(message->messageSize), + message->getBuffer(),&size, RTEMS_NO_WAIT, 1); if (status == RTEMS_SUCCESSFUL) { + message->setMessageSize(size); this->lastPartner = message->getSender(); //Check size of incoming message. - if (message->messageSize < message->getMinimumMessageSize()) { + if (message->getMessageSize() < message->getMinimumMessageSize()) { return HasReturnvaluesIF::RETURN_FAILED; } } else { //No message was received. Keep lastPartner anyway, I might send something later. //But still, delete packet content. - memset(message->getData(), 0, message->MAX_DATA_SIZE); + memset(message->getData(), 0, message->getMaximumMessageSize()); } return convertReturnCode(status); } @@ -79,20 +82,20 @@ void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { } ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault) { message->setSender(sentFrom); rtems_status_code result = rtems_message_queue_send(sendTo, - message->getBuffer(), message->messageSize); + message->getBuffer(), message->getMessageSize()); //TODO: Check if we're in ISR. if (result != RTEMS_SUCCESSFUL && !ignoreFault) { - if (internalErrorReporter == NULL) { + if (internalErrorReporter == nullptr) { internalErrorReporter = objectManager->get( objects::INTERNAL_ERROR_REPORTER); } - if (internalErrorReporter != NULL) { + if (internalErrorReporter != nullptr) { internalErrorReporter->queueMessageNotSent(); } } @@ -105,7 +108,7 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, return returnCode; } -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom, bool ignoreFault) { return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault); } diff --git a/osal/rtems/MessageQueue.h b/osal/rtems/MessageQueue.h index c6fc62d5..342f1e30 100644 --- a/osal/rtems/MessageQueue.h +++ b/osal/rtems/MessageQueue.h @@ -1,14 +1,5 @@ -/** - * @file MessageQueue.h - * - * @date 10/02/2012 - * @author Bastian Baetz - * - * @brief This file contains the definition of the MessageQueue class. - */ - -#ifndef MESSAGEQUEUE_H_ -#define MESSAGEQUEUE_H_ +#ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ +#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ #include "../../internalError/InternalErrorReporterIF.h" #include "../../ipc/MessageQueueIF.h" @@ -60,14 +51,14 @@ public: * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. */ ReturnValue_t sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, bool ignoreFault = false ); + MessageQueueMessageIF* message, bool ignoreFault = false ); /** * @brief This operation sends a message to the default destination. * @details As in the sendMessage method, this function uses the sendToDefault call of the * MessageQueueSender parent class and adds its queue id as "sentFrom" information. * @param message A pointer to a previously created message, which is sent. */ - ReturnValue_t sendToDefault( MessageQueueMessage* message ); + ReturnValue_t sendToDefault( MessageQueueMessageIF* message ); /** * @brief This operation sends a message to the last communication partner. * @details This operation simplifies answering an incoming message by using the stored @@ -75,7 +66,7 @@ public: * (i.e. lastPartner is zero), an error code is returned. * @param message A pointer to a previously created message, which is sent. */ - ReturnValue_t reply( MessageQueueMessage* message ); + ReturnValue_t reply( MessageQueueMessageIF* message ); /** * @brief This function reads available messages from the message queue and returns the sender. @@ -84,7 +75,7 @@ public: * @param message A pointer to a message in which the received data is stored. * @param receivedFrom A pointer to a queue id in which the sender's id is stored. */ - ReturnValue_t receiveMessage(MessageQueueMessage* message, + ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t *receivedFrom); /** @@ -95,7 +86,7 @@ public: * message's content is cleared and the function returns immediately. * @param message A pointer to a message in which the received data is stored. */ - ReturnValue_t receiveMessage(MessageQueueMessage* message); + ReturnValue_t receiveMessage(MessageQueueMessageIF* message); /** * Deletes all pending messages in the queue. * @param count The number of flushed messages. @@ -121,7 +112,7 @@ public: * This variable is set to zero by default. * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. */ - virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); /** * \brief The sendToDefault method sends a queue message to the default destination. * \details In all other aspects, it works identical to the sendMessage method. @@ -129,7 +120,7 @@ public: * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * This variable is set to zero by default. */ - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); /** * \brief This method is a simple setter for the default destination. */ @@ -178,4 +169,4 @@ private: static ReturnValue_t convertReturnCode(rtems_status_code inValue); }; -#endif /* MESSAGEQUEUE_H_ */ +#endif /* FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_ */ diff --git a/osal/rtems/MultiObjectTask.cpp b/osal/rtems/MultiObjectTask.cpp index 2342c24c..970d01e1 100644 --- a/osal/rtems/MultiObjectTask.cpp +++ b/osal/rtems/MultiObjectTask.cpp @@ -30,7 +30,7 @@ ReturnValue_t MultiObjectTask::startTask() { rtems_status_code status = rtems_task_start(id, MultiObjectTask::taskEntryPoint, rtems_task_argument((void *) this)); if (status != RTEMS_SUCCESSFUL) { - error << "ObjectTask::startTask for " << std::hex << this->getId() + sif::error << "ObjectTask::startTask for " << std::hex << this->getId() << std::dec << " failed." << std::endl; } switch(status){ @@ -63,8 +63,8 @@ void MultiObjectTask::taskFunctionality() { char nameSpace[8] = { 0 }; char* ptr = rtems_object_get_name(getId(), sizeof(nameSpace), nameSpace); - error << "ObjectTask: " << ptr << " Deadline missed." << std::endl; - if (this->deadlineMissedFunc != NULL) { + sif::error << "ObjectTask: " << ptr << " Deadline missed." << std::endl; + if (this->deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } } @@ -74,7 +74,7 @@ void MultiObjectTask::taskFunctionality() { ReturnValue_t MultiObjectTask::addComponent(object_id_t object) { ExecutableObjectIF* newObject = objectManager->get( object); - if (newObject == NULL) { + if (newObject == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } objectList.push_back(newObject); diff --git a/osal/rtems/MultiObjectTask.h b/osal/rtems/MultiObjectTask.h index 736e79dd..04d122a3 100644 --- a/osal/rtems/MultiObjectTask.h +++ b/osal/rtems/MultiObjectTask.h @@ -80,7 +80,7 @@ protected: /** * @brief The pointer to the deadline-missed function. * @details This pointer stores the function that is executed if the task's deadline is missed. - * So, each may react individually on a timing failure. The pointer may be NULL, + * So, each may react individually on a timing failure. The pointer may be nullptr, * then nothing happens on missing the deadline. The deadline is equal to the next execution * of the periodic task. */ diff --git a/osal/rtems/Mutex.cpp b/osal/rtems/Mutex.cpp index 9553ac79..a5ec9635 100644 --- a/osal/rtems/Mutex.cpp +++ b/osal/rtems/Mutex.cpp @@ -10,7 +10,7 @@ Mutex::Mutex() : RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0, &mutexId); if (status != RTEMS_SUCCESSFUL) { - error << "Mutex: creation with name, id " << mutexName << ", " << mutexId + sif::error << "Mutex: creation with name, id " << mutexName << ", " << mutexId << " failed with " << status << std::endl; } } @@ -18,24 +18,25 @@ Mutex::Mutex() : Mutex::~Mutex() { rtems_status_code status = rtems_semaphore_delete(mutexId); if (status != RTEMS_SUCCESSFUL) { - error << "Mutex: deletion for id " << mutexId + sif::error << "Mutex: deletion for id " << mutexId << " failed with " << status << std::endl; } } ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType = TimeoutType::BLOCKING, uint32_t timeoutMs) { + rtems_status_code status = RTEMS_INVALID_ID; if(timeoutMs == MutexIF::TimeoutType::BLOCKING) { - rtems_status_code status = rtems_semaphore_obtain(mutexId, + status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, RTEMS_NO_TIMEOUT); } else if(timeoutMs == MutexIF::TimeoutType::POLLING) { timeoutMs = RTEMS_NO_TIMEOUT; - rtems_status_code status = rtems_semaphore_obtain(mutexId, + status = rtems_semaphore_obtain(mutexId, RTEMS_NO_WAIT, 0); } else { - rtems_status_code status = rtems_semaphore_obtain(mutexId, + status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, timeoutMs); } diff --git a/osal/rtems/Mutex.h b/osal/rtems/Mutex.h index 72368210..4c861318 100644 --- a/osal/rtems/Mutex.h +++ b/osal/rtems/Mutex.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_OSAL_RTEMS_MUTEX_H_ -#define FRAMEWORK_OSAL_RTEMS_MUTEX_H_ +#ifndef FSFW_OSAL_RTEMS_MUTEX_H_ +#define FSFW_OSAL_RTEMS_MUTEX_H_ #include "../../ipc/MutexIF.h" #include "RtemsBasic.h" @@ -15,4 +15,4 @@ private: static uint8_t count; }; -#endif /* OS_RTEMS_MUTEX_H_ */ +#endif /* FSFW_OSAL_RTEMS_MUTEX_H_ */ diff --git a/osal/rtems/MutexFactory.cpp b/osal/rtems/MutexFactory.cpp index ea594789..24af5fa9 100644 --- a/osal/rtems/MutexFactory.cpp +++ b/osal/rtems/MutexFactory.cpp @@ -2,7 +2,6 @@ #include "Mutex.h" #include "RtemsBasic.h" -//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); MutexFactory::MutexFactory() { diff --git a/osal/rtems/PollingTask.cpp b/osal/rtems/PollingTask.cpp index 04191515..db7864fe 100644 --- a/osal/rtems/PollingTask.cpp +++ b/osal/rtems/PollingTask.cpp @@ -1,5 +1,6 @@ -#include "../../devicehandlers/FixedSequenceSlot.h" +#include "../../tasks/FixedSequenceSlot.h" #include "../../objectmanager/SystemObjectIF.h" +#include "../../objectmanager/ObjectManagerIF.h" #include "PollingTask.h" #include "RtemsBasic.h" #include "../../returnvalues/HasReturnvaluesIF.h" @@ -34,14 +35,14 @@ rtems_task PollingTask::taskEntryPoint(rtems_task_argument argument) { PollingTask *originalTask(reinterpret_cast(argument)); //The task's functionality is called. originalTask->taskFunctionality(); - debug << "Polling task " << originalTask->getId() + sif::debug << "Polling task " << originalTask->getId() << " returned from taskFunctionality." << std::endl; } void PollingTask::missedDeadlineCounter() { PollingTask::deadlineMissedCount++; if (PollingTask::deadlineMissedCount % 10 == 0) { - error << "PST missed " << PollingTask::deadlineMissedCount + sif::error << "PST missed " << PollingTask::deadlineMissedCount << " deadlines." << std::endl; } } @@ -50,7 +51,7 @@ ReturnValue_t PollingTask::startTask() { rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint, rtems_task_argument((void *) this)); if (status != RTEMS_SUCCESSFUL) { - error << "PollingTask::startTask for " << std::hex << this->getId() + sif::error << "PollingTask::startTask for " << std::hex << this->getId() << std::dec << " failed." << std::endl; } switch(status){ @@ -68,12 +69,13 @@ ReturnValue_t PollingTask::startTask() { ReturnValue_t PollingTask::addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) { - if (objectManager->get(componentId) != nullptr) { - pst.addSlot(componentId, slotTimeMs, executionStep, this); + ExecutableObjectIF* object = objectManager->get(componentId); + if (object != nullptr) { + pst.addSlot(componentId, slotTimeMs, executionStep, object, this); return HasReturnvaluesIF::RETURN_OK; } - error << "Component " << std::hex << componentId << + sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } @@ -90,11 +92,10 @@ ReturnValue_t PollingTask::checkSequence() const { void PollingTask::taskFunctionality() { // A local iterator for the Polling Sequence Table is created to find the start time for the first entry. - std::list::iterator it = pst.current; + FixedSlotSequence::SlotListIter it = pst.current; //The start time for the first entry is read. - rtems_interval interval = RtemsBasic::convertMsToTicks( - (*it)->pollingTimeMs); + rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs); TaskBase::setAndStartPeriod(interval,&periodId); //The task's "infinite" inner loop is entered. while (1) { @@ -107,7 +108,7 @@ void PollingTask::taskFunctionality() { //If the deadline was missed, the deadlineMissedFunc is called. rtems_status_code status = TaskBase::restartPeriod(interval,periodId); if (status == RTEMS_TIMEOUT) { - if (this->deadlineMissedFunc != NULL) { + if (this->deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); } } diff --git a/osal/rtems/PollingTask.h b/osal/rtems/PollingTask.h index 199c34e7..42deaf09 100644 --- a/osal/rtems/PollingTask.h +++ b/osal/rtems/PollingTask.h @@ -1,7 +1,7 @@ -#ifndef POLLINGTASK_H_ -#define POLLINGTASK_H_ +#ifndef FSFW_OSAL_RTEMS_POLLINGTASK_H_ +#define FSFW_OSAL_RTEMS_POLLINGTASK_H_ -#include "../../devicehandlers/FixedSlotSequence.h" +#include "../../tasks/FixedSlotSequence.h" #include "../../tasks/FixedTimeslotTaskIF.h" #include "TaskBase.h" @@ -82,4 +82,4 @@ protected: void taskFunctionality( void ); }; -#endif /* POLLINGTASK_H_ */ +#endif /* FSFW_OSAL_RTEMS_POLLINGTASK_H_ */ diff --git a/osal/rtems/QueueFactory.cpp b/osal/rtems/QueueFactory.cpp index fce55a0e..ff561304 100644 --- a/osal/rtems/QueueFactory.cpp +++ b/osal/rtems/QueueFactory.cpp @@ -1,16 +1,17 @@ #include "../../ipc/QueueFactory.h" +#include "../../ipc/MessageQueueSenderIF.h" #include "MessageQueue.h" #include "RtemsBasic.h" -QueueFactory* QueueFactory::factoryInstance = NULL; +QueueFactory* QueueFactory::factoryInstance = nullptr; ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom,bool ignoreFault) { + MessageQueueMessageIF* message, MessageQueueId_t sentFrom,bool ignoreFault) { //TODO add ignoreFault functionality message->setSender(sentFrom); rtems_status_code result = rtems_message_queue_send(sendTo, message->getBuffer(), - message->messageSize); + message->getMessageSize()); switch(result){ case RTEMS_SUCCESSFUL: //message sent successfully @@ -37,7 +38,7 @@ ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, } QueueFactory* QueueFactory::instance() { - if (factoryInstance == NULL) { + if (factoryInstance == nullptr) { factoryInstance = new QueueFactory; } return factoryInstance; diff --git a/osal/rtems/RtemsBasic.h b/osal/rtems/RtemsBasic.h index 78e0d46e..d0ca5aba 100644 --- a/osal/rtems/RtemsBasic.h +++ b/osal/rtems/RtemsBasic.h @@ -1,5 +1,5 @@ -#ifndef OS_RTEMS_RTEMSBASIC_H_ -#define OS_RTEMS_RTEMSBASIC_H_ +#ifndef FSFW_OSAL_RTEMS_RTEMSBASIC_H_ +#define FSFW_OSAL_RTEMS_RTEMSBASIC_H_ #include "../../returnvalues/HasReturnvaluesIF.h" #include @@ -22,4 +22,4 @@ public: } }; -#endif /* OS_RTEMS_RTEMSBASIC_H_ */ +#endif /* FSFW_OSAL_RTEMS_RTEMSBASIC_H_ */ diff --git a/osal/rtems/TaskBase.cpp b/osal/rtems/TaskBase.cpp index adf6ee70..4e0c8f00 100644 --- a/osal/rtems/TaskBase.cpp +++ b/osal/rtems/TaskBase.cpp @@ -22,7 +22,7 @@ TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size, } ReturnValue_t result = convertReturnCode(status); if (result != HasReturnvaluesIF::RETURN_OK) { - error << "TaskBase::TaskBase: createTask with name " << std::hex + sif::error << "TaskBase::TaskBase: createTask with name " << std::hex << osalName << std::dec << " failed with return code " << (uint32_t) status << std::endl; this->id = 0; diff --git a/osal/rtems/TaskBase.h b/osal/rtems/TaskBase.h index 410d9110..0e186e67 100644 --- a/osal/rtems/TaskBase.h +++ b/osal/rtems/TaskBase.h @@ -1,5 +1,5 @@ -#ifndef TASKBASE_H_ -#define TASKBASE_H_ +#ifndef FSFW_OSAL_RTEMS_TASKBASE_H_ +#define FSFW_OSAL_RTEMS_TASKBASE_H_ #include "RtemsBasic.h" #include "../../tasks/PeriodicTaskIF.h" @@ -44,4 +44,4 @@ private: }; -#endif /* TASKBASE_H_ */ +#endif /* FSFW_OSAL_RTEMS_TASKBASE_H_ */ diff --git a/osal/windows/CMakeLists.txt b/osal/windows/CMakeLists.txt new file mode 100644 index 00000000..b6e76d6a --- /dev/null +++ b/osal/windows/CMakeLists.txt @@ -0,0 +1,11 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + TcWinUdpPollingTask.cpp + TmTcWinUdpBridge.cpp +) + +target_link_libraries(${LIB_FSFW_NAME} + PRIVATE + wsock32 + ws2_32 +) \ No newline at end of file diff --git a/osal/windows/TmTcWinUdpBridge.cpp b/osal/windows/TmTcWinUdpBridge.cpp index 7e283c2a..1f66290f 100644 --- a/osal/windows/TmTcWinUdpBridge.cpp +++ b/osal/windows/TmTcWinUdpBridge.cpp @@ -6,6 +6,7 @@ TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId, uint16_t serverPort, uint16_t clientPort): TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { mutex = MutexFactory::instance()->createMutex(); + communicationLinkUp = false; // Initiates Winsock DLL. WSAData wsaData; @@ -90,7 +91,6 @@ ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { // sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were" // " sent." << std::endl; return HasReturnvaluesIF::RETURN_OK; - return HasReturnvaluesIF::RETURN_OK; } void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { @@ -101,6 +101,7 @@ void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { // &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; + registerCommConnect(); // Set new IP address if it has changed. if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) { @@ -114,7 +115,7 @@ void TmTcWinUdpBridge::handleSocketError() { switch(errCode) { case(WSANOTINITIALISED): { sif::info << "TmTcWinUdpBridge::handleSocketError: WSANOTINITIALISED: " - << "WSAStartup(...) call " << "necessary" << std::endl; + << "WSAStartup(...) call necessary" << std::endl; break; } default: { @@ -154,11 +155,11 @@ void TmTcWinUdpBridge::handleSendError() { switch(errCode) { case(WSANOTINITIALISED): { sif::info << "TmTcWinUdpBridge::handleSendError: WSANOTINITIALISED: " - << "WSAStartup(...) call " << "necessary" << std::endl; + << "WSAStartup(...) call necessary" << std::endl; break; } case(WSAEADDRNOTAVAIL): { - sif::info << "TmTcWinUdpBridge::handleReadError: WSAEADDRNOTAVAIL: " + sif::info << "TmTcWinUdpBridge::handleSendError: WSAEADDRNOTAVAIL: " << "Check target address. " << std::endl; break; } diff --git a/parameters/CMakeLists.txt b/parameters/CMakeLists.txt new file mode 100644 index 00000000..fb5e4590 --- /dev/null +++ b/parameters/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ParameterHelper.cpp + ParameterMessage.cpp + ParameterWrapper.cpp +) \ No newline at end of file diff --git a/parameters/HasParametersIF.h b/parameters/HasParametersIF.h index 005403fa..19c12d81 100644 --- a/parameters/HasParametersIF.h +++ b/parameters/HasParametersIF.h @@ -1,12 +1,16 @@ #ifndef FSFW_PARAMETERS_HASPARAMETERSIF_H_ #define FSFW_PARAMETERS_HASPARAMETERSIF_H_ -#include "../parameters/ParameterWrapper.h" +#include "ParameterWrapper.h" #include "../returnvalues/HasReturnvaluesIF.h" -#include +#include -/** Each parameter is identified with a unique parameter ID */ -typedef uint32_t ParameterId_t; +/** + * Each parameter is identified with a unique parameter ID + * The first byte of the parameter ID will denote the domain ID. + * The second and third byte will be the unique identifier number. + */ +using ParameterId_t = uint32_t; /** * @brief This interface is used by components which have modifiable @@ -16,16 +20,15 @@ typedef uint32_t ParameterId_t; * ID is the domain ID which can be used to identify unqiue spacecraft domains * (e.g. control and sensor domain in the AOCS controller). * - * The second and third byte represent the matrix ID, which can represent - * a 8-bit row and column number and the last byte... + * The second byte is a unique identfier ID. * - * Yeah, it it matrix ID oder parameter ID now and is index a 16 bit number - * of a 8 bit number now? + * The third and fourth byte can be used as a linear index for matrix or array + * parameter entries. */ class HasParametersIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::HAS_PARAMETERS_IF; - static const ReturnValue_t INVALID_MATRIX_ID = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t INVALID_IDENTIFIER_ID = MAKE_RETURN_CODE(0x01); static const ReturnValue_t INVALID_DOMAIN_ID = MAKE_RETURN_CODE(0x02); static const ReturnValue_t INVALID_VALUE = MAKE_RETURN_CODE(0x03); static const ReturnValue_t READ_ONLY = MAKE_RETURN_CODE(0x05); @@ -34,33 +37,45 @@ public: return id >> 24; } - static uint16_t getMatrixId(ParameterId_t id) { - return id >> 8; + static uint8_t getUniqueIdentifierId(ParameterId_t id) { + return id >> 16; } - static uint8_t getIndex(ParameterId_t id) { + /** + * Get the index of a parameter. Please note that the index is always a + * linear index. For a vector, this is straightforward. + * For a matrix, the linear indexing run from left to right, top to bottom. + * @param id + * @return + */ + static uint16_t getIndex(ParameterId_t id) { return id; } - static uint32_t getFullParameterId(uint8_t domainId, uint16_t parameterId, - uint8_t index) { - return (domainId << 24) + (parameterId << 8) + index; + static uint32_t getFullParameterId(uint8_t domainId, + uint8_t uniqueIdentifier, uint16_t linearIndex) { + return (domainId << 24) + (uniqueIdentifier << 16) + linearIndex; } virtual ~HasParametersIF() {} /** + * This is the generic function overriden by child classes to set + * parameters. To set a parameter, the parameter wrapper is used with + * a variety of set functions. The provided values can be checked with + * newValues. * Always set parameter before checking newValues! * * @param domainId * @param parameterId * @param parameterWrapper * @param newValues - * @param startAtIndex + * @param startAtIndex Linear index, runs left to right, top to bottom for + * matrix indexes. * @return */ - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, + virtual ReturnValue_t getParameter(uint8_t domainId, + uint16_t uniqueIdentifier, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex) = 0; }; diff --git a/parameters/ParameterHelper.cpp b/parameters/ParameterHelper.cpp index 659b00de..23d1a1f3 100644 --- a/parameters/ParameterHelper.cpp +++ b/parameters/ParameterHelper.cpp @@ -2,131 +2,133 @@ #include "ParameterMessage.h" #include "../objectmanager/ObjectManagerIF.h" -ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner) : - owner(owner) {} +ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner): + owner(owner) {} ParameterHelper::~ParameterHelper() { } ReturnValue_t ParameterHelper::handleParameterMessage(CommandMessage *message) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - switch (message->getCommand()) { - case ParameterMessage::CMD_PARAMETER_DUMP: { - ParameterWrapper description; - uint8_t domain = HasParametersIF::getDomain( - ParameterMessage::getParameterId(message)); - uint16_t parameterId = HasParametersIF::getMatrixId( - ParameterMessage::getParameterId(message)); - result = owner->getParameter(domain, parameterId, - &description, &description, 0); - if (result == HasReturnvaluesIF::RETURN_OK) { - result = sendParameter(message->getSender(), - ParameterMessage::getParameterId(message), &description); - } - } - break; - case ParameterMessage::CMD_PARAMETER_LOAD: { - uint8_t domain = HasParametersIF::getDomain( - ParameterMessage::getParameterId(message)); - uint16_t parameterId = HasParametersIF::getMatrixId( - ParameterMessage::getParameterId(message)); - uint8_t index = HasParametersIF::getIndex( - ParameterMessage::getParameterId(message)); + if(storage == nullptr) { + // ParameterHelper was not initialized + return HasReturnvaluesIF::RETURN_FAILED; + } - const uint8_t *storedStream = nullptr; - size_t storedStreamSize = 0; - result = storage->getData( - ParameterMessage::getStoreId(message), &storedStream, - &storedStreamSize); - if (result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "ParameterHelper::handleParameterMessage: Getting" - " store data failed for load command." << std::endl; - break; - } + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + switch (message->getCommand()) { + case ParameterMessage::CMD_PARAMETER_DUMP: { + ParameterWrapper description; + uint8_t domain = HasParametersIF::getDomain( + ParameterMessage::getParameterId(message)); + uint8_t uniqueIdentifier = HasParametersIF::getUniqueIdentifierId( + ParameterMessage::getParameterId(message)); + result = owner->getParameter(domain, uniqueIdentifier, + &description, &description, 0); + if (result == HasReturnvaluesIF::RETURN_OK) { + result = sendParameter(message->getSender(), + ParameterMessage::getParameterId(message), &description); + } + } + break; + case ParameterMessage::CMD_PARAMETER_LOAD: { + ParameterId_t parameterId = 0; + uint8_t ptc = 0; + uint8_t pfc = 0; + uint8_t rows = 0; + uint8_t columns = 0; + store_address_t storeId = ParameterMessage::getParameterLoadCommand( + message, ¶meterId, &ptc, &pfc, &rows, &columns); + Type type(Type::getActualType(ptc, pfc)); - ParameterWrapper streamWrapper; - result = streamWrapper.set(storedStream, storedStreamSize); - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(ParameterMessage::getStoreId(message)); - break; - } + uint8_t domain = HasParametersIF::getDomain(parameterId); + uint8_t uniqueIdentifier = HasParametersIF::getUniqueIdentifierId( + parameterId); + uint16_t linearIndex = HasParametersIF::getIndex(parameterId); - ParameterWrapper ownerWrapper; - result = owner->getParameter(domain, parameterId, &ownerWrapper, - &streamWrapper, index); - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(ParameterMessage::getStoreId(message)); - break; - } + ConstStorageAccessor accessor(storeId); + result = storage->getData(storeId, accessor); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "ParameterHelper::handleParameterMessage: Getting" + << " store data failed for load command." << std::endl; + break; + } - result = ownerWrapper.copyFrom(&streamWrapper, index); + ParameterWrapper streamWrapper; + result = streamWrapper.set(type, rows, columns, accessor.data(), + accessor.size()); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - storage->deleteData(ParameterMessage::getStoreId(message)); + ParameterWrapper ownerWrapper; + result = owner->getParameter(domain, uniqueIdentifier, &ownerWrapper, + &streamWrapper, linearIndex); - if (result == HasReturnvaluesIF::RETURN_OK) { - result = sendParameter(message->getSender(), - ParameterMessage::getParameterId(message), &ownerWrapper); - } - } - break; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } + result = ownerWrapper.copyFrom(&streamWrapper, linearIndex); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - if (result != HasReturnvaluesIF::RETURN_OK) { - rejectCommand(message->getSender(), result, message->getCommand()); - } + result = sendParameter(message->getSender(), + ParameterMessage::getParameterId(message), &ownerWrapper); + break; + } + default: + return HasReturnvaluesIF::RETURN_FAILED; + } - return HasReturnvaluesIF::RETURN_OK; + if (result != HasReturnvaluesIF::RETURN_OK) { + rejectCommand(message->getSender(), result, message->getCommand()); + } + + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t ParameterHelper::sendParameter(MessageQueueId_t to, uint32_t id, - const ParameterWrapper* description) { - size_t serializedSize = description->getSerializedSize(); + const ParameterWrapper* description) { + size_t serializedSize = description->getSerializedSize(); - uint8_t *storeElement; - store_address_t address; + uint8_t *storeElement; + store_address_t address; - ReturnValue_t result = storage->getFreeElement(&address, serializedSize, - &storeElement); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + ReturnValue_t result = storage->getFreeElement(&address, serializedSize, + &storeElement); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - size_t storeElementSize = 0; + size_t storeElementSize = 0; - result = description->serialize(&storeElement, &storeElementSize, - serializedSize, SerializeIF::Endianness::BIG); + result = description->serialize(&storeElement, &storeElementSize, + serializedSize, SerializeIF::Endianness::BIG); - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(address); - return result; - } + if (result != HasReturnvaluesIF::RETURN_OK) { + storage->deleteData(address); + return result; + } - CommandMessage reply; + CommandMessage reply; - ParameterMessage::setParameterDumpReply(&reply, id, address); + ParameterMessage::setParameterDumpReply(&reply, id, address); - MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId); + MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId); - return HasReturnvaluesIF::RETURN_OK; + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t ParameterHelper::initialize() { - ownerQueueId = owner->getCommandQueue(); + ownerQueueId = owner->getCommandQueue(); - - storage = objectManager->get(objects::IPC_STORE); - if (storage == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } else { - return HasReturnvaluesIF::RETURN_OK; - } + storage = objectManager->get(objects::IPC_STORE); + if (storage == nullptr) { + return ObjectManagerIF::CHILD_INIT_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; } void ParameterHelper::rejectCommand(MessageQueueId_t to, ReturnValue_t reason, - Command_t initialCommand) { - CommandMessage reply; - reply.setReplyRejected(reason, initialCommand); - MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId); + Command_t initialCommand) { + CommandMessage reply; + reply.setReplyRejected(reason, initialCommand); + MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId); } diff --git a/parameters/ParameterMessage.cpp b/parameters/ParameterMessage.cpp index e9f3191f..af1f9ce8 100644 --- a/parameters/ParameterMessage.cpp +++ b/parameters/ParameterMessage.cpp @@ -25,10 +25,26 @@ void ParameterMessage::setParameterDumpReply(CommandMessage* message, } void ParameterMessage::setParameterLoadCommand(CommandMessage* message, - ParameterId_t id, store_address_t storageID) { + ParameterId_t id, store_address_t storeId, uint8_t ptc, uint8_t pfc, + uint8_t rows = 1, uint8_t columns = 1) { message->setCommand(CMD_PARAMETER_LOAD); message->setParameter(id); - message->setParameter2(storageID.raw); + message->setParameter2(storeId.raw); + uint32_t packedParameterSettings = (ptc << 24) | (pfc << 16) | + (rows << 8) | columns; + message->setParameter3(packedParameterSettings); +} + +store_address_t ParameterMessage::getParameterLoadCommand( + const CommandMessage *message, ParameterId_t* parameterId, uint8_t *ptc, + uint8_t *pfc, uint8_t *rows, uint8_t *columns) { + *parameterId = message->getParameter2(); + uint32_t packedParamSettings = message->getParameter3(); + *ptc = packedParamSettings >> 24 & 0xff; + *pfc = packedParamSettings >> 16 & 0xff; + *rows = packedParamSettings >> 8 & 0xff; + *columns = packedParamSettings & 0xff; + return message->getParameter2(); } void ParameterMessage::clear(CommandMessage* message) { diff --git a/parameters/ParameterMessage.h b/parameters/ParameterMessage.h index 31d7fe0b..fd4481ee 100644 --- a/parameters/ParameterMessage.h +++ b/parameters/ParameterMessage.h @@ -5,6 +5,20 @@ #include "../ipc/CommandMessage.h" #include "../storagemanager/StorageManagerIF.h" +/** + * @brief ParameterMessage interface + * @details + * General structure of a parameter message: + * 1. 4-byte Object ID + * 2. 4-byte Parameter ID, first byte is Domain ID, second byte is unique + * identifier, third and fourth byte is linear index to start from + * 3. 4-byte Parameter Settings. First byte and second byte are the PTC and PFC + * ECSS type identifiers (see ECSS-E-ST-70-41C15 p.428 or Type class in + * globalfunctions). Third byte is the number of rows and fourth byte + * is the number of columns. For single variable parameters, this will + * be [1, 1]. + * + */ class ParameterMessage { private: ParameterMessage(); @@ -20,8 +34,27 @@ public: ParameterId_t id); static void setParameterDumpReply(CommandMessage* message, ParameterId_t id, store_address_t storageID); + + /** + * Command to set a load parameter message. The CCSDS / ECSS type in + * form of a PTC and a PFC is expected. See ECSS-E-ST-70-41C15 p.428 + * for all types or the Type class in globalfunctions. + * @param message + * @param id + * @param storeId + * @param ptc Type information according to CCSDS/ECSS standards + * @param pfc Type information according to CCSDS/ECSS standards + * @param rows Set number of rows in parameter set, minimum one. + * @param columns Set number of columns in parameter set, minimum one + */ static void setParameterLoadCommand(CommandMessage* message, - ParameterId_t id, store_address_t storageID); + ParameterId_t id, store_address_t storeId, uint8_t ptc, + uint8_t pfc, uint8_t rows, uint8_t columns); + + static store_address_t getParameterLoadCommand( + const CommandMessage* message, ParameterId_t* parameterId, + uint8_t* ptc, uint8_t* pfc, uint8_t* rows, uint8_t* columns) ; + static void clear(CommandMessage* message); }; diff --git a/parameters/ParameterWrapper.cpp b/parameters/ParameterWrapper.cpp index 6adc6857..d9f1ef68 100644 --- a/parameters/ParameterWrapper.cpp +++ b/parameters/ParameterWrapper.cpp @@ -115,7 +115,7 @@ ReturnValue_t ParameterWrapper::deSerializeData(uint8_t startingRow, uint8_t fromColumns) { //treat from as a continuous Stream as we copy all of it - const uint8_t *fromAsStream = (const uint8_t*) from; + const uint8_t *fromAsStream = reinterpret_cast(from); size_t streamSize = fromRows * fromColumns * sizeof(T); ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; @@ -123,8 +123,9 @@ ReturnValue_t ParameterWrapper::deSerializeData(uint8_t startingRow, for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) { //get the start element of this row in data - T *dataWithDataType = ((T*) data) - + (((startingRow + fromRow) * columns) + startingColumn); + uint16_t offset = (((startingRow + fromRow) * + static_cast(columns)) + startingColumn); + T *dataWithDataType = static_cast(data) + offset; for (uint8_t fromColumn = 0; fromColumn < fromColumns; fromColumn++) { result = SerializeAdapter::deSerialize( @@ -159,6 +160,23 @@ ReturnValue_t ParameterWrapper::deSerialize(const uint8_t **buffer, return copyFrom(&streamDescription, startWritingAtIndex); } +ReturnValue_t ParameterWrapper::set(Type type, uint8_t rows, uint8_t columns, + const void *data, size_t dataSize) { + this->type = type; + this->rows = rows; + this->columns = columns; + + size_t expectedSize = type.getSize() * rows * columns; + if (expectedSize < dataSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + + this->data = nullptr; + this->readonlyData = data; + pointsToStream = true; + return HasReturnvaluesIF::RETURN_OK; +} + ReturnValue_t ParameterWrapper::set(const uint8_t *stream, size_t streamSize, const uint8_t **remainingStream, size_t *remainingSize) { ReturnValue_t result = SerializeAdapter::deSerialize(&type, &stream, @@ -202,11 +220,13 @@ ReturnValue_t ParameterWrapper::set(const uint8_t *stream, size_t streamSize, ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from, uint16_t startWritingAtIndex) { - if (data == NULL) { + // TODO: Optional diagnostic output (which can be disabled in FSFWConfig) + // to determined faulty implementations and configuration errors quickly. + if (data == nullptr) { return READONLY; } - if (from->readonlyData == NULL) { + if (from->readonlyData == nullptr) { return SOURCE_NOT_SET; } @@ -214,9 +234,16 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from, return DATATYPE_MISSMATCH; } + // The smallest allowed value for rows and columns is one. + if(rows == 0 or columns == 0) { + return COLUMN_OR_ROWS_ZERO; + } + //check if from fits into this - uint8_t startingRow = startWritingAtIndex / columns; - uint8_t startingColumn = startWritingAtIndex % columns; + uint8_t startingRow = 0; + uint8_t startingColumn = 0; + ParameterWrapper::convertLinearIndexToRowAndColumn(startWritingAtIndex, + &startingRow, &startingColumn); if ((from->rows > (rows - startingRow)) || (from->columns > (columns - startingColumn))) { @@ -270,8 +297,8 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from, //need a type to do arithmetic uint8_t* typedData = static_cast(data); for (uint8_t fromRow = 0; fromRow < from->rows; fromRow++) { - size_t offset = (((startingRow + fromRow) * columns) + - startingColumn) * typeSize; + size_t offset = (((startingRow + fromRow) * static_cast( + columns)) + startingColumn) * typeSize; std::memcpy(typedData + offset, from->readonlyData, typeSize * from->columns); } @@ -279,3 +306,18 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from, return result; } + +void ParameterWrapper::convertLinearIndexToRowAndColumn(uint16_t index, + uint8_t *row, uint8_t *column) { + if(row == nullptr or column == nullptr) { + return; + } + // Integer division. + *row = index / columns; + *column = index % columns; +} + +uint16_t ParameterWrapper::convertRowAndColumnToLinearIndex(uint8_t row, + uint8_t column) { + return row * columns + column; +} diff --git a/parameters/ParameterWrapper.h b/parameters/ParameterWrapper.h index f07205d4..168a535f 100644 --- a/parameters/ParameterWrapper.h +++ b/parameters/ParameterWrapper.h @@ -22,6 +22,7 @@ public: static const ReturnValue_t SOURCE_NOT_SET = MAKE_RETURN_CODE(0x05); static const ReturnValue_t OUT_OF_BOUNDS = MAKE_RETURN_CODE(0x06); static const ReturnValue_t NOT_SET = MAKE_RETURN_CODE(0x07); + static const ReturnValue_t COLUMN_OR_ROWS_ZERO = MAKE_RETURN_CODE(0x08); ParameterWrapper(); ParameterWrapper(Type type, uint8_t rows, uint8_t columns, void *data); @@ -68,7 +69,7 @@ public: template void set(const T *readonlyData, uint8_t rows, uint8_t columns) { - this->data = NULL; + this->data = nullptr; this->readonlyData = readonlyData; this->type = PodTypeConversion::type; this->rows = rows; @@ -97,14 +98,19 @@ public: } template void setMatrix(T& member) { - this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0])); + this->set(member[0], sizeof(member)/sizeof(member[0]), + sizeof(member[0])/sizeof(member[0][0])); } template void setMatrix(const T& member) { - this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0])); + this->set(member[0], sizeof(member)/sizeof(member[0]), + sizeof(member[0])/sizeof(member[0][0])); } + ReturnValue_t set(Type type, uint8_t rows, uint8_t columns, + const void *data, size_t dataSize); + ReturnValue_t set(const uint8_t *stream, size_t streamSize, const uint8_t **remainingStream = nullptr, size_t *remainingSize = nullptr); @@ -113,6 +119,13 @@ public: uint16_t startWritingAtIndex); private: + + void convertLinearIndexToRowAndColumn(uint16_t index, + uint8_t *row, uint8_t *column); + + uint16_t convertRowAndColumnToLinearIndex(uint8_t row, + uint8_t column); + bool pointsToStream = false; Type type; @@ -148,9 +161,9 @@ inline ReturnValue_t ParameterWrapper::getElement(T *value, uint8_t row, if (pointsToStream) { const uint8_t *streamWithType = static_cast(readonlyData); streamWithType += (row * columns + column) * type.getSize(); - int32_t size = type.getSize(); + size_t size = type.getSize(); return SerializeAdapter::deSerialize(value, &streamWithType, - &size, true); + &size, SerializeIF::Endianness::BIG); } else { const T *dataWithType = static_cast(readonlyData); diff --git a/power/CMakeLists.txt b/power/CMakeLists.txt new file mode 100644 index 00000000..1c625db1 --- /dev/null +++ b/power/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + Fuse.cpp + PowerComponent.cpp + PowerSensor.cpp + PowerSwitcher.cpp +) \ No newline at end of file diff --git a/power/Fuse.cpp b/power/Fuse.cpp index 9986ab6b..1c30d83f 100644 --- a/power/Fuse.cpp +++ b/power/Fuse.cpp @@ -1,22 +1,25 @@ +#include "Fuse.h" + #include "../monitoring/LimitViolationReporter.h" #include "../monitoring/MonitoringMessageContent.h" #include "../objectmanager/ObjectManagerIF.h" -#include "Fuse.h" #include "../serialize/SerialFixedArrayListAdapter.h" #include "../ipc/QueueFactory.h" object_id_t Fuse::powerSwitchId = 0; -Fuse::Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids, +Fuse::Fuse(object_id_t fuseObjectId, uint8_t fuseId, + sid_t variableSet, VariableIds ids, float maxCurrent, uint16_t confirmationCount) : - SystemObject(fuseObjectId), oldFuseState(0), fuseId(fuseId), powerIF( - NULL), currentLimit(fuseObjectId, 1, ids.pidCurrent, confirmationCount, - maxCurrent, FUSE_CURRENT_HIGH), powerMonitor(fuseObjectId, 2, - DataPool::poolIdAndPositionToPid(ids.poolIdPower, 0), - confirmationCount), set(), voltage(ids.pidVoltage, &set), current( - ids.pidCurrent, &set), state(ids.pidState, &set), power( - ids.poolIdPower, &set, PoolVariableIF::VAR_READ_WRITE), commandQueue( - NULL), parameterHelper(this), healthHelper(this, fuseObjectId) { + SystemObject(fuseObjectId), oldFuseState(0), fuseId(fuseId), + currentLimit(fuseObjectId, 1, ids.pidCurrent, confirmationCount, + maxCurrent, FUSE_CURRENT_HIGH), + powerMonitor(fuseObjectId, 2, ids.poolIdPower, + confirmationCount), + set(variableSet), voltage(ids.pidVoltage, &set), + current(ids.pidCurrent, &set), state(ids.pidState, &set), + power(ids.poolIdPower, &set, PoolVariableIF::VAR_READ_WRITE), + parameterHelper(this), healthHelper(this, fuseObjectId) { commandQueue = QueueFactory::instance()->createMessageQueue(); } @@ -75,7 +78,7 @@ ReturnValue_t Fuse::check() { float lowLimit = 0.0; float highLimit = RESIDUAL_POWER; calculatePowerLimits(&lowLimit, &highLimit); - result = powerMonitor.checkPower(power, lowLimit, highLimit); + result = powerMonitor.checkPower(power.value, lowLimit, highLimit); if (result == MonitoringIF::BELOW_LOW_LIMIT) { reportEvents(POWER_BELOW_LOW_LIMIT); } else if (result == MonitoringIF::ABOVE_HIGH_LIMIT) { @@ -109,7 +112,7 @@ size_t Fuse::getSerializedSize() const { } ReturnValue_t Fuse::deSerialize(const uint8_t** buffer, size_t* size, -Endianness streamEndianness) { + Endianness streamEndianness) { ReturnValue_t result = RETURN_FAILED; for (DeviceList::iterator iter = devices.begin(); iter != devices.end(); iter++) { @@ -132,7 +135,7 @@ void Fuse::calculateFusePower() { return; } //Calculate fuse power. - power = current * voltage; + power.value = current.value * voltage.value; power.setValid(PoolVariableIF::VALID); } @@ -190,12 +193,12 @@ void Fuse::checkFuseState() { reportEvents(FUSE_WENT_OFF); } } - oldFuseState = state; + oldFuseState = state.value; } float Fuse::getPower() { if (power.isValid()) { - return power; + return power.value; } else { return 0.0; } diff --git a/power/Fuse.h b/power/Fuse.h index 279642be..b892611b 100644 --- a/power/Fuse.h +++ b/power/Fuse.h @@ -1,16 +1,16 @@ -#ifndef FUSE_H_ -#define FUSE_H_ +#ifndef FSFW_POWER_FUSE_H_ +#define FSFW_POWER_FUSE_H_ -#include "../datapool/DataSet.h" -#include "../datapool/PIDReader.h" -#include "../devicehandlers/HealthDevice.h" -#include "../monitoring/AbsLimitMonitor.h" #include "PowerComponentIF.h" #include "PowerSwitchIF.h" + +#include "../devicehandlers/HealthDevice.h" +#include "../monitoring/AbsLimitMonitor.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../parameters/ParameterHelper.h" #include +#include "../datapoollocal/StaticLocalDataSet.h" namespace Factory { void setStaticFrameworkObjectIds(); } @@ -25,21 +25,21 @@ private: static constexpr float RESIDUAL_POWER = 0.005 * 28.5; //!< This is the upper limit of residual power lost by fuses and switches. Worst case is Fuse and one of two switches on. See PCDU ICD 1.9 p29 bottom public: struct VariableIds { - uint32_t pidVoltage; - uint32_t pidCurrent; - uint32_t pidState; - uint32_t poolIdPower; + gp_id_t pidVoltage; + gp_id_t pidCurrent; + gp_id_t pidState; + gp_id_t poolIdPower; }; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1; - static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, SEVERITY::LOW); //!< PSS detected that current on a fuse is totally out of bounds. - static const Event FUSE_WENT_OFF = MAKE_EVENT(2, SEVERITY::LOW); //!< PSS detected a fuse that went off. - static const Event POWER_ABOVE_HIGH_LIMIT = MAKE_EVENT(4, SEVERITY::LOW); //!< PSS detected a fuse that violates its limits. - static const Event POWER_BELOW_LOW_LIMIT = MAKE_EVENT(5, SEVERITY::LOW); //!< PSS detected a fuse that violates its limits. + static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW); //!< PSS detected that current on a fuse is totally out of bounds. + static const Event FUSE_WENT_OFF = MAKE_EVENT(2, severity::LOW); //!< PSS detected a fuse that went off. + static const Event POWER_ABOVE_HIGH_LIMIT = MAKE_EVENT(4, severity::LOW); //!< PSS detected a fuse that violates its limits. + static const Event POWER_BELOW_LOW_LIMIT = MAKE_EVENT(5, severity::LOW); //!< PSS detected a fuse that violates its limits. typedef std::list DeviceList; - Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids, - float maxCurrent, uint16_t confirmationCount = 2); + Fuse(object_id_t fuseObjectId, uint8_t fuseId, sid_t variableSet, + VariableIds ids, float maxCurrent, uint16_t confirmationCount = 2); virtual ~Fuse(); void addDevice(PowerComponentIF *set); float getPower(); @@ -69,12 +69,12 @@ public: private: uint8_t oldFuseState; uint8_t fuseId; - PowerSwitchIF *powerIF; //could be static in our case. + PowerSwitchIF *powerIF = nullptr; //could be static in our case. AbsLimitMonitor currentLimit; class PowerMonitor: public MonitorReporter { public: template - PowerMonitor(Args ... args) : + PowerMonitor(Args ... args): MonitorReporter(std::forward(args)...) { } ReturnValue_t checkPower(float sample, float lowerLimit, @@ -84,12 +84,14 @@ private: }; PowerMonitor powerMonitor; - DataSet set; - PIDReader voltage; - PIDReader current; - PIDReader state; - db_float_t power; - MessageQueueIF *commandQueue; + StaticLocalDataSet<3> set; + + lp_var_t voltage; + lp_var_t current; + lp_var_t state; + + lp_var_t power; + MessageQueueIF* commandQueue = nullptr; ParameterHelper parameterHelper; HealthHelper healthHelper; static object_id_t powerSwitchId; @@ -102,4 +104,4 @@ private: bool areSwitchesOfComponentOn(DeviceList::iterator iter); }; -#endif /* FUSE_H_ */ +#endif /* FSFW_POWER_FUSE_H_ */ diff --git a/power/PowerComponent.cpp b/power/PowerComponent.cpp index 6012ad4c..c31b9a85 100644 --- a/power/PowerComponent.cpp +++ b/power/PowerComponent.cpp @@ -1,20 +1,15 @@ -/** - * @file PowerComponent.cpp - * @brief This file defines the PowerComponent class. - * @date 28.08.2014 - * @author baetz - */ - #include "PowerComponent.h" +#include "../serialize/SerializeAdapter.h" -PowerComponent::PowerComponent() : - deviceObjectId(0), switchId1(0xFF), switchId2(0xFF), doIHaveTwoSwitches( - false), min(0.0), max(0.0), moduleId(0) { +PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF), + doIHaveTwoSwitches(false) { } -PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, - uint8_t switchId1, bool twoSwitches, uint8_t switchId2) : - deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2), doIHaveTwoSwitches( - twoSwitches), min(min), max(max), moduleId(moduleId) { + +PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min, + float max, uint8_t switchId1, bool twoSwitches, uint8_t switchId2) : + deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2), + doIHaveTwoSwitches(twoSwitches), min(min), max(max), + moduleId(moduleId) { } ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size, @@ -57,7 +52,7 @@ float PowerComponent::getMax() { } ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, size_t* size, -Endianness streamEndianness) { + Endianness streamEndianness) { ReturnValue_t result = SerializeAdapter::deSerialize(&min, buffer, size, streamEndianness); if (result != HasReturnvaluesIF::RETURN_OK) { @@ -80,7 +75,7 @@ ReturnValue_t PowerComponent::getParameter(uint8_t domainId, parameterWrapper->set<>(max); break; default: - return INVALID_MATRIX_ID; + return INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/power/PowerComponent.h b/power/PowerComponent.h index 6d1c9c06..c1add3b9 100644 --- a/power/PowerComponent.h +++ b/power/PowerComponent.h @@ -1,13 +1,17 @@ -#ifndef POWERCOMPONENT_H_ -#define POWERCOMPONENT_H_ +#ifndef FSFW_POWER_POWERCOMPONENT_H_ +#define FSFW_POWER_POWERCOMPONENT_H_ -#include "../objectmanager/SystemObjectIF.h" #include "PowerComponentIF.h" +#include "../objectmanager/frameworkObjects.h" +#include "../objectmanager/SystemObjectIF.h" + + class PowerComponent: public PowerComponentIF { public: - PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, uint8_t switchId1, - bool twoSwitches = false, uint8_t switchId2 = 0xFF); + PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, + uint8_t switchId1, bool twoSwitches = false, + uint8_t switchId2 = 0xFF); virtual object_id_t getDeviceObjectId(); @@ -31,18 +35,18 @@ public: ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex); private: - const object_id_t deviceObjectId; + const object_id_t deviceObjectId = objects::NO_OBJECT; const uint8_t switchId1; const uint8_t switchId2; const bool doIHaveTwoSwitches; - float min; - float max; + float min = 0.0; + float max = 0.0; - uint8_t moduleId; + uint8_t moduleId = 0; PowerComponent(); }; -#endif /* POWERCOMPONENT_H_ */ +#endif /* FSFW_POWER_POWERCOMPONENT_H_ */ diff --git a/power/PowerComponentIF.h b/power/PowerComponentIF.h index c2e3a6a5..f35b4d1d 100644 --- a/power/PowerComponentIF.h +++ b/power/PowerComponentIF.h @@ -1,24 +1,23 @@ -#ifndef POWERCOMPONENTIF_H_ -#define POWERCOMPONENTIF_H_ +#ifndef FSFW_POWER_POWERCOMPONENTIF_H_ +#define FSFW_POWER_POWERCOMPONENTIF_H_ #include "../serialize/SerializeIF.h" #include "../parameters/HasParametersIF.h" +#include "../objectmanager/SystemObjectIF.h" class PowerComponentIF : public SerializeIF, public HasParametersIF { public: - virtual ~PowerComponentIF() { + virtual ~PowerComponentIF() {} - } + virtual object_id_t getDeviceObjectId() = 0; - virtual object_id_t getDeviceObjectId()=0; - - virtual uint8_t getSwitchId1()=0; - virtual uint8_t getSwitchId2()=0; - virtual bool hasTwoSwitches()=0; + virtual uint8_t getSwitchId1() = 0; + virtual uint8_t getSwitchId2() = 0; + virtual bool hasTwoSwitches() = 0; virtual float getMin() = 0; virtual float getMax() = 0; }; -#endif /* POWERCOMPONENTIF_H_ */ +#endif /* FSFW_POWER_POWERCOMPONENTIF_H_ */ diff --git a/power/PowerSensor.cpp b/power/PowerSensor.cpp index 50cb6acd..1ef041e3 100644 --- a/power/PowerSensor.cpp +++ b/power/PowerSensor.cpp @@ -1,14 +1,18 @@ #include "PowerSensor.h" + #include "../ipc/QueueFactory.h" -PowerSensor::PowerSensor(object_id_t setId, VariableIds ids, +PowerSensor::PowerSensor(object_id_t objectId, sid_t setId, VariableIds ids, DefaultLimits limits, SensorEvents events, uint16_t confirmationCount) : - SystemObject(setId), commandQueue(NULL), parameterHelper(this), healthHelper(this, setId), set(), current( - ids.pidCurrent, &set), voltage(ids.pidVoltage, &set), power( - ids.poolIdPower, &set, PoolVariableIF::VAR_WRITE), currentLimit( - setId, MODULE_ID_CURRENT, ids.pidCurrent, confirmationCount, + SystemObject(objectId), parameterHelper(this), + healthHelper(this, objectId), + powerSensorSet(setId), current(ids.pidCurrent, &powerSensorSet), + voltage(ids.pidVoltage, &powerSensorSet), + power(ids.poolIdPower, &powerSensorSet, PoolVariableIF::VAR_WRITE), + currentLimit(objectId, MODULE_ID_CURRENT, ids.pidCurrent, confirmationCount, limits.currentMin, limits.currentMax, events.currentLow, - events.currentHigh), voltageLimit(setId, MODULE_ID_VOLTAGE, + events.currentHigh), + voltageLimit(objectId, MODULE_ID_VOLTAGE, ids.pidVoltage, confirmationCount, limits.voltageMin, limits.voltageMax, events.voltageLow, events.voltageHigh) { commandQueue = QueueFactory::instance()->createMessageQueue(); @@ -19,13 +23,13 @@ PowerSensor::~PowerSensor() { } ReturnValue_t PowerSensor::calculatePower() { - set.read(); + powerSensorSet.read(); ReturnValue_t result1 = HasReturnvaluesIF::RETURN_FAILED; ReturnValue_t result2 = HasReturnvaluesIF::RETURN_FAILED; if (healthHelper.healthTable->isHealthy(getObjectId()) && voltage.isValid() && current.isValid()) { - result1 = voltageLimit.doCheck(voltage); - result2 = currentLimit.doCheck(current); + result1 = voltageLimit.doCheck(voltage.value); + result2 = currentLimit.doCheck(current.value); } else { voltageLimit.setToInvalid(); currentLimit.setToInvalid(); @@ -37,9 +41,9 @@ ReturnValue_t PowerSensor::calculatePower() { power.setValid(PoolVariableIF::INVALID); } else { power.setValid(PoolVariableIF::VALID); - power = current * voltage; + power.value = current.value * voltage.value; } - set.commit(); + powerSensorSet.commit(); return result1; } @@ -92,8 +96,8 @@ void PowerSensor::checkCommandQueue() { } void PowerSensor::setDataPoolEntriesInvalid() { - set.read(); - set.commit(PoolVariableIF::INVALID); + powerSensorSet.read(); + powerSensorSet.commit(PoolVariableIF::INVALID); } float PowerSensor::getPower() { diff --git a/power/PowerSensor.h b/power/PowerSensor.h index 0f973e45..a0ccb1ca 100644 --- a/power/PowerSensor.h +++ b/power/PowerSensor.h @@ -1,9 +1,7 @@ -#ifndef POWERSENSOR_H_ -#define POWERSENSOR_H_ +#ifndef FSFW_POWER_POWERSENSOR_H_ +#define FSFW_POWER_POWERSENSOR_H_ -#include "../datapool/DataSet.h" -#include "../datapool/PIDReader.h" -#include "../datapool/PoolVariable.h" +#include "../datapoollocal/StaticLocalDataSet.h" #include "../devicehandlers/HealthDevice.h" #include "../monitoring/LimitMonitor.h" #include "../parameters/ParameterHelper.h" @@ -12,15 +10,18 @@ class PowerController; +/** + * @brief Does magic. + */ class PowerSensor: public SystemObject, public ReceivesParameterMessagesIF, public HasHealthIF { friend class PowerController; public: struct VariableIds { - uint32_t pidCurrent; - uint32_t pidVoltage; - uint32_t poolIdPower; + gp_id_t pidCurrent; + gp_id_t pidVoltage; + gp_id_t poolIdPower; }; struct DefaultLimits { float currentMin; @@ -34,8 +35,9 @@ public: Event voltageLow; Event voltageHigh; }; - PowerSensor(object_id_t setId, VariableIds setIds, DefaultLimits limits, - SensorEvents events, uint16_t confirmationCount = 0); + PowerSensor(object_id_t objectId, sid_t sid, VariableIds setIds, + DefaultLimits limits, SensorEvents events, + uint16_t confirmationCount = 0); virtual ~PowerSensor(); ReturnValue_t calculatePower(); ReturnValue_t performOperation(uint8_t opCode); @@ -50,15 +52,19 @@ public: ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex); private: - MessageQueueIF* commandQueue; + MessageQueueIF* commandQueue = nullptr; ParameterHelper parameterHelper; HealthHelper healthHelper; - DataSet set; + //GlobDataSet set; + StaticLocalDataSet<3> powerSensorSet; //Variables in - PIDReader current; - PIDReader voltage; + lp_var_t current; + lp_var_t voltage; + //PIDReader current; + //PIDReader voltage; //Variables out - db_float_t power; + lp_var_t power; + //gp_float_t power; static const uint8_t MODULE_ID_CURRENT = 1; static const uint8_t MODULE_ID_VOLTAGE = 2; @@ -68,4 +74,4 @@ protected: LimitMonitor voltageLimit; }; -#endif /* POWERSENSOR_H_ */ +#endif /* FSFW_POWER_POWERSENSOR_H_ */ diff --git a/power/PowerSwitchIF.h b/power/PowerSwitchIF.h index 40220fb6..b1f53a35 100644 --- a/power/PowerSwitchIF.h +++ b/power/PowerSwitchIF.h @@ -1,18 +1,16 @@ -/** - * @file PowerSwitchIF.h - * @brief This file defines the PowerSwitchIF class. - * @date 20.03.2013 - * @author baetz - */ - -#ifndef POWERSWITCHIF_H_ -#define POWERSWITCHIF_H_ +#ifndef FSFW_POWER_POWERSWITCHIF_H_ +#define FSFW_POWER_POWERSWITCHIF_H_ #include "../events/Event.h" #include "../returnvalues/HasReturnvaluesIF.h" /** - * This interface defines a connection to a device that is capable of turning on and off - * switches of devices identified by a switch ID. + * + * @brief This interface defines a connection to a device that is capable of + * turning on and off switches of devices identified by a switch ID. + * @details + * The virtual functions of this interface do not allow to make any assignments + * because they can be called asynchronosuly (const ending). + * @ingroup interfaces */ class PowerSwitchIF : public HasReturnvaluesIF { public: @@ -32,7 +30,7 @@ public: static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3); static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4); static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2; - static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, SEVERITY::LOW); //!< Someone detected that a switch went off which shouldn't. Severity: Low, Parameter1: switchId1, Parameter2: switchId2 + static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW); //!< Someone detected that a switch went off which shouldn't. Severity: Low, Parameter1: switchId1, Parameter2: switchId2 /** * send a direct command to the Power Unit to enable/disable the specified switch. * @@ -72,4 +70,4 @@ public: }; -#endif /* POWERSWITCHIF_H_ */ +#endif /* FSFW_POWER_POWERSWITCHIF_H_ */ diff --git a/power/PowerSwitcher.cpp b/power/PowerSwitcher.cpp index 6296a04c..ed37998e 100644 --- a/power/PowerSwitcher.cpp +++ b/power/PowerSwitcher.cpp @@ -1,15 +1,17 @@ -#include "../objectmanager/ObjectManagerIF.h" #include "PowerSwitcher.h" + +#include "../objectmanager/ObjectManagerIF.h" #include "../serviceinterface/ServiceInterfaceStream.h" PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2, - PowerSwitcher::State_t setStartState) : - state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2), power(NULL) { + PowerSwitcher::State_t setStartState): + state(setStartState), firstSwitch(setSwitch1), + secondSwitch(setSwitch2) { } ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) { power = objectManager->get(powerSwitchId); - if (power == NULL) { + if (power == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } return HasReturnvaluesIF::RETURN_OK; @@ -17,19 +19,25 @@ ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) { ReturnValue_t PowerSwitcher::getStateOfSwitches() { SwitchReturn_t result = howManySwitches(); + switch (result) { case ONE_SWITCH: return power->getSwitchState(firstSwitch); - case TWO_SWITCHES: - if ((power->getSwitchState(firstSwitch) == PowerSwitchIF::SWITCH_ON) - && (power->getSwitchState(secondSwitch) == PowerSwitchIF::SWITCH_ON)) { + case TWO_SWITCHES: { + ReturnValue_t firstSwitchState = power->getSwitchState(firstSwitch); + ReturnValue_t secondSwitchState = power->getSwitchState(firstSwitch); + if ((firstSwitchState == PowerSwitchIF::SWITCH_ON) + && (secondSwitchState == PowerSwitchIF::SWITCH_ON)) { return PowerSwitchIF::SWITCH_ON; - } else if ((power->getSwitchState(firstSwitch) == PowerSwitchIF::SWITCH_OFF) - && (power->getSwitchState(secondSwitch) == PowerSwitchIF::SWITCH_OFF)) { + } + else if ((firstSwitchState == PowerSwitchIF::SWITCH_OFF) + && (secondSwitchState == PowerSwitchIF::SWITCH_OFF)) { return PowerSwitchIF::SWITCH_OFF; - } else { + } + else { return HasReturnvaluesIF::RETURN_FAILED; } + } default: return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/power/PowerSwitcher.h b/power/PowerSwitcher.h index 0f1c02de..f4e2138d 100644 --- a/power/PowerSwitcher.h +++ b/power/PowerSwitcher.h @@ -1,10 +1,13 @@ -#ifndef POWERSWITCHER_H_ -#define POWERSWITCHER_H_ +#ifndef FSFW_POWER_POWERSWITCHER_H_ +#define FSFW_POWER_POWERSWITCHER_H_ + #include "PowerSwitchIF.h" + +#include "../objectmanager/SystemObjectIF.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../timemanager/Countdown.h" -class PowerSwitcher : public HasReturnvaluesIF { +class PowerSwitcher: public HasReturnvaluesIF { public: enum State_t { WAIT_OFF, @@ -16,7 +19,8 @@ public: static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER; static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1); static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2); - PowerSwitcher( uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH, State_t setStartState = SWITCH_IS_OFF ); + PowerSwitcher( uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH, + State_t setStartState = SWITCH_IS_OFF ); ReturnValue_t initialize(object_id_t powerSwitchId); void turnOn(); void turnOff(); @@ -29,7 +33,8 @@ public: private: uint8_t firstSwitch; uint8_t secondSwitch; - PowerSwitchIF* power; + PowerSwitchIF* power = nullptr; + static const uint8_t NO_SWITCH = 0xFF; enum SwitchReturn_t { ONE_SWITCH = 1, @@ -42,4 +47,4 @@ private: -#endif /* POWERSWITCHER_H_ */ +#endif /* FSFW_POWER_POWERSWITCHER_H_ */ diff --git a/pus/CMakeLists.txt b/pus/CMakeLists.txt new file mode 100644 index 00000000..758c2629 --- /dev/null +++ b/pus/CMakeLists.txt @@ -0,0 +1,11 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + CService200ModeCommanding.cpp + CService201HealthCommanding.cpp + Service17Test.cpp + Service1TelecommandVerification.cpp + Service2DeviceAccess.cpp + Service5EventReporting.cpp + Service8FunctionManagement.cpp + Service9TimeManagement.cpp +) \ No newline at end of file diff --git a/pus/CService200ModeCommanding.cpp b/pus/CService200ModeCommanding.cpp index c63b47a6..c4e99359 100644 --- a/pus/CService200ModeCommanding.cpp +++ b/pus/CService200ModeCommanding.cpp @@ -7,9 +7,10 @@ #include "../modes/ModeMessage.h" CService200ModeCommanding::CService200ModeCommanding(object_id_t objectId, - uint16_t apid, uint8_t serviceId): + uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands, + uint16_t commandTimeoutSeconds): CommandingServiceBase(objectId, apid, serviceId, - NUMBER_OF_PARALLEL_COMMANDS,COMMAND_TIMEOUT_SECONDS) {} + numParallelCommands, commandTimeoutSeconds) {} CService200ModeCommanding::~CService200ModeCommanding() {} diff --git a/pus/CService200ModeCommanding.h b/pus/CService200ModeCommanding.h index 89347dbd..84040212 100644 --- a/pus/CService200ModeCommanding.h +++ b/pus/CService200ModeCommanding.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_PUS_CSERVICE200MODECOMMANDING_H_ -#define FRAMEWORK_PUS_CSERVICE200MODECOMMANDING_H_ +#ifndef FSFW_PUS_CSERVICE200MODECOMMANDING_H_ +#define FSFW_PUS_CSERVICE200MODECOMMANDING_H_ #include "../tmtcservices/CommandingServiceBase.h" @@ -15,11 +15,10 @@ */ class CService200ModeCommanding: public CommandingServiceBase { public: - static constexpr uint8_t NUMBER_OF_PARALLEL_COMMANDS = 4; - static constexpr uint16_t COMMAND_TIMEOUT_SECONDS = 60; CService200ModeCommanding(object_id_t objectId, - uint16_t apid, uint8_t serviceId); + uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands = 4, + uint16_t commandTimeoutSeconds = 60); virtual~ CService200ModeCommanding(); protected: @@ -82,4 +81,4 @@ private: }; }; -#endif /* FRAMEWORK_PUS_CSERVICE200MODECOMMANDING_H_ */ +#endif /* FSFW_PUS_CSERVICE200MODECOMMANDING_H_ */ diff --git a/pus/CService201HealthCommanding.cpp b/pus/CService201HealthCommanding.cpp new file mode 100644 index 00000000..edacd73a --- /dev/null +++ b/pus/CService201HealthCommanding.cpp @@ -0,0 +1,106 @@ +#include "CService201HealthCommanding.h" + +#include "../health/HasHealthIF.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../health/HealthMessage.h" +#include "servicepackets/Service201Packets.h" + +CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, + uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands, + uint16_t commandTimeoutSeconds): + CommandingServiceBase(objectId, apid, serviceId, + numParallelCommands, commandTimeoutSeconds) { +} + +CService201HealthCommanding::~CService201HealthCommanding() { +} + +ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) { + switch(subservice) { + case(Subservice::COMMAND_SET_HEALTH): + case(Subservice::COMMAND_ANNOUNCE_HEALTH): + case(Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): + return RETURN_OK; + default: + sif::error << "Invalid Subservice" << std::endl; + return AcceptsTelecommandsIF::INVALID_SUBSERVICE; + } +} + +ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject( + uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, + MessageQueueId_t *id, object_id_t *objectId) { + if(tcDataLen < sizeof(object_id_t)) { + return CommandingServiceBase::INVALID_TC; + } + SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, + SerializeIF::Endianness::BIG); + + return checkInterfaceAndAcquireMessageQueue(id,objectId); +} + +ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue( + MessageQueueId_t* messageQueueToSet, object_id_t* objectId) { + HasHealthIF * destination = objectManager->get(*objectId); + if(destination == nullptr) { + return CommandingServiceBase::INVALID_OBJECT; + } + + *messageQueueToSet = destination->getCommandQueue(); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t CService201HealthCommanding::prepareCommand( + CommandMessage* message, uint8_t subservice, const uint8_t *tcData, + size_t tcDataLen, uint32_t *state, object_id_t objectId) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(subservice) { + case(Subservice::COMMAND_SET_HEALTH): { + HealthSetCommand healthCommand; + result = healthCommand.deSerialize(&tcData, &tcDataLen, + SerializeIF::Endianness::BIG); + if (result != RETURN_OK) { + break; + } + HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET, + healthCommand.getHealth()); + break; + } + case(Subservice::COMMAND_ANNOUNCE_HEALTH): { + HealthMessage::setHealthMessage(message, + HealthMessage::HEALTH_ANNOUNCE); + break; + } + case(Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): { + HealthMessage::setHealthMessage(message, + HealthMessage::HEALTH_ANNOUNCE_ALL); + break; + } + } + return result; +} + +ReturnValue_t CService201HealthCommanding::handleReply + (const CommandMessage* reply, Command_t previousCommand, + uint32_t *state, CommandMessage* optionalNextCommand, + object_id_t objectId, bool *isStep) { + Command_t replyId = reply->getCommand(); + if (replyId == HealthMessage::REPLY_HEALTH_SET) { + return EXECUTION_COMPLETE; + } + else if(replyId == CommandMessageIF::REPLY_REJECTED) { + return reply->getReplyRejectedReason(); + } + return CommandingServiceBase::INVALID_REPLY; +} + +// Not used for now, health state already reported by event +ReturnValue_t CService201HealthCommanding::prepareHealthSetReply( + const CommandMessage* reply) { + prepareHealthSetReply(reply); + uint8_t health = static_cast(HealthMessage::getHealth(reply)); + uint8_t oldHealth = static_cast(HealthMessage::getOldHealth(reply)); + HealthSetReply healthSetReply(health, oldHealth); + return sendTmPacket(Subservice::REPLY_HEALTH_SET, &healthSetReply); +} + diff --git a/pus/CService201HealthCommanding.h b/pus/CService201HealthCommanding.h new file mode 100644 index 00000000..124e2ac7 --- /dev/null +++ b/pus/CService201HealthCommanding.h @@ -0,0 +1,63 @@ +#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ +#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ + +#include "../tmtcservices/CommandingServiceBase.h" + +/** + * @brief Custom PUS service to set health of all objects + * implementing hasHealthIF. + * + * Examples: Device Handlers, Assemblies or Subsystems. + * Full Documentation: ECSS-E-ST-70-41C or ECSS-E-70-41A + * Dissertation Baetz p. 115, 116, 165-167. + * + * This is a gateway service. It relays device commands using the software bus. + * This service is very closely tied to the Commanding Service Base template + * class. There is constant interaction between this Service Base und a + * child class like this service + * + */ +class CService201HealthCommanding: public CommandingServiceBase { +public: + + CService201HealthCommanding(object_id_t objectId, uint16_t apid, + uint8_t serviceId, uint8_t numParallelCommands = 4, + uint16_t commandTimeoutSeconds = 60); + virtual~ CService201HealthCommanding(); +protected: + /* CSB abstract function implementations */ + ReturnValue_t isValidSubservice(uint8_t subservice) override; + ReturnValue_t getMessageQueueAndObject(uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, + object_id_t *objectId) override; + /** Prepare health command */ + ReturnValue_t prepareCommand(CommandMessage* message, + uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, + uint32_t *state, object_id_t objectId) override; + /** Handle health reply */ + ReturnValue_t handleReply(const CommandMessage* reply, + Command_t previousCommand, uint32_t *state, + CommandMessage* optionalNextCommand, object_id_t objectId, + bool *isStep) override; + +private: + ReturnValue_t checkAndAcquireTargetID(object_id_t* objectIdToSet, + const uint8_t* tcData, size_t tcDataLen); + ReturnValue_t checkInterfaceAndAcquireMessageQueue( + MessageQueueId_t* MessageQueueToSet, object_id_t* objectId); + + ReturnValue_t prepareHealthSetReply(const CommandMessage *reply); + + enum Subservice { + //! [EXPORT] : [TC] Set health of target object + COMMAND_SET_HEALTH = 1, + //! [EXPORT] : [TM] Reply to health set command which also provides old health + REPLY_HEALTH_SET = 2, + //! [EXPORT] : [TC] Commands object to announce their health as an event + COMMAND_ANNOUNCE_HEALTH = 3, + //! [EXPORT] : [TC] Commands all objects in the health map to announce their health + COMMAND_ANNOUNCE_HEALTH_ALL = 4 + }; +}; + +#endif /* FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ */ diff --git a/pus/Service17Test.h b/pus/Service17Test.h index e2681865..83d436ea 100644 --- a/pus/Service17Test.h +++ b/pus/Service17Test.h @@ -21,7 +21,7 @@ class Service17Test: public PusServiceBase { public: // Custom events which can be triggered static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_17; - static constexpr Event TEST = MAKE_EVENT(0, SEVERITY::INFO); + static constexpr Event TEST = MAKE_EVENT(0, severity::INFO); enum Subservice: uint8_t { //! [EXPORT] : [COMMAND] Perform connection test diff --git a/pus/Service1TelecommandVerification.cpp b/pus/Service1TelecommandVerification.cpp index 578eb02d..86b0dcde 100644 --- a/pus/Service1TelecommandVerification.cpp +++ b/pus/Service1TelecommandVerification.cpp @@ -6,15 +6,13 @@ #include "../tmtcpacket/pus/TmPacketStored.h" #include "../serviceinterface/ServiceInterfaceStream.h" #include "../tmtcservices/AcceptsTelemetryIF.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - Service1TelecommandVerification::Service1TelecommandVerification( object_id_t objectId, uint16_t apid, uint8_t serviceId, - object_id_t targetDestination): + object_id_t targetDestination, uint16_t messageQueueDepth): SystemObject(objectId), apid(apid), serviceId(serviceId), targetDestination(targetDestination) { - tmQueue = QueueFactory::instance()->createMessageQueue(); + tmQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); } Service1TelecommandVerification::~Service1TelecommandVerification() {} @@ -53,7 +51,7 @@ ReturnValue_t Service1TelecommandVerification::sendVerificationReport( result = generateSuccessReport(message); } if(result != HasReturnvaluesIF::RETURN_OK){ - sif::error << "Service1TelecommandVerification::initialize: " + sif::error << "Service1TelecommandVerification::sendVerificationReport: " "Sending verification packet failed !" << std::endl; } return result; diff --git a/pus/Service1TelecommandVerification.h b/pus/Service1TelecommandVerification.h index 37562d1c..3d68a4e0 100644 --- a/pus/Service1TelecommandVerification.h +++ b/pus/Service1TelecommandVerification.h @@ -1,5 +1,5 @@ -#ifndef MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ -#define MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ +#ifndef FSFW_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ +#define FSFW_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ #include "../objectmanager/SystemObject.h" #include "../returnvalues/HasReturnvaluesIF.h" @@ -44,14 +44,15 @@ public: static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_1; Service1TelecommandVerification(object_id_t objectId, - uint16_t apid, uint8_t serviceId, object_id_t targetDestination); + uint16_t apid, uint8_t serviceId, object_id_t targetDestination, + uint16_t messageQueueDepth); virtual ~Service1TelecommandVerification(); /** * * @return ID of Verification Queue */ - virtual MessageQueueId_t getVerificationQueue(); + virtual MessageQueueId_t getVerificationQueue() override; /** * Performs the service periodically as specified in init_mission(). @@ -91,4 +92,4 @@ private: }; }; -#endif /* MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ */ +#endif /* FSFW_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ */ diff --git a/pus/Service2DeviceAccess.cpp b/pus/Service2DeviceAccess.cpp index 2093a617..3648b7eb 100644 --- a/pus/Service2DeviceAccess.cpp +++ b/pus/Service2DeviceAccess.cpp @@ -21,8 +21,8 @@ Service2DeviceAccess::~Service2DeviceAccess() {} ReturnValue_t Service2DeviceAccess::isValidSubservice(uint8_t subservice) { switch(static_cast(subservice)){ - case Subservice::RAW_COMMANDING: - case Subservice::TOGGLE_WIRETAPPING: + case Subservice::COMMAND_RAW_COMMANDING: + case Subservice::COMMAND_TOGGLE_WIRETAPPING: return HasReturnvaluesIF::RETURN_OK; default: sif::error << "Invalid Subservice" << std::endl; @@ -39,8 +39,7 @@ ReturnValue_t Service2DeviceAccess::getMessageQueueAndObject( SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG); - ReturnValue_t result = checkInterfaceAndAcquireMessageQueue(id,objectId); - return result; + return checkInterfaceAndAcquireMessageQueue(id,objectId); } ReturnValue_t Service2DeviceAccess::checkInterfaceAndAcquireMessageQueue( @@ -59,14 +58,12 @@ ReturnValue_t Service2DeviceAccess::prepareCommand(CommandMessage* message, uint8_t subservice, const uint8_t* tcData, size_t tcDataLen, uint32_t* state, object_id_t objectId) { switch(static_cast(subservice)){ - case Subservice::RAW_COMMANDING: { - return prepareRawCommand(dynamic_cast(message), - tcData, tcDataLen); + case Subservice::COMMAND_RAW_COMMANDING: { + return prepareRawCommand(message, tcData, tcDataLen); } break; - case Subservice::TOGGLE_WIRETAPPING: { - return prepareWiretappingCommand(dynamic_cast(message), - tcData, tcDataLen); + case Subservice::COMMAND_TOGGLE_WIRETAPPING: { + return prepareWiretappingCommand(message, tcData, tcDataLen); } break; default: @@ -121,11 +118,11 @@ void Service2DeviceAccess::handleUnrequestedReply(CommandMessage* reply) { switch(reply->getCommand()) { case DeviceHandlerMessage::REPLY_RAW_COMMAND: sendWiretappingTm(reply, - static_cast(Subservice::WIRETAPPING_RAW_TC)); + static_cast(Subservice::REPLY_WIRETAPPING_RAW_TC)); break; case DeviceHandlerMessage::REPLY_RAW_REPLY: sendWiretappingTm(reply, - static_cast(Subservice::RAW_REPLY)); + static_cast(Subservice::REPLY_RAW)); break; default: sif::error << "Unknown message in Service2DeviceAccess::" diff --git a/pus/Service2DeviceAccess.h b/pus/Service2DeviceAccess.h index f6aa8b52..b62e6854 100644 --- a/pus/Service2DeviceAccess.h +++ b/pus/Service2DeviceAccess.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_PUS_SERVICE2DEVICEACCESS_H_ -#define FRAMEWORK_PUS_SERVICE2DEVICEACCESS_H_ +#ifndef FSFW_PUS_SERVICE2DEVICEACCESS_H_ +#define FSFW_PUS_SERVICE2DEVICEACCESS_H_ #include "../objectmanager/SystemObjectIF.h" #include "../devicehandlers/AcceptsDeviceResponsesIF.h" @@ -81,12 +81,16 @@ private: const uint8_t* tcData, size_t tcDataLen); enum class Subservice { - RAW_COMMANDING = 128, //!< [EXPORT] : [COMMAND] Command in device native protocol - TOGGLE_WIRETAPPING = 129, //!< [EXPORT] : [COMMAND] Toggle wiretapping of raw communication - RAW_REPLY = 130, //!< [EXPORT] : [REPLY] Includes wiretapping TM and normal TM raw replies from device - WIRETAPPING_RAW_TC = 131 //!< [EXPORT] : [REPLY] Wiretapping packets of commands built by device handler + //!< [EXPORT] : [COMMAND] Command in device native protocol + COMMAND_RAW_COMMANDING = 128, + //!< [EXPORT] : [COMMAND] Toggle wiretapping of raw communication + COMMAND_TOGGLE_WIRETAPPING = 129, + //!< [EXPORT] : [REPLY] Includes wiretapping TM and normal TM raw replies from device + REPLY_RAW = 130, + //!< [EXPORT] : [REPLY] Wiretapping packets of commands built by device handler + REPLY_WIRETAPPING_RAW_TC = 131 }; }; -#endif /* MISSION_PUS_DEVICE2DEVICECOMMANDING_H_ */ +#endif /* FSFW_PUS_DEVICE2DEVICECOMMANDING_H_ */ diff --git a/pus/Service5EventReporting.cpp b/pus/Service5EventReporting.cpp index 829d04bd..e0b34a5b 100644 --- a/pus/Service5EventReporting.cpp +++ b/pus/Service5EventReporting.cpp @@ -8,10 +8,11 @@ Service5EventReporting::Service5EventReporting(object_id_t objectId, - uint16_t apid, uint8_t serviceId, size_t maxNumberReportsPerCycle): + uint16_t apid, uint8_t serviceId, size_t maxNumberReportsPerCycle, + uint32_t messageQueueDepth): PusServiceBase(objectId, apid, serviceId), maxNumberReportsPerCycle(maxNumberReportsPerCycle) { - eventQueue = QueueFactory::instance()->createMessageQueue(); + eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); } Service5EventReporting::~Service5EventReporting(){} diff --git a/pus/Service5EventReporting.h b/pus/Service5EventReporting.h index 0b6ee9a8..69242801 100644 --- a/pus/Service5EventReporting.h +++ b/pus/Service5EventReporting.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_PUS_SERVICE5EVENTREPORTING_H_ -#define FRAMEWORK_PUS_SERVICE5EVENTREPORTING_H_ +#ifndef FSFW_PUS_SERVICE5EVENTREPORTING_H_ +#define FSFW_PUS_SERVICE5EVENTREPORTING_H_ #include "../tmtcservices/PusServiceBase.h" #include "../events/EventMessage.h" @@ -42,7 +42,8 @@ class Service5EventReporting: public PusServiceBase { public: Service5EventReporting(object_id_t objectId, uint16_t apid, - uint8_t serviceId, size_t maxNumberReportsPerCycle = 10); + uint8_t serviceId, size_t maxNumberReportsPerCycle = 10, + uint32_t messageQueueDepth = 10); virtual ~Service5EventReporting(); /*** @@ -83,4 +84,4 @@ private: ReturnValue_t generateEventReport(EventMessage message); }; -#endif /* MISSION_PUS_SERVICE5EVENTREPORTING_H_ */ +#endif /* FSFW_PUS_SERVICE5EVENTREPORTING_H_ */ diff --git a/pus/Service8FunctionManagement.cpp b/pus/Service8FunctionManagement.cpp index 2c2e590b..d710c56e 100644 --- a/pus/Service8FunctionManagement.cpp +++ b/pus/Service8FunctionManagement.cpp @@ -7,10 +7,10 @@ #include "../serialize/SerializeAdapter.h" #include "../serviceinterface/ServiceInterfaceStream.h" -Service8FunctionManagement::Service8FunctionManagement(object_id_t object_id, +Service8FunctionManagement::Service8FunctionManagement(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands, uint16_t commandTimeoutSeconds): - CommandingServiceBase(object_id, apid, serviceId, numParallelCommands, + CommandingServiceBase(objectId, apid, serviceId, numParallelCommands, commandTimeoutSeconds) {} Service8FunctionManagement::~Service8FunctionManagement() {} @@ -19,7 +19,7 @@ Service8FunctionManagement::~Service8FunctionManagement() {} ReturnValue_t Service8FunctionManagement::isValidSubservice( uint8_t subservice) { switch(static_cast(subservice)) { - case Subservice::DIRECT_COMMANDING: + case Subservice::COMMAND_DIRECT_COMMANDING: return HasReturnvaluesIF::RETURN_OK; default: return AcceptsTelecommandsIF::INVALID_SUBSERVICE; @@ -131,7 +131,7 @@ ReturnValue_t Service8FunctionManagement::handleDataReply( } DataReply dataReply(objectId, actionId, buffer, size); result = sendTmPacket(static_cast( - Subservice::DIRECT_COMMANDING_DATA_REPLY), &dataReply); + Subservice::REPLY_DIRECT_COMMANDING_DATA), &dataReply); auto deletionResult = IPCStore->deleteData(storeId); if(deletionResult != HasReturnvaluesIF::RETURN_OK) { diff --git a/pus/Service8FunctionManagement.h b/pus/Service8FunctionManagement.h index b5ebcda8..00153cfb 100644 --- a/pus/Service8FunctionManagement.h +++ b/pus/Service8FunctionManagement.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ -#define FRAMEWORK_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ +#ifndef FSFW_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ +#define FSFW_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ #include "../action/ActionMessage.h" #include "../tmtcservices/CommandingServiceBase.h" @@ -52,8 +52,10 @@ protected: private: enum class Subservice { - DIRECT_COMMANDING = 128, //!< [EXPORT] : [COMMAND] Functional commanding - DIRECT_COMMANDING_DATA_REPLY = 130, //!< [EXPORT] : [REPLY] Data reply + //!< [EXPORT] : [COMMAND] Functional commanding + COMMAND_DIRECT_COMMANDING = 128, + //!< [EXPORT] : [REPLY] Data reply + REPLY_DIRECT_COMMANDING_DATA = 130, }; ReturnValue_t checkInterfaceAndAcquireMessageQueue( @@ -64,4 +66,4 @@ private: object_id_t objectId, ActionId_t actionId); }; -#endif /* FRAMEWORK_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ */ +#endif /* FSFW_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ */ diff --git a/pus/Service9TimeManagement.h b/pus/Service9TimeManagement.h index 4802cdec..70b86966 100644 --- a/pus/Service9TimeManagement.h +++ b/pus/Service9TimeManagement.h @@ -7,8 +7,8 @@ class Service9TimeManagement: public PusServiceBase { public: static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9; - static constexpr Event CLOCK_SET = MAKE_EVENT(0, SEVERITY::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime - static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, SEVERITY::LOW); //!< Clock could not be set. P1: Returncode. + static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime + static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode. static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9; diff --git a/pus/servicepackets/Service1Packets.h b/pus/servicepackets/Service1Packets.h index dbd31028..ecb62693 100644 --- a/pus/servicepackets/Service1Packets.h +++ b/pus/servicepackets/Service1Packets.h @@ -1,3 +1,6 @@ +#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ +#define FSFW_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ + /** * @defgroup spacepackets PUS Packet Definitions * This group contains all implemented TM or TM packages that are sent to @@ -5,9 +8,6 @@ * packet structures in Mission Information Base (MIB). */ -#ifndef MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ -#define MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ - #include "../../serialize/SerializeAdapter.h" #include "../../tmtcservices/VerificationCodes.h" diff --git a/pus/servicepackets/Service200Packets.h b/pus/servicepackets/Service200Packets.h index efcf65fc..cb9ad4a7 100644 --- a/pus/servicepackets/Service200Packets.h +++ b/pus/servicepackets/Service200Packets.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_ -#define FRAMEWORK_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_ +#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_ +#define FSFW_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_ #include "../../serialize/SerialLinkedListAdapter.h" #include "../../modes/ModeMessage.h" @@ -60,4 +60,4 @@ public: SerializeElement reason; //!< [EXPORT] : [COMMENT] Reason the mode could not be reached }; -#endif /* FRAMEWORK_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_ */ +#endif /* FSFW_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_ */ diff --git a/pus/servicepackets/Service201Packets.h b/pus/servicepackets/Service201Packets.h new file mode 100644 index 00000000..aed821f9 --- /dev/null +++ b/pus/servicepackets/Service201Packets.h @@ -0,0 +1,48 @@ +#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE201PACKETS_H_ +#define FSFW_PUS_SERVICEPACKETS_SERVICE201PACKETS_H_ + +#include "../../serialize/SerialLinkedListAdapter.h" +#include "../../serialize/SerializeIF.h" +#include "../../health/HasHealthIF.h" + +class HealthSetCommand: public SerialLinkedListAdapter { //!< [EXPORT] : [SUBSERVICE] 1 +public: + + HealthSetCommand() { + setLinks(); + } + + HasHealthIF::HealthState getHealth() { + return static_cast(health.entry); + } +private: + void setLinks() { + setStart(&objectId); + objectId.setNext(&health); + } + SerializeElement objectId; //!< [EXPORT] : [COMMENT] Target object Id + SerializeElement health; //!< [EXPORT] : [COMMENT] Health to set +}; + + +class HealthSetReply: public SerialLinkedListAdapter { //!< [EXPORT] : [SUBSERVICE] 2 +public: + HealthSetReply(uint8_t health_, uint8_t oldHealth_): + health(health_), oldHealth(oldHealth_) + { + setLinks(); + } + +private: + HealthSetReply(const HealthSetReply &reply); + void setLinks() { + setStart(&objectId); + objectId.setNext(&health); + health.setNext(&oldHealth); + } + SerializeElement objectId; //!< [EXPORT] : [COMMENT] Source object ID + SerializeElement health; //!< [EXPORT] : [COMMENT] New Health + SerializeElement oldHealth; //!< [EXPORT] : [COMMENT] Old Health +}; + +#endif /* FSFW_PUS_SERVICEPACKETS_SERVICE201PACKETS_H_ */ diff --git a/pus/servicepackets/Service2Packets.h b/pus/servicepackets/Service2Packets.h index d4f3fb17..285a8f9f 100644 --- a/pus/servicepackets/Service2Packets.h +++ b/pus/servicepackets/Service2Packets.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ -#define FRAMEWORK_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ +#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ +#define FSFW_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ #include "../../action/ActionMessage.h" #include "../../objectmanager/SystemObjectIF.h" @@ -73,4 +73,4 @@ public: } }; -#endif /* FRAMEWORK_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ */ +#endif /* FSFW_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ */ diff --git a/pus/servicepackets/Service5Packets.h b/pus/servicepackets/Service5Packets.h index 9655608a..f903d6a2 100644 --- a/pus/servicepackets/Service5Packets.h +++ b/pus/servicepackets/Service5Packets.h @@ -1,5 +1,5 @@ -#ifndef MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ -#define MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ +#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ +#define FSFW_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ #include "../../serialize/SerializeAdapter.h" #include "../../tmtcservices/VerificationCodes.h" @@ -73,4 +73,4 @@ private: }; -#endif /* MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ */ +#endif /* FSFW_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ */ diff --git a/pus/servicepackets/Service8Packets.h b/pus/servicepackets/Service8Packets.h index 14f8b6e6..b026edf5 100644 --- a/pus/servicepackets/Service8Packets.h +++ b/pus/servicepackets/Service8Packets.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ -#define FRAMEWORK_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ +#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ +#define FSFW_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ #include "../../action/ActionMessage.h" #include "../../objectmanager/SystemObjectIF.h" @@ -118,4 +118,4 @@ private: }; -#endif /* FRAMEWORK_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ */ +#endif /* FSFW_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ */ diff --git a/rmap/CMakeLists.txt b/rmap/CMakeLists.txt new file mode 100644 index 00000000..78c99e42 --- /dev/null +++ b/rmap/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + RMAP.cpp + RMAPCookie.cpp + RmapDeviceCommunicationIF.cpp +) + diff --git a/serialize/CMakeLists.txt b/serialize/CMakeLists.txt new file mode 100644 index 00000000..fc2387e8 --- /dev/null +++ b/serialize/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + SerialBufferAdapter.cpp +) \ No newline at end of file diff --git a/serviceinterface/CMakeLists.txt b/serviceinterface/CMakeLists.txt new file mode 100644 index 00000000..d84adbeb --- /dev/null +++ b/serviceinterface/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ServiceInterfaceStream.cpp + ServiceInterfaceBuffer.cpp +) \ No newline at end of file diff --git a/storagemanager/CMakeLists.txt b/storagemanager/CMakeLists.txt new file mode 100644 index 00000000..57c92195 --- /dev/null +++ b/storagemanager/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ConstStorageAccessor.cpp + StorageAccessor.cpp +) \ No newline at end of file diff --git a/storagemanager/ConstStorageAccessor.h b/storagemanager/ConstStorageAccessor.h index 96d2dca2..570c20ce 100644 --- a/storagemanager/ConstStorageAccessor.h +++ b/storagemanager/ConstStorageAccessor.h @@ -20,9 +20,7 @@ class StorageManagerIF; */ class ConstStorageAccessor { //! StorageManager classes have exclusive access to private variables. - template friend class PoolManager; - template friend class LocalPool; public: /** diff --git a/storagemanager/LocalPool.cpp b/storagemanager/LocalPool.cpp new file mode 100644 index 00000000..74e362d4 --- /dev/null +++ b/storagemanager/LocalPool.cpp @@ -0,0 +1,347 @@ +#include "LocalPool.h" +#include +#include + +LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig, + bool registered, bool spillsToHigherPools): + SystemObject(setObjectId, registered), + NUMBER_OF_POOLS(poolConfig.size()), + spillsToHigherPools(spillsToHigherPools) { + if(NUMBER_OF_POOLS == 0) { + sif::error << "LocalPool::LocalPool: Passed pool configuration is " + << " invalid!" << std::endl; + } + max_pools_t index = 0; + for (const auto& currentPoolConfig: poolConfig) { + this->numberOfElements[index] = currentPoolConfig.first; + this->elementSizes[index] = currentPoolConfig.second; + store[index] = std::vector( + numberOfElements[index] * elementSizes[index]); + sizeLists[index] = std::vector(numberOfElements[index]); + for(auto& size: sizeLists[index]) { + size = STORAGE_FREE; + } + index++; + } +} + +LocalPool::~LocalPool(void) {} + + +ReturnValue_t LocalPool::addData(store_address_t* storageId, + const uint8_t* data, size_t size, bool ignoreFault) { + ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); + if (status == RETURN_OK) { + write(*storageId, data, size); + } + return status; +} + +ReturnValue_t LocalPool::getData(store_address_t packetId, + const uint8_t **packetPtr, size_t *size) { + uint8_t* tempData = nullptr; + ReturnValue_t status = modifyData(packetId, &tempData, size); + *packetPtr = tempData; + return status; +} + +ReturnValue_t LocalPool::getData(store_address_t storeId, + ConstStorageAccessor& storeAccessor) { + uint8_t* tempData = nullptr; + ReturnValue_t status = modifyData(storeId, &tempData, + &storeAccessor.size_); + storeAccessor.assignStore(this); + storeAccessor.constDataPointer = tempData; + return status; +} + +ConstAccessorPair LocalPool::getData(store_address_t storeId) { + uint8_t* tempData = nullptr; + ConstStorageAccessor constAccessor(storeId, this); + ReturnValue_t status = modifyData(storeId, &tempData, &constAccessor.size_); + constAccessor.constDataPointer = tempData; + return ConstAccessorPair(status, std::move(constAccessor)); +} + +ReturnValue_t LocalPool::getFreeElement(store_address_t *storageId, + const size_t size, uint8_t **pData, bool ignoreFault) { + ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); + if (status == RETURN_OK) { + *pData = &store[storageId->poolIndex][getRawPosition(*storageId)]; + } + else { + *pData = nullptr; + } + return status; +} + + +AccessorPair LocalPool::modifyData(store_address_t storeId) { + StorageAccessor accessor(storeId, this); + ReturnValue_t status = modifyData(storeId, &accessor.dataPointer, + &accessor.size_); + accessor.assignConstPointer(); + return AccessorPair(status, std::move(accessor)); +} + +ReturnValue_t LocalPool::modifyData(store_address_t storeId, + StorageAccessor& storeAccessor) { + storeAccessor.assignStore(this); + ReturnValue_t status = modifyData(storeId, &storeAccessor.dataPointer, + &storeAccessor.size_); + storeAccessor.assignConstPointer(); + return status; +} + +ReturnValue_t LocalPool::modifyData(store_address_t storeId, + uint8_t **packetPtr, size_t *size) { + ReturnValue_t status = RETURN_FAILED; + if (storeId.poolIndex >= NUMBER_OF_POOLS) { + return ILLEGAL_STORAGE_ID; + } + if ((storeId.packetIndex >= numberOfElements[storeId.poolIndex])) { + return ILLEGAL_STORAGE_ID; + } + + if (sizeLists[storeId.poolIndex][storeId.packetIndex] + != STORAGE_FREE) { + size_type packetPosition = getRawPosition(storeId); + *packetPtr = &store[storeId.poolIndex][packetPosition]; + *size = sizeLists[storeId.poolIndex][storeId.packetIndex]; + status = RETURN_OK; + } + else { + status = DATA_DOES_NOT_EXIST; + } + return status; +} + +ReturnValue_t LocalPool::deleteData(store_address_t storeId) { +#if FSFW_VERBOSE_PRINTOUT == 2 + sif::debug << "Delete: Pool: " << std::dec << storeId.poolIndex + << " Index: " << storeId.packetIndex << std::endl; + +#endif + ReturnValue_t status = RETURN_OK; + size_type pageSize = getPageSize(storeId.poolIndex); + if ((pageSize != 0) and + (storeId.packetIndex < numberOfElements[storeId.poolIndex])) { + uint16_t packetPosition = getRawPosition(storeId); + uint8_t* ptr = &store[storeId.poolIndex][packetPosition]; + std::memset(ptr, 0, pageSize); + //Set free list + sizeLists[storeId.poolIndex][storeId.packetIndex] = STORAGE_FREE; + } + else { + //pool_index or packet_index is too large + sif::error << "LocalPool::deleteData: Illegal store ID, no deletion!" + << std::endl; + status = ILLEGAL_STORAGE_ID; + } + return status; +} + +ReturnValue_t LocalPool::deleteData(uint8_t *ptr, size_t size, + store_address_t *storeId) { + store_address_t localId; + ReturnValue_t result = ILLEGAL_ADDRESS; + for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { + //Not sure if new allocates all stores in order. so better be careful. + if ((store[n].data() <= ptr) and + (&store[n][numberOfElements[n]*elementSizes[n]] > ptr)) { + localId.poolIndex = n; + uint32_t deltaAddress = ptr - store[n].data(); + // Getting any data from the right "block" is ok. + // This is necessary, as IF's sometimes don't point to the first + // element of an object. + localId.packetIndex = deltaAddress / elementSizes[n]; + result = deleteData(localId); +#if FSFW_VERBOSE_PRINTOUT == 2 + if (deltaAddress % elementSizes[n] != 0) { + sif::error << "LocalPool::deleteData: Address not aligned!" + << std::endl; + } +#endif + break; + } + } + if (storeId != nullptr) { + *storeId = localId; + } + return result; +} + + +ReturnValue_t LocalPool::initialize() { + ReturnValue_t result = SystemObject::initialize(); + if (result != RETURN_OK) { + return result; + } + internalErrorReporter = objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter == nullptr){ + return ObjectManagerIF::INTERNAL_ERR_REPORTER_UNINIT; + } + + //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) { + sif::error << "LocalPool::initialize: Pool is too large! " + "Max. allowed size is: " << (STORAGE_FREE - 1) << std::endl; + return StorageManagerIF::POOL_TOO_LARGE; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +void LocalPool::clearStore() { + for(auto& sizeList: sizeLists) { + for(auto& size: sizeList) { + size = STORAGE_FREE; + } +// std::memset(sizeList[index], 0xff, +// numberOfElements[index] * sizeof(size_type)); + } + +} + +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) { + sif::error << "LocalPool( " << std::hex << getObjectId() << std::dec + << " )::reserveSpace: Packet too large." << std::endl; + return status; + } + status = findEmpty(storeId->poolIndex, &storeId->packetIndex); + while (status != RETURN_OK && spillsToHigherPools) { + status = getPoolIndex(size, &storeId->poolIndex, storeId->poolIndex + 1); + if (status != RETURN_OK) { + //We don't find any fitting pool anymore. + break; + } + status = findEmpty(storeId->poolIndex, &storeId->packetIndex); + } + if (status == RETURN_OK) { +#if FSFW_VERBOSE_PRINTOUT == 2 + sif::debug << "Reserve: Pool: " << std::dec + << storeId->poolIndex << " Index: " << storeId->packetIndex + << std::endl; +#endif + sizeLists[storeId->poolIndex][storeId->packetIndex] = size; + } + else { + if ((not ignoreFault) and (internalErrorReporter != nullptr)) { + internalErrorReporter->storeFull(); + } + } + return status; +} + +void LocalPool::write(store_address_t storeId, const uint8_t *data, + size_t size) { + uint8_t* ptr = nullptr; + size_type packetPosition = getRawPosition(storeId); + + // Size was checked before calling this function. + ptr = &store[storeId.poolIndex][packetPosition]; + std::memcpy(ptr, data, size); + sizeLists[storeId.poolIndex][storeId.packetIndex] = size; +} + +LocalPool::size_type LocalPool::getPageSize(max_pools_t poolIndex) { + if (poolIndex < NUMBER_OF_POOLS) { + return elementSizes[poolIndex]; + } + else { + return 0; + } +} + +void LocalPool::setToSpillToHigherPools(bool enable) { + this->spillsToHigherPools = enable; +} + +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 + sif::debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " + << n << ", Element Size: " << elementSizes[n] << std::endl; +#endif + if (elementSizes[n] >= packetSize) { + *poolIndex = n; + return RETURN_OK; + } + } + return DATA_TOO_LARGE; +} + +LocalPool::size_type LocalPool::getRawPosition(store_address_t storeId) { + return storeId.packetIndex * elementSizes[storeId.poolIndex]; +} + +ReturnValue_t LocalPool::findEmpty(n_pool_elem_t poolIndex, uint16_t *element) { + ReturnValue_t status = DATA_STORAGE_FULL; + for (uint16_t foundElement = 0; foundElement < numberOfElements[poolIndex]; + foundElement++) { + if (sizeLists[poolIndex][foundElement] == STORAGE_FREE) { + *element = foundElement; + status = RETURN_OK; + break; + } + } + return status; +} + +size_t LocalPool::getTotalSize(size_t* additionalSize) { + size_t totalSize = 0; + size_t sizesSize = 0; + for(uint8_t idx = 0; idx < NUMBER_OF_POOLS; idx ++) { + totalSize += elementSizes[idx] * numberOfElements[idx]; + sizesSize += numberOfElements[idx] * sizeof(size_type); + } + if(additionalSize != nullptr) { + *additionalSize = sizesSize; + } + return totalSize; +} + +void LocalPool::getFillCount(uint8_t *buffer, uint8_t *bytesWritten) { + if(bytesWritten == nullptr or buffer == nullptr) { + return; + } + + uint16_t reservedHits = 0; + uint8_t idx = 0; + uint16_t sum = 0; + for(; idx < NUMBER_OF_POOLS; idx ++) { + for(const auto& size: sizeLists[idx]) { + if(size != STORAGE_FREE) { + reservedHits++; + } + } + buffer[idx] = static_cast(reservedHits) / + numberOfElements[idx] * 100; + *bytesWritten += 1; + sum += buffer[idx]; + reservedHits = 0; + } + buffer[idx] = sum / NUMBER_OF_POOLS; + *bytesWritten += 1; +} + + +void LocalPool::clearPage(max_pools_t pageIndex) { + if(pageIndex >= NUMBER_OF_POOLS) { + return; + } + + // Mark the storage as free + for(auto& size: sizeLists[pageIndex]) { + size = STORAGE_FREE; + } + + // Set all the page content to 0. + std::memset(store[pageIndex].data(), 0, elementSizes[pageIndex]); +} diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index 3a94c03d..db771152 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -7,57 +7,93 @@ #include "../serviceinterface/ServiceInterfaceStream.h" #include "../internalError/InternalErrorReporterIF.h" #include "../storagemanager/StorageAccessor.h" -#include + +#include +#include +#include +#include /** - * @brief The LocalPool class provides an intermediate data storage with - * a fixed pool size policy. - * @details The class implements the StorageManagerIF interface. While the - * total number of pools is fixed, the element sizes in one pool and - * the number of pool elements per pool are set on construction. - * The full amount of memory is allocated on construction. - * The overhead is 4 byte per pool element to store the size - * information of each stored element. - * To maintain an "empty" information, the pool size is limited to - * 0xFFFF-1 bytes. - * It is possible to store empty packets in the pool. - * The local pool is NOT thread-safe. - * @author Bastian Baetz + * @brief The LocalPool class provides an intermediate data storage with + * a fixed pool size policy. + * @details + * The class implements the StorageManagerIF interface. While the total number + * of pools is fixed, the element sizes in one pool and the number of pool + * elements per pool are set on construction. The full amount of memory is + * allocated on construction. + * The overhead is 4 byte per pool element to store the size information of + * each stored element. To maintain an "empty" information, the pool size is + * limited to 0xFFFF-1 bytes. + * It is possible to store empty packets in the pool. + * The local pool is NOT thread-safe. */ -template class LocalPool: public SystemObject, public StorageManagerIF { public: - /** - * @brief This definition generally sets the number of different sized pools. - * @details This must be less than the maximum number of pools (currently 0xff). - */ - // static const uint32_t NUMBER_OF_POOLS; - /** - * @brief This is the default constructor for a pool manager instance. - * @details By passing two arrays of size NUMBER_OF_POOLS, the constructor - * allocates memory (with @c new) for store and size_list. These - * regions are all set to zero on start up. - * @param setObjectId The object identifier to be set. This allows for - * multiple instances of LocalPool in the system. - * @param element_sizes An array of size NUMBER_OF_POOLS in which the size - * of a single element in each pool is determined. - * The sizes must be provided in ascending order. - * - * @param n_elements An array of size NUMBER_OF_POOLS in which the - * number of elements for each pool is determined. - * The position of these values correspond to those in - * element_sizes. - * @param registered Register the pool in object manager or not. - * Default is false (local pool). - * @param spillsToHigherPools A variable to determine whether - * higher n pools are used if the store is full. - */ - LocalPool(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS], - bool registered = false, - bool spillsToHigherPools = false); + using pool_elem_size_t = size_type; + using n_pool_elem_t = uint16_t; + using LocalPoolCfgPair = std::pair; + + // The configuration needs to be provided with the pool sizes ascending + // but the number of pool elements as the first value is more intuitive. + // Therefore, a custom comparator was provided. + struct LocalPoolConfigCmp + { + bool operator ()(const LocalPoolCfgPair &a, + const LocalPoolCfgPair &b) const + { + if(a.second < b.second) { + return true; + } + else if(a.second > b.second) { + return false; + } + else { + if(a.first < b.first) { + return true; + } + else { + return false; + } + } + } + }; + using LocalPoolConfig = std::multiset; + + /** + * @brief This definition generally sets the number of + * different sized pools. It is derived from the number of pairs + * inside the LocalPoolConfig set on object creation. + * @details + * This must be less than the maximum number of pools (currently 0xff). + */ + const max_pools_t NUMBER_OF_POOLS; + + /** + * @brief This is the default constructor for a pool manager instance. + * @details + * The pool is configured by passing a set of pairs into the constructor. + * The first value of that pair determines the number of one elements on + * the respective page of the pool while the second value determines how + * many elements with that size are created on that page. + * All regions are to zero on start up. + * @param setObjectId The object identifier to be set. This allows for + * multiple instances of LocalPool in the system. + * @param poolConfig + * This is a set of pairs to configure the number of pages in the pool, + * the size of an element on a page, the number of elements on a page + * and the total size of the pool at once while also implicitely + * sorting the pairs in the right order. + * @param registered + * Determines whether the pool is registered in the object manager or not. + * @param spillsToHigherPools A variable to determine whether + * higher n pools are used if the store is full. + */ + LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig, + bool registered = false, bool spillsToHigherPools = false); + + void setToSpillToHigherPools(bool enable); + /** * @brief In the LocalPool's destructor all allocated memory is freed. */ @@ -66,25 +102,49 @@ public: /** * Documentation: See StorageManagerIF.h */ - ReturnValue_t addData(store_address_t* storageId, const uint8_t * data, + ReturnValue_t addData(store_address_t* storeId, const uint8_t * data, size_t size, bool ignoreFault = false) override; - ReturnValue_t getFreeElement(store_address_t* storageId,const size_t size, - uint8_t** p_data, bool ignoreFault = false) override; + ReturnValue_t getFreeElement(store_address_t* storeId,const size_t size, + uint8_t** pData, bool ignoreFault = false) override; - ConstAccessorPair getData(store_address_t packet_id) override; - ReturnValue_t getData(store_address_t packet_id, ConstStorageAccessor&) override; - ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr, + ConstAccessorPair getData(store_address_t storeId) override; + ReturnValue_t getData(store_address_t storeId, + ConstStorageAccessor& constAccessor) override; + ReturnValue_t getData(store_address_t storeId, + const uint8_t** packet_ptr, size_t * size) override; + + AccessorPair modifyData(store_address_t storeId) override; + ReturnValue_t modifyData(store_address_t storeId, + StorageAccessor& storeAccessor) override; + ReturnValue_t modifyData(store_address_t storeId, uint8_t** packet_ptr, size_t * size) override; - AccessorPair modifyData(store_address_t packet_id) override; - ReturnValue_t modifyData(store_address_t packet_id, StorageAccessor&) override; - ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr, - size_t * size) override; - - virtual ReturnValue_t deleteData(store_address_t) override; + virtual ReturnValue_t deleteData(store_address_t storeId) override; virtual ReturnValue_t deleteData(uint8_t* ptr, size_t size, - store_address_t* storeId = NULL) override; + store_address_t* storeId = nullptr) override; + + /** + * Get the total size of allocated memory for pool data. + * There is an additional overhead of the sizes of elements which will + * be assigned to additionalSize + * @return + */ + size_t getTotalSize(size_t* additionalSize) override; + + /** + * Get the fill count of the pool. Each character inside the provided + * buffer will be assigned to a rounded percentage fill count for each + * page. The last written byte (at the index bytesWritten - 1) + * will contain the total fill count of the pool as a mean of the + * percentages of single pages. + * @param buffer + * @param maxSize + */ + void getFillCount(uint8_t* buffer, uint8_t* bytesWritten) override; + void clearStore() override; + void clearPage(max_pools_t pageIndex) override; + ReturnValue_t initialize() override; protected: /** @@ -94,43 +154,48 @@ protected: * @return - #RETURN_OK on success, * - the return codes of #getPoolIndex or #findEmpty otherwise. */ - virtual ReturnValue_t reserveSpace(const uint32_t size, + virtual ReturnValue_t reserveSpace(const size_t size, store_address_t* address, bool ignoreFault); - InternalErrorReporterIF *internalErrorReporter; private: - /** - * Indicates that this element is free. - * This value limits the maximum size of a pool. Change to larger data type - * if increase is required. - */ - static const uint32_t STORAGE_FREE = 0xFFFFFFFF; + /** + * Indicates that this element is free. + * This value limits the maximum size of a pool. + * Change to larger data type if increase is required. + */ + static const size_type STORAGE_FREE = std::numeric_limits::max(); /** * @brief In this array, the element sizes of each pool is stored. * @details The sizes are maintained for internal pool management. The sizes * must be set in ascending order on construction. */ - uint32_t element_sizes[NUMBER_OF_POOLS]; + std::vector elementSizes = + std::vector(NUMBER_OF_POOLS); /** * @brief n_elements stores the number of elements per pool. * @details These numbers are maintained for internal pool management. */ - uint16_t n_elements[NUMBER_OF_POOLS]; + std::vector numberOfElements = + std::vector(NUMBER_OF_POOLS); /** * @brief store represents the actual memory pool. * @details It is an array of pointers to memory, which was allocated with * a @c new call on construction. */ - uint8_t* store[NUMBER_OF_POOLS]; + std::vector> store = + std::vector>(NUMBER_OF_POOLS); + /** * @brief The size_list attribute stores the size values of every pool element. * @details As the number of elements is determined on construction, the size list * is also dynamically allocated there. */ - uint32_t* size_list[NUMBER_OF_POOLS]; + std::vector> sizeLists = + std::vector>(NUMBER_OF_POOLS); + //! A variable to determine whether higher n pools are used if //! the store is full. - bool spillsToHigherPools; + bool spillsToHigherPools = false; /** * @brief This method safely stores the given data in the given packet_id. * @details It also sets the size in size_list. The method does not perform @@ -139,30 +204,24 @@ private: * @param data The data to be stored. * @param size The size of the data to be stored. */ - void write(store_address_t packet_id, const uint8_t* data, size_t size); + void write(store_address_t packetId, const uint8_t* data, size_t size); /** * @brief A helper method to read the element size of a certain pool. * @param pool_index The pool in which to look. * @return Returns the size of an element or 0. */ - uint32_t getPageSize(uint16_t pool_index); - /** - * @brief This helper method looks up a fitting pool for a given size. - * @details The pools are looked up in ascending order, so the first that - * fits is used. - * @param packet_size The size of the data to be stored. - * @return Returns the pool that fits or StorageManagerIF::INVALID_ADDRESS. - */ + size_type getPageSize(max_pools_t poolIndex); + /** * @brief This helper method looks up a fitting pool for a given size. * @details The pools are looked up in ascending order, so the first that * fits is used. * @param packet_size The size of the data to be stored. * @param[out] poolIndex The fitting pool index found. - * @return - #RETURN_OK on success, - * - #DATA_TOO_LARGE otherwise. + * @return - @c RETURN_OK on success, + * - @c DATA_TOO_LARGE otherwise. */ - ReturnValue_t getPoolIndex(size_t packet_size, uint16_t* poolIndex, + ReturnValue_t getPoolIndex(size_t packetSize, uint16_t* poolIndex, uint16_t startAtIndex = 0); /** * @brief This helper method calculates the true array position in store @@ -172,7 +231,7 @@ private: * @param packet_id The packet id to look up. * @return Returns the position of the data in store. */ - uint32_t getRawPosition(store_address_t packet_id); + size_type getRawPosition(store_address_t storeId); /** * @brief This is a helper method to find an empty element in a given pool. * @details The method searches size_list for the first empty element, so @@ -182,9 +241,9 @@ private: * @return - #RETURN_OK on success, * - #DATA_STORAGE_FULL if the store is full */ - ReturnValue_t findEmpty(uint16_t pool_index, uint16_t* element); + ReturnValue_t findEmpty(n_pool_elem_t poolIndex, uint16_t* element); + + InternalErrorReporterIF *internalErrorReporter = nullptr; }; -#include "LocalPool.tpp" - #endif /* FSFW_STORAGEMANAGER_LOCALPOOL_H_ */ diff --git a/storagemanager/PoolManager.cpp b/storagemanager/PoolManager.cpp new file mode 100644 index 00000000..3b7b549b --- /dev/null +++ b/storagemanager/PoolManager.cpp @@ -0,0 +1,60 @@ +#include "PoolManager.h" +#include + +PoolManager::PoolManager(object_id_t setObjectId, + const LocalPoolConfig& localPoolConfig): + LocalPool(setObjectId, localPoolConfig, true) { + mutex = MutexFactory::instance()->createMutex(); +} + + +PoolManager::~PoolManager(void) { + MutexFactory::instance()->deleteMutex(mutex); +} + + +ReturnValue_t PoolManager::reserveSpace(const size_t size, + store_address_t* address, bool ignoreFault) { + MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, + mutexTimeoutMs); + ReturnValue_t status = LocalPool::reserveSpace(size, + address,ignoreFault); + return status; +} + + +ReturnValue_t PoolManager::deleteData( + store_address_t storeId) { +#if FSFW_VERBOSE_PRINTOUT == 2 + sif::debug << "PoolManager( " << translateObject(getObjectId()) << + " )::deleteData from store " << storeId.poolIndex << + ". id is "<< storeId.packetIndex << std::endl; +#endif + MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, + mutexTimeoutMs); + return LocalPool::deleteData(storeId); +} + + +ReturnValue_t PoolManager::deleteData(uint8_t* buffer, + size_t size, store_address_t* storeId) { + MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); + ReturnValue_t status = LocalPool::deleteData(buffer, + size, storeId); + return status; +} + + +void PoolManager::setMutexTimeout( + uint32_t mutexTimeoutMs) { + this->mutexTimeoutMs = mutexTimeoutMs; +} + +ReturnValue_t PoolManager::lockMutex(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + return mutex->lockMutex(timeoutType, timeoutMs); +} + +ReturnValue_t PoolManager::unlockMutex() { + return mutex->unlockMutex(); +} diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 8cc6c065..5786a225 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -9,16 +9,20 @@ /** * @brief The PoolManager class provides an intermediate data storage with * a fixed pool size policy for inter-process communication. - * @details Uses local pool calls but is thread safe by protecting the call - * with a lock. + * @details + * Uses local pool calls but is thread safe by protecting most calls + * with a lock. The developer can lock the pool with the provided API + * if the lock needs to persists beyond the function call. + * + * Other than that, the class provides the same interface as the LocalPool + * class. The class is always registered as a system object as it is assumed + * it will always be used concurrently (if this is not the case, it is + * recommended to use the LocalPool class instead). * @author Bastian Baetz */ -template -class PoolManager : public LocalPool { +class PoolManager: public LocalPool { public: - PoolManager(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS]); + PoolManager(object_id_t setObjectId, const LocalPoolConfig& poolConfig); /** * @brief In the PoolManager's destructor all allocated memory @@ -26,6 +30,12 @@ public: */ virtual ~PoolManager(); + /** + * Set the default mutex timeout for internal calls. + * @param mutexTimeoutMs + */ + void setMutexTimeout(uint32_t mutexTimeoutMs); + /** * @brief LocalPool overrides for thread-safety. Decorator function * which wraps LocalPool calls with a mutex protection. @@ -34,12 +44,23 @@ public: ReturnValue_t deleteData(uint8_t* buffer, size_t size, store_address_t* storeId = nullptr) override; - void setMutexTimeout(uint32_t mutexTimeoutMs); + /** + * The developer is allowed to lock the mutex in case the lock needs + * to persist beyond the function calls which are not protected by the + * class. + * @param timeoutType + * @param timeoutMs + * @return + */ + ReturnValue_t lockMutex(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs); + ReturnValue_t unlockMutex(); + protected: //! Default mutex timeout value to prevent permanent blocking. uint32_t mutexTimeoutMs = 20; - ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address, + ReturnValue_t reserveSpace(const size_t size, store_address_t* address, bool ignoreFault) override; /** @@ -51,6 +72,4 @@ protected: MutexIF* mutex; }; -#include "PoolManager.tpp" - #endif /* FSFW_STORAGEMANAGER_POOLMANAGER_H_ */ diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index 5cf15d50..d5b383eb 100644 --- a/storagemanager/StorageAccessor.h +++ b/storagemanager/StorageAccessor.h @@ -10,9 +10,7 @@ class StorageManagerIF; */ class StorageAccessor: public ConstStorageAccessor { //! StorageManager classes have exclusive access to private variables. - template friend class PoolManager; - template friend class LocalPool; public: StorageAccessor(store_address_t storeId); diff --git a/storagemanager/StorageManagerIF.h b/storagemanager/StorageManagerIF.h index 834e7563..62251933 100644 --- a/storagemanager/StorageManagerIF.h +++ b/storagemanager/StorageManagerIF.h @@ -28,6 +28,9 @@ using ConstAccessorPair = std::pair; */ class StorageManagerIF : public HasReturnvaluesIF { public: + using size_type = size_t; + using max_pools_t = uint8_t; + static const uint8_t INTERFACE_ID = CLASS_ID::STORAGE_MANAGER_IF; //!< The unique ID for return codes for this interface. static const ReturnValue_t DATA_TOO_LARGE = MAKE_RETURN_CODE(1); //!< This return code indicates that the data to be stored is too large for the store. static const ReturnValue_t DATA_STORAGE_FULL = MAKE_RETURN_CODE(2); //!< This return code indicates that a data storage is full. @@ -37,10 +40,12 @@ public: static const ReturnValue_t POOL_TOO_LARGE = MAKE_RETURN_CODE(6); //!< Pool size too large on initialization. static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::OBSW; - static const Event GET_DATA_FAILED = MAKE_EVENT(0, SEVERITY::LOW); - static const Event STORE_DATA_FAILED = MAKE_EVENT(1, SEVERITY::LOW); + static const Event GET_DATA_FAILED = MAKE_EVENT(0, severity::LOW); + static const Event STORE_DATA_FAILED = MAKE_EVENT(1, severity::LOW); + + //!< Indicates an invalid (i.e unused) storage address. + static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; - static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; //!< Indicates an invalid (i.e unused) storage address. /** * @brief This is the empty virtual destructor as required for C++ interfaces. */ @@ -164,6 +169,22 @@ public: * Use with care! */ virtual void clearStore() = 0; + + /** + * Clears a page in the store. Use with care! + * @param pageIndex + */ + virtual void clearPage(uint8_t pageIndex) = 0; + + /** + * Get the fill count of the pool. The exact form will be implementation + * dependant. + * @param buffer + * @param bytesWritten + */ + virtual void getFillCount(uint8_t* buffer, uint8_t* bytesWritten) = 0; + + virtual size_t getTotalSize(size_t* additionalSize) = 0; }; #endif /* FSFW_STORAGEMANAGER_STORAGEMANAGERIF_H_ */ diff --git a/storagemanager/storeAddress.h b/storagemanager/storeAddress.h index 044c0790..ea72f6f8 100644 --- a/storagemanager/storeAddress.h +++ b/storagemanager/storeAddress.h @@ -3,16 +3,21 @@ #include +namespace storeId { +static constexpr uint32_t INVALID_STORE_ADDRESS = 0xffffffff; +} + /** * This union defines the type that identifies where a data packet is * stored in the store. It comprises of a raw part to read it as raw value and * a structured part to use it in pool-like stores. */ union store_address_t { + /** * Default Constructor, initializing to INVALID_ADDRESS */ - store_address_t():raw(0xFFFFFFFF){} + store_address_t(): raw(storeId::INVALID_STORE_ADDRESS){} /** * Constructor to create an address object using the raw address * @@ -28,7 +33,7 @@ union store_address_t { * @param packetIndex */ store_address_t(uint16_t poolIndex, uint16_t packetIndex): - pool_index(poolIndex),packet_index(packetIndex){} + poolIndex(poolIndex), packetIndex(packetIndex){} /** * A structure with two elements to access the store address pool-like. */ @@ -36,11 +41,11 @@ union store_address_t { /** * The index in which pool the packet lies. */ - uint16_t pool_index; + uint16_t poolIndex; /** * The position in the chosen pool. */ - uint16_t packet_index; + uint16_t packetIndex; }; /** * Alternative access to the raw value. diff --git a/subsystem/CMakeLists.txt b/subsystem/CMakeLists.txt new file mode 100644 index 00000000..5c98ee70 --- /dev/null +++ b/subsystem/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + Subsystem.cpp + SubsystemBase.cpp +) + +add_subdirectory(modes) \ No newline at end of file diff --git a/subsystem/modes/CMakeLists.txt b/subsystem/modes/CMakeLists.txt new file mode 100644 index 00000000..6ac6a293 --- /dev/null +++ b/subsystem/modes/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ModeSequenceMessage.cpp + ModeStore.cpp +) diff --git a/tasks/CMakeLists.txt b/tasks/CMakeLists.txt new file mode 100644 index 00000000..1964bb4e --- /dev/null +++ b/tasks/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + FixedSequenceSlot.cpp + FixedSlotSequence.cpp +) \ No newline at end of file diff --git a/tcdistribution/CMakeLists.txt b/tcdistribution/CMakeLists.txt new file mode 100644 index 00000000..17dc186c --- /dev/null +++ b/tcdistribution/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + CCSDSDistributor.cpp + PUSDistributor.cpp + TcDistributor.cpp + TcPacketCheck.cpp +) diff --git a/thermal/AbstractTemperatureSensor.cpp b/thermal/AbstractTemperatureSensor.cpp index 45ebe4a2..40b305af 100644 --- a/thermal/AbstractTemperatureSensor.cpp +++ b/thermal/AbstractTemperatureSensor.cpp @@ -44,19 +44,19 @@ ReturnValue_t AbstractTemperatureSensor::performHealthOp() { } void AbstractTemperatureSensor::handleCommandQueue() { - CommandMessage message; - ReturnValue_t result = commandQueue->receiveMessage(&message); + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); if (result == HasReturnvaluesIF::RETURN_OK) { - result = healthHelper.handleHealthCommand(&message); + result = healthHelper.handleHealthCommand(&command); if (result == HasReturnvaluesIF::RETURN_OK) { return; } - result = parameterHelper.handleParameterMessage(&message); + result = parameterHelper.handleParameterMessage(&command); if (result == HasReturnvaluesIF::RETURN_OK) { return; } - message.setToUnknownCommand(); - commandQueue->reply(&message); + command.setToUnknownCommand(); + commandQueue->reply(&command); } } diff --git a/thermal/AbstractTemperatureSensor.h b/thermal/AbstractTemperatureSensor.h index 726ab9f4..a1153314 100644 --- a/thermal/AbstractTemperatureSensor.h +++ b/thermal/AbstractTemperatureSensor.h @@ -10,6 +10,16 @@ #include "ThermalModuleIF.h" #include "tcsDefinitions.h" +/** + * @defgroup thermal Thermal Components + * @brief Contains all components related to thermal tasks (sensors, heaters) + */ + +/** + * @brief Base class for Temperature Sensor, implements all important interfaces. + * Please use the TemperatureSensor class to implement the actual sensors. + * @ingroup thermal + */ class AbstractTemperatureSensor: public HasHealthIF, public SystemObject, public ExecutableObjectIF, @@ -17,9 +27,9 @@ class AbstractTemperatureSensor: public HasHealthIF, public: static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::T_SENSORS; - static const Event TEMP_SENSOR_HIGH = MAKE_EVENT(0, SEVERITY::LOW); - static const Event TEMP_SENSOR_LOW = MAKE_EVENT(1, SEVERITY::LOW); - static const Event TEMP_SENSOR_GRADIENT = MAKE_EVENT(2, SEVERITY::LOW); + static const Event TEMP_SENSOR_HIGH = MAKE_EVENT(0, severity::LOW); + static const Event TEMP_SENSOR_LOW = MAKE_EVENT(1, severity::LOW); + static const Event TEMP_SENSOR_GRADIENT = MAKE_EVENT(2, severity::LOW); static constexpr float ZERO_KELVIN_C = -273.15; AbstractTemperatureSensor(object_id_t setObjectid, diff --git a/thermal/AcceptsThermalMessagesIF.h b/thermal/AcceptsThermalMessagesIF.h new file mode 100644 index 00000000..5fbd6bb3 --- /dev/null +++ b/thermal/AcceptsThermalMessagesIF.h @@ -0,0 +1,22 @@ +/** + * \file AcceptsThermalMessagesIF.h + * + * \date 16.02.2020 + */ + +#ifndef FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_ +#define FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_ +#include "../ipc/MessageQueueSenderIF.h" + +class AcceptsThermalMessagesIF { +public: + + /** + * @brief This is the empty virtual destructor as required for C++ interfaces. + */ + virtual ~AcceptsThermalMessagesIF() { } + + virtual MessageQueueId_t getReceptionQueue() const = 0; +}; + +#endif /* FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_ */ diff --git a/thermal/CMakeLists.txt b/thermal/CMakeLists.txt new file mode 100644 index 00000000..67664fbe --- /dev/null +++ b/thermal/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + AbstractTemperatureSensor.cpp + CoreComponent.cpp + Heater.cpp + RedundantHeater.cpp + ThermalComponent.cpp + ThermalModule.cpp + ThermalMonitor.cpp +) diff --git a/thermal/CoreComponent.h b/thermal/CoreComponent.h deleted file mode 100644 index 48a49f7d..00000000 --- a/thermal/CoreComponent.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ -#define MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ - -#include "../datapool/DataSet.h" -#include "../datapool/PoolVariable.h" -#include "ThermalComponentIF.h" -#include "AbstractTemperatureSensor.h" -#include "ThermalModule.h" -#include "ThermalMonitor.h" - -class CoreComponent: public ThermalComponentIF { -public: - struct Parameters { - float lowerOpLimit; - float upperOpLimit; - float heaterOn; - float hysteresis; - float heaterSwitchoff; - }; - - static const uint16_t COMPONENT_TEMP_CONFIRMATION = 5; - - CoreComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, - uint32_t targetStatePoolId, uint32_t currentStatePoolId, - uint32_t requestPoolId, DataSet *dataSet, - AbstractTemperatureSensor *sensor, - AbstractTemperatureSensor *firstRedundantSensor, - AbstractTemperatureSensor *secondRedundantSensor, - ThermalModuleIF *thermalModule, Parameters parameters, - Priority priority, StateRequest initialTargetState = - ThermalComponentIF::STATE_REQUEST_OPERATIONAL); - - virtual ~CoreComponent(); - - virtual HeaterRequest performOperation(uint8_t opCode); - - void markStateIgnored(); - - object_id_t getObjectId(); - - uint8_t getDomainId() const; - - virtual float getLowerOpLimit(); - - ReturnValue_t setTargetState(int8_t newState); - - virtual void setOutputInvalid(); - - virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); - -protected: - - AbstractTemperatureSensor *sensor; - AbstractTemperatureSensor *firstRedundantSensor; - AbstractTemperatureSensor *secondRedundantSensor; - ThermalModuleIF *thermalModule; - - db_float_t temperature; - db_int8_t targetState; - db_int8_t currentState; - db_uint8_t heaterRequest; - - bool isHeating; - - bool isSafeComponent; - - float minTemp; - - float maxTemp; - - Parameters parameters; - - ThermalMonitor temperatureMonitor; - - const uint8_t domainId; - - virtual float getTemperature(); - virtual State getState(float temperature, Parameters parameters, - int8_t targetState); - - virtual void checkLimits(State state); - - virtual HeaterRequest getHeaterRequest(int8_t targetState, - float temperature, Parameters parameters); - - virtual State getIgnoredState(int8_t state); - - void updateMinMaxTemp(); - - virtual Parameters getParameters(); -}; - -#endif /* MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ */ diff --git a/thermal/Heater.cpp b/thermal/Heater.cpp index 1301e2e0..ce965d5e 100644 --- a/thermal/Heater.cpp +++ b/thermal/Heater.cpp @@ -279,14 +279,14 @@ ReturnValue_t Heater::initialize() { } void Heater::handleQueue() { - CommandMessage message; - ReturnValue_t result = commandQueue->receiveMessage(&message); + CommandMessage command; + ReturnValue_t result = commandQueue->receiveMessage(&command); if (result == HasReturnvaluesIF::RETURN_OK) { - result = healthHelper.handleHealthCommand(&message); + result = healthHelper.handleHealthCommand(&command); if (result == HasReturnvaluesIF::RETURN_OK) { return; } - parameterHelper.handleParameterMessage(&message); + parameterHelper.handleParameterMessage(&command); } } @@ -301,7 +301,7 @@ ReturnValue_t Heater::getParameter(uint8_t domainId, uint16_t parameterId, parameterWrapper->set(heaterOnCountdown.timeout); break; default: - return INVALID_MATRIX_ID; + return INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/thermal/Heater.h b/thermal/Heater.h index 63fe2066..b034dfee 100644 --- a/thermal/Heater.h +++ b/thermal/Heater.h @@ -14,11 +14,11 @@ class Heater: public HealthDevice, public ReceivesParameterMessagesIF { public: static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HEATER; - static const Event HEATER_ON = MAKE_EVENT(0, SEVERITY::INFO); - static const Event HEATER_OFF = MAKE_EVENT(1, SEVERITY::INFO); - static const Event HEATER_TIMEOUT = MAKE_EVENT(2, SEVERITY::LOW); - static const Event HEATER_STAYED_ON = MAKE_EVENT(3, SEVERITY::LOW); - static const Event HEATER_STAYED_OFF = MAKE_EVENT(4, SEVERITY::LOW); + static const Event HEATER_ON = MAKE_EVENT(0, severity::INFO); + static const Event HEATER_OFF = MAKE_EVENT(1, severity::INFO); + static const Event HEATER_TIMEOUT = MAKE_EVENT(2, severity::LOW); + static const Event HEATER_STAYED_ON = MAKE_EVENT(3, severity::LOW); + static const Event HEATER_STAYED_OFF = MAKE_EVENT(4, severity::LOW); Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1); virtual ~Heater(); diff --git a/thermal/RedundantHeater.h b/thermal/RedundantHeater.h index ab745a69..76537542 100644 --- a/thermal/RedundantHeater.h +++ b/thermal/RedundantHeater.h @@ -1,7 +1,7 @@ #ifndef REDUNDANTHEATER_H_ #define REDUNDANTHEATER_H_ -#include "Heater.h" +#include "../thermal/Heater.h" class RedundantHeater { public: @@ -10,15 +10,14 @@ public: Parameters(uint32_t objectIdHeater0, uint32_t objectIdHeater1, uint8_t switch0Heater0, uint8_t switch1Heater0, uint8_t switch0Heater1, uint8_t switch1Heater1) : - objectIdHeater0(objectIdHeater0), objectIdHeater1( - objectIdHeater1), switch0Heater0(switch0Heater0), switch1Heater0( - switch1Heater0), switch0Heater1(switch0Heater1), switch1Heater1( - switch1Heater1) { + objectIdHeater0(objectIdHeater0), objectIdHeater1(objectIdHeater1), + switch0Heater0(switch0Heater0),switch1Heater0(switch1Heater0), + switch0Heater1(switch0Heater1), switch1Heater1(switch1Heater1) { } Parameters() : - objectIdHeater0(0), objectIdHeater1(0), switch0Heater0(0), switch1Heater0( - 0), switch0Heater1(0), switch1Heater1(0) { + objectIdHeater0(0), objectIdHeater1(0), switch0Heater0(0), + switch1Heater0(0), switch0Heater1(0), switch1Heater1(0) { } uint32_t objectIdHeater0; diff --git a/thermal/TemperatureSensor.h b/thermal/TemperatureSensor.h index 356ca722..f41b3761 100644 --- a/thermal/TemperatureSensor.h +++ b/thermal/TemperatureSensor.h @@ -1,40 +1,101 @@ #ifndef TEMPERATURESENSOR_H_ #define TEMPERATURESENSOR_H_ -#include "../datapool/DataSet.h" -#include "AbstractTemperatureSensor.h" +#include "../thermal/AbstractTemperatureSensor.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" #include "../monitoring/LimitMonitor.h" -template +/** + * @brief This building block handles non-linear value conversion and + * range checks for analog temperature sensors. + * @details This class can be used to perform all necessary tasks for temperature sensors. + * A sensor can be instantiated by calling the constructor. + * The temperature is calculated from an input value with + * the calculateOutputTemperature() function. Range checking and + * limit monitoring is performed automatically. + * The inputType specifies the type of the raw input while the + * limitType specifies the type of the upper and lower limit to check against. + * @ingroup thermal + */ + +template class TemperatureSensor: public AbstractTemperatureSensor { public: + /** + * This structure contains parameters required for range checking + * and the conversion from the input value to the output temperature. + * a, b and c can be any parameters required to calculate the output + * temperature from the input value, depending on the formula used. + * + * The parameters a,b and c are used in the calculateOutputTemperature() call. + * + * The lower and upper limits can be specified in any type, for example float for C values + * or any other type for raw values. + */ struct Parameters { float a; float b; float c; - T lowerLimit; - T upperLimit; - float gradient; + limitType lowerLimit; + limitType upperLimit; + float maxGradient; }; + + /** + * Forward declaration for explicit instantiation of used parameters. + */ struct UsedParameters { UsedParameters(Parameters parameters) : - a(parameters.a), b(parameters.b), c(parameters.c), gradient( - parameters.gradient) { - } + a(parameters.a), b(parameters.b), c(parameters.c), + gradient(parameters.maxGradient) {} float a; float b; float c; float gradient; }; - static const uint16_t ADDRESS_A = 0; - static const uint16_t ADDRESS_B = 1; - static const uint16_t ADDRESS_C = 2; - static const uint16_t ADDRESS_GRADIENT = 3; + /** + * Instantiate Temperature Sensor Object. + * @param setObjectid objectId of the sensor object + * @param inputValue Input value which is converted to a temperature + * @param poolVariable Pool Variable to store the temperature value + * @param vectorIndex Vector Index for the sensor monitor + * @param parameters Calculation parameters, temperature limits, gradient limit + * @param datapoolId Datapool ID of the output temperature + * @param outputSet Output dataset for the output temperature to fetch it with read() + * @param thermalModule respective thermal module, if it has one + */ + TemperatureSensor(object_id_t setObjectid, + inputType *inputValue, PoolVariableIF *poolVariable, + uint8_t vectorIndex, uint32_t datapoolId, Parameters parameters = {0, 0, 0, 0, 0, 0}, + GlobDataSet *outputSet = NULL, ThermalModuleIF *thermalModule = NULL) : + AbstractTemperatureSensor(setObjectid, thermalModule), parameters(parameters), + inputValue(inputValue), poolVariable(poolVariable), + outputTemperature(datapoolId, outputSet, PoolVariableIF::VAR_WRITE), + sensorMonitor(setObjectid, DOMAIN_ID_SENSOR, + GlobalDataPool::poolIdAndPositionToPid(poolVariable->getDataPoolId(), vectorIndex), + DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, parameters.upperLimit, + TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), + oldTemperature(20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) { + } + + +protected: + /** + * This formula is used to calculate the temperature from an input value + * with an arbitrary type. + * A default implementation is provided but can be replaced depending + * on the required calculation. + * @param inputTemperature + * @return + */ + virtual float calculateOutputTemperature(inputType inputValue) { + return parameters.a * inputValue * inputValue + + parameters.b * inputValue + parameters.c; + } - static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.) - static const uint8_t DOMAIN_ID_SENSOR = 1; private: void setInvalid() { outputTemperature = INVALID_TEMPERATURE; @@ -47,22 +108,17 @@ protected: UsedParameters parameters; - T *inputTemperature; + inputType * inputValue; PoolVariableIF *poolVariable; - PoolVariable outputTemperature; + gp_float_t outputTemperature; - LimitMonitor sensorMonitor; + LimitMonitor sensorMonitor; float oldTemperature; timeval uptimeOfOldTemperature; - virtual float calculateOutputTemperature(T inputTemperature) { - return parameters.a * inputTemperature * inputTemperature - + parameters.b * inputTemperature + parameters.c; - } - void doChildOperation() { if (!poolVariable->isValid() || !healthHelper.healthTable->isHealthy(getObjectId())) { @@ -70,7 +126,7 @@ protected: return; } - outputTemperature = calculateOutputTemperature(*inputTemperature); + outputTemperature = calculateOutputTemperature(*inputValue); outputTemperature.setValid(PoolVariableIF::VALID); timeval uptime; @@ -78,7 +134,7 @@ protected: if (uptimeOfOldTemperature.tv_sec != INVALID_UPTIME) { //In theory, we could use an AbsValueMonitor to monitor the gradient. - //But this would require storing the gradient in DP and quite some overhead. + //But this would require storing the maxGradient in DP and quite some overhead. //The concept of delta limits is a bit strange anyway. float deltaTime; float deltaTemp; @@ -96,8 +152,8 @@ protected: } } - //Check is done against raw limits. SHOULDDO: Why? Using °C would be more easy to handle. - sensorMonitor.doCheck(*inputTemperature); + //Check is done against raw limits. SHOULDDO: Why? Using �C would be more easy to handle. + sensorMonitor.doCheck(outputTemperature.value); if (sensorMonitor.isOutOfLimits()) { uptimeOfOldTemperature.tv_sec = INVALID_UPTIME; @@ -110,23 +166,6 @@ protected: } public: - TemperatureSensor(object_id_t setObjectid, - T *inputTemperature, PoolVariableIF *poolVariable, - uint8_t vectorIndex, Parameters parameters, uint32_t datapoolId, - DataSet *outputSet, ThermalModuleIF *thermalModule) : - AbstractTemperatureSensor(setObjectid, thermalModule), parameters( - parameters), inputTemperature(inputTemperature), poolVariable( - poolVariable), outputTemperature(datapoolId, outputSet, - PoolVariableIF::VAR_WRITE), sensorMonitor(setObjectid, - DOMAIN_ID_SENSOR, - DataPool::poolIdAndPositionToPid( - poolVariable->getDataPoolId(), vectorIndex), - DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, - parameters.upperLimit, TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), oldTemperature( - 20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) { - - } - float getTemperature() { return outputTemperature; } @@ -135,6 +174,15 @@ public: return outputTemperature.isValid(); } + static const uint16_t ADDRESS_A = 0; + static const uint16_t ADDRESS_B = 1; + static const uint16_t ADDRESS_C = 2; + static const uint16_t ADDRESS_GRADIENT = 3; + + static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.) + + static const uint8_t DOMAIN_ID_SENSOR = 1; + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex) { @@ -160,7 +208,7 @@ public: parameterWrapper->set(parameters.gradient); break; default: - return INVALID_MATRIX_ID; + return INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/thermal/ThermalComponent.cpp b/thermal/ThermalComponent.cpp index 5dcd0bc6..084201dd 100644 --- a/thermal/ThermalComponent.cpp +++ b/thermal/ThermalComponent.cpp @@ -1,48 +1,46 @@ #include "ThermalComponent.h" ThermalComponent::ThermalComponent(object_id_t reportingObjectId, - uint8_t domainId, uint32_t temperaturePoolId, - uint32_t targetStatePoolId, uint32_t currentStatePoolId, - uint32_t requestPoolId, DataSet* dataSet, + uint8_t domainId, gp_id_t temperaturePoolId, + gp_id_t targetStatePoolId, gp_id_t currentStatePoolId, + gp_id_t requestPoolId, LocalPoolDataSetBase* dataSet, AbstractTemperatureSensor* sensor, AbstractTemperatureSensor* firstRedundantSensor, AbstractTemperatureSensor* secondRedundantSensor, ThermalModuleIF* thermalModule, Parameters parameters, Priority priority) : - CoreComponent(reportingObjectId, domainId, temperaturePoolId, + ThermalComponentCore(reportingObjectId, domainId, temperaturePoolId, targetStatePoolId, currentStatePoolId, requestPoolId, dataSet, - sensor, firstRedundantSensor, secondRedundantSensor, - thermalModule, { parameters.lowerOpLimit, parameters.upperOpLimit, - parameters.heaterOn, parameters.hysteresis, - parameters.heaterSwitchoff }, priority, - ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL), nopParameters( - { parameters.lowerNopLimit, parameters.upperNopLimit }) { + parameters.heaterOn, parameters.hysteresis, + parameters.heaterSwitchoff }, + ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL), + nopParameters({ parameters.lowerNopLimit, parameters.upperNopLimit }) { } ThermalComponent::~ThermalComponent() { } ReturnValue_t ThermalComponent::setTargetState(int8_t newState) { - DataSet mySet; - PoolVariable writableTargetState(targetState.getDataPoolId(), - &mySet, PoolVariableIF::VAR_READ_WRITE); - mySet.read(); - if ((writableTargetState == STATE_REQUEST_OPERATIONAL) - && (newState != STATE_REQUEST_IGNORE)) { + targetState.setReadWriteMode(pool_rwm_t::VAR_READ_WRITE); + targetState.read(); + if ((targetState == STATE_REQUEST_OPERATIONAL) + and (newState != STATE_REQUEST_IGNORE)) { return HasReturnvaluesIF::RETURN_FAILED; } switch (newState) { case STATE_REQUEST_NON_OPERATIONAL: - writableTargetState = newState; - mySet.commit(PoolVariableIF::VALID); + targetState = newState; + targetState.setValid(true); + targetState.commit(PoolVariableIF::VALID); return HasReturnvaluesIF::RETURN_OK; default: - return CoreComponent::setTargetState(newState); + return ThermalComponentCore::setTargetState(newState); } + return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, uint32_t size) { +ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, size_t size) { if (size != 4 * sizeof(parameters.lowerOpLimit)) { return MonitoringIF::INVALID_SIZE; } @@ -59,11 +57,11 @@ ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, uint32_t size) { } ThermalComponentIF::State ThermalComponent::getState(float temperature, - CoreComponent::Parameters parameters, int8_t targetState) { + ThermalComponentCore::Parameters parameters, int8_t targetState) { if (temperature < nopParameters.lowerNopLimit) { return OUT_OF_RANGE_LOW; } else { - State state = CoreComponent::getState(temperature, parameters, + State state = ThermalComponentCore::getState(temperature, parameters, targetState); if (state != NON_OPERATIONAL_HIGH && state != NON_OPERATIONAL_HIGH_IGNORED) { @@ -80,18 +78,19 @@ ThermalComponentIF::State ThermalComponent::getState(float temperature, } void ThermalComponent::checkLimits(ThermalComponentIF::State state) { - if (targetState == STATE_REQUEST_OPERATIONAL || targetState == STATE_REQUEST_IGNORE) { - CoreComponent::checkLimits(state); + if ((targetState == STATE_REQUEST_OPERATIONAL) or + (targetState == STATE_REQUEST_IGNORE)) { + ThermalComponentCore::checkLimits(state); return; } - //If component is not operational, it checks the NOP limits. + // If component is not operational, it checks the NOP limits. temperatureMonitor.translateState(state, temperature.value, nopParameters.lowerNopLimit, nopParameters.upperNopLimit, false); } ThermalComponentIF::HeaterRequest ThermalComponent::getHeaterRequest( int8_t targetState, float temperature, - CoreComponent::Parameters parameters) { + ThermalComponentCore::Parameters parameters) { if (targetState == STATE_REQUEST_IGNORE) { isHeating = false; return HEATER_DONT_CARE; @@ -144,16 +143,16 @@ ThermalComponentIF::State ThermalComponent::getIgnoredState(int8_t state) { case OUT_OF_RANGE_HIGH_IGNORED: return OUT_OF_RANGE_HIGH_IGNORED; default: - return CoreComponent::getIgnoredState(state); + return ThermalComponentCore::getIgnoredState(state); } } ReturnValue_t ThermalComponent::getParameter(uint8_t domainId, uint16_t parameterId, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, uint16_t startAtIndex) { - ReturnValue_t result = CoreComponent::getParameter(domainId, parameterId, + ReturnValue_t result = ThermalComponentCore::getParameter(domainId, parameterId, parameterWrapper, newValues, startAtIndex); - if (result != INVALID_MATRIX_ID) { + if (result != INVALID_IDENTIFIER_ID) { return result; } switch (parameterId) { @@ -164,7 +163,7 @@ ReturnValue_t ThermalComponent::getParameter(uint8_t domainId, parameterWrapper->set(nopParameters.upperNopLimit); break; default: - return INVALID_MATRIX_ID; + return INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/thermal/ThermalComponent.h b/thermal/ThermalComponent.h index 93243868..0785a914 100644 --- a/thermal/ThermalComponent.h +++ b/thermal/ThermalComponent.h @@ -1,9 +1,14 @@ -#ifndef THERMALCOMPONENT_H_ -#define THERMALCOMPONENT_H_ +#ifndef FSFW_THERMAL_THERMALCOMPONENT_H_ +#define FSFW_THERMAL_THERMALCOMPONENT_H_ -#include "CoreComponent.h" +#include "ThermalComponentCore.h" -class ThermalComponent: public CoreComponent { +/** + * @brief + * @details + * Some more documentation. + */ +class ThermalComponent: public ThermalComponentCore { public: struct Parameters { float lowerNopLimit; @@ -14,13 +19,35 @@ public: float hysteresis; float heaterSwitchoff; }; + + /** + * Non-Operational Temperatures + */ struct NopParameters { float lowerNopLimit; float upperNopLimit; }; - ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, - uint32_t targetStatePoolId, uint32_t currentStatePoolId, uint32_t requestPoolId, - DataSet *dataSet, AbstractTemperatureSensor *sensor, + + /** + * How to use. + * @param reportingObjectId + * @param domainId + * @param temperaturePoolId + * @param targetStatePoolId + * @param currentStatePoolId + * @param requestPoolId + * @param dataSet + * @param sensor + * @param firstRedundantSensor + * @param secondRedundantSensor + * @param thermalModule + * @param parameters + * @param priority + */ + ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, + gp_id_t temperaturePoolId, gp_id_t targetStatePoolId, + gp_id_t currentStatePoolId, gp_id_t requestPoolId, + LocalPoolDataSetBase *dataSet, AbstractTemperatureSensor *sensor, AbstractTemperatureSensor *firstRedundantSensor, AbstractTemperatureSensor *secondRedundantSensor, ThermalModuleIF *thermalModule, Parameters parameters, @@ -29,7 +56,7 @@ public: ReturnValue_t setTargetState(int8_t newState); - virtual ReturnValue_t setLimits( const uint8_t* data, uint32_t size); + virtual ReturnValue_t setLimits( const uint8_t* data, size_t size); virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ParameterWrapper *parameterWrapper, @@ -39,15 +66,15 @@ protected: NopParameters nopParameters; - State getState(float temperature, CoreComponent::Parameters parameters, + State getState(float temperature, ThermalComponentCore::Parameters parameters, int8_t targetState); virtual void checkLimits(State state); virtual HeaterRequest getHeaterRequest(int8_t targetState, float temperature, - CoreComponent::Parameters parameters); + ThermalComponentCore::Parameters parameters); State getIgnoredState(int8_t state); }; -#endif /* THERMALCOMPONENT_H_ */ +#endif /* FSFW_THERMAL_THERMALCOMPONENT_H_ */ diff --git a/thermal/CoreComponent.cpp b/thermal/ThermalComponentCore.cpp similarity index 52% rename from thermal/CoreComponent.cpp rename to thermal/ThermalComponentCore.cpp index 304712ef..7b594d0c 100644 --- a/thermal/CoreComponent.cpp +++ b/thermal/ThermalComponentCore.cpp @@ -1,50 +1,73 @@ -#include "CoreComponent.h" +#include "ThermalComponentCore.h" -CoreComponent::CoreComponent(object_id_t reportingObjectId, uint8_t domainId, - uint32_t temperaturePoolId, uint32_t targetStatePoolId, - uint32_t currentStatePoolId, uint32_t requestPoolId, DataSet* dataSet, - AbstractTemperatureSensor* sensor, - AbstractTemperatureSensor* firstRedundantSensor, - AbstractTemperatureSensor* secondRedundantSensor, - ThermalModuleIF* thermalModule, Parameters parameters, - Priority priority, StateRequest initialTargetState) : - sensor(sensor), firstRedundantSensor(firstRedundantSensor), secondRedundantSensor( - secondRedundantSensor), thermalModule(thermalModule), temperature( - temperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), targetState( - targetStatePoolId, dataSet, PoolVariableIF::VAR_READ), currentState( - currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE), heaterRequest( - requestPoolId, dataSet, PoolVariableIF::VAR_WRITE), isHeating( - false), isSafeComponent(priority == SAFE), minTemp(999), maxTemp( - AbstractTemperatureSensor::ZERO_KELVIN_C), parameters( - parameters), temperatureMonitor(reportingObjectId, - domainId + 1, - DataPool::poolIdAndPositionToPid(temperaturePoolId, 0), - COMPONENT_TEMP_CONFIRMATION), domainId(domainId) { - if (thermalModule != NULL) { - thermalModule->registerComponent(this, priority); - } +ThermalComponentCore::ThermalComponentCore(object_id_t reportingObjectId, + uint8_t domainId, gp_id_t temperaturePoolId, + gp_id_t targetStatePoolId, gp_id_t currentStatePoolId, + gp_id_t requestPoolId, LocalPoolDataSetBase* dataSet, + Parameters parameters, StateRequest initialTargetState) : + temperature(temperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), + targetState(targetStatePoolId, dataSet, PoolVariableIF::VAR_READ), + currentState(currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE), + heaterRequest(requestPoolId, dataSet, PoolVariableIF::VAR_WRITE), + parameters(parameters), domainId(domainId), + temperatureMonitor(reportingObjectId, domainId + 1,temperaturePoolId, + COMPONENT_TEMP_CONFIRMATION) { //Set thermal state once, then leave to operator. - DataSet mySet; - PoolVariable writableTargetState(targetStatePoolId, &mySet, - PoolVariableIF::VAR_WRITE); - writableTargetState = initialTargetState; - mySet.commit(PoolVariableIF::VALID); + targetState.setReadWriteMode(PoolVariableIF::VAR_WRITE); + ReturnValue_t result = targetState.read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + targetState = initialTargetState; + targetState.setValid(true); + targetState.commit(); + } + targetState.setReadWriteMode(PoolVariableIF::VAR_READ); } -CoreComponent::~CoreComponent() { +void ThermalComponentCore::addSensor(AbstractTemperatureSensor* sensor) { + this->sensor = sensor; } -ThermalComponentIF::HeaterRequest CoreComponent::performOperation(uint8_t opCode) { +void ThermalComponentCore::addFirstRedundantSensor( + AbstractTemperatureSensor *firstRedundantSensor) { + this->firstRedundantSensor = firstRedundantSensor; +} + +void ThermalComponentCore::addSecondRedundantSensor( + AbstractTemperatureSensor *secondRedundantSensor) { + this->secondRedundantSensor = secondRedundantSensor; +} + +void ThermalComponentCore::addThermalModule(ThermalModule *thermalModule, + Priority priority) { + this->thermalModule = thermalModule; + if(thermalModule != nullptr) { + thermalModule->registerComponent(this, priority); + } +} + +void ThermalComponentCore::setPriority(Priority priority) { + if(priority == SAFE) { + this->isSafeComponent = true; + } +} + +ThermalComponentCore::~ThermalComponentCore() { +} + +ThermalComponentIF::HeaterRequest ThermalComponentCore::performOperation( + uint8_t opCode) { HeaterRequest request = HEATER_DONT_CARE; //SHOULDDO: Better pass db_float_t* to getTemperature and set it invalid if invalid. temperature = getTemperature(); updateMinMaxTemp(); - if ((temperature != INVALID_TEMPERATURE)) { + if (temperature != INVALID_TEMPERATURE) { temperature.setValid(PoolVariableIF::VALID); - State state = getState(temperature, getParameters(), targetState); + State state = getState(temperature.value, getParameters(), + targetState.value); currentState = state; checkLimits(state); - request = getHeaterRequest(targetState, temperature, getParameters()); + request = getHeaterRequest(targetState.value, temperature.value, + getParameters()); } else { temperatureMonitor.setToInvalid(); temperature.setValid(PoolVariableIF::INVALID); @@ -57,42 +80,45 @@ ThermalComponentIF::HeaterRequest CoreComponent::performOperation(uint8_t opCode return request; } -void CoreComponent::markStateIgnored() { - currentState = getIgnoredState(currentState); +void ThermalComponentCore::markStateIgnored() { + currentState = getIgnoredState(currentState.value); } -object_id_t CoreComponent::getObjectId() { +object_id_t ThermalComponentCore::getObjectId() { return temperatureMonitor.getReporterId(); + return 0; } -float CoreComponent::getLowerOpLimit() { +float ThermalComponentCore::getLowerOpLimit() { return parameters.lowerOpLimit; } -ReturnValue_t CoreComponent::setTargetState(int8_t newState) { - DataSet mySet; - PoolVariable writableTargetState(targetState.getDataPoolId(), - &mySet, PoolVariableIF::VAR_READ_WRITE); - mySet.read(); - if ((writableTargetState == STATE_REQUEST_OPERATIONAL) - && (newState != STATE_REQUEST_IGNORE)) { + + +ReturnValue_t ThermalComponentCore::setTargetState(int8_t newState) { + targetState.setReadWriteMode(pool_rwm_t::VAR_READ_WRITE); + targetState.read(); + if((targetState == STATE_REQUEST_OPERATIONAL) and + (newState != STATE_REQUEST_IGNORE)) { return HasReturnvaluesIF::RETURN_FAILED; } + switch (newState) { case STATE_REQUEST_HEATING: case STATE_REQUEST_IGNORE: case STATE_REQUEST_OPERATIONAL: - writableTargetState = newState; + targetState = newState; break; case STATE_REQUEST_NON_OPERATIONAL: default: return INVALID_TARGET_STATE; } - mySet.commit(PoolVariableIF::VALID); + targetState.setValid(true); + targetState.commit(); return HasReturnvaluesIF::RETURN_OK; } -void CoreComponent::setOutputInvalid() { +void ThermalComponentCore::setOutputInvalid() { temperature = INVALID_TEMPERATURE; temperature.setValid(PoolVariableIF::INVALID); currentState.setValid(PoolVariableIF::INVALID); @@ -101,20 +127,22 @@ void CoreComponent::setOutputInvalid() { temperatureMonitor.setToUnchecked(); } -float CoreComponent::getTemperature() { - if ((sensor != NULL) && (sensor->isValid())) { +float ThermalComponentCore::getTemperature() { + if ((sensor != nullptr) && (sensor->isValid())) { return sensor->getTemperature(); } - if ((firstRedundantSensor != NULL) && (firstRedundantSensor->isValid())) { + if ((firstRedundantSensor != nullptr) && + (firstRedundantSensor->isValid())) { return firstRedundantSensor->getTemperature(); } - if ((secondRedundantSensor != NULL) && (secondRedundantSensor->isValid())) { + if ((secondRedundantSensor != nullptr) && + (secondRedundantSensor->isValid())) { return secondRedundantSensor->getTemperature(); } - if (thermalModule != NULL) { + if (thermalModule != nullptr) { float temperature = thermalModule->getTemperature(); if (temperature != ThermalModuleIF::INVALID_TEMPERATURE) { return temperature; @@ -126,7 +154,7 @@ float CoreComponent::getTemperature() { } } -ThermalComponentIF::State CoreComponent::getState(float temperature, +ThermalComponentIF::State ThermalComponentCore::getState(float temperature, Parameters parameters, int8_t targetState) { ThermalComponentIF::State state; @@ -144,14 +172,14 @@ ThermalComponentIF::State CoreComponent::getState(float temperature, return state; } -void CoreComponent::checkLimits(ThermalComponentIF::State state) { +void ThermalComponentCore::checkLimits(ThermalComponentIF::State state) { //Checks operational limits only. temperatureMonitor.translateState(state, temperature.value, getParameters().lowerOpLimit, getParameters().upperOpLimit); } -ThermalComponentIF::HeaterRequest CoreComponent::getHeaterRequest( +ThermalComponentIF::HeaterRequest ThermalComponentCore::getHeaterRequest( int8_t targetState, float temperature, Parameters parameters) { if (targetState == STATE_REQUEST_IGNORE) { isHeating = false; @@ -177,7 +205,7 @@ ThermalComponentIF::HeaterRequest CoreComponent::getHeaterRequest( return HEATER_DONT_CARE; } -ThermalComponentIF::State CoreComponent::getIgnoredState(int8_t state) { +ThermalComponentIF::State ThermalComponentCore::getIgnoredState(int8_t state) { switch (state) { case NON_OPERATIONAL_LOW: return NON_OPERATIONAL_LOW_IGNORED; @@ -197,27 +225,27 @@ ThermalComponentIF::State CoreComponent::getIgnoredState(int8_t state) { } } -void CoreComponent::updateMinMaxTemp() { +void ThermalComponentCore::updateMinMaxTemp() { if (temperature == INVALID_TEMPERATURE) { return; } if (temperature < minTemp) { - minTemp = temperature; + minTemp = static_cast(temperature); } if (temperature > maxTemp) { - maxTemp = temperature; + maxTemp = static_cast(temperature); } } -uint8_t CoreComponent::getDomainId() const { +uint8_t ThermalComponentCore::getDomainId() const { return domainId; } -CoreComponent::Parameters CoreComponent::getParameters() { +ThermalComponentCore::Parameters ThermalComponentCore::getParameters() { return parameters; } -ReturnValue_t CoreComponent::getParameter(uint8_t domainId, +ReturnValue_t ThermalComponentCore::getParameter(uint8_t domainId, uint16_t parameterId, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, uint16_t startAtIndex) { ReturnValue_t result = temperatureMonitor.getParameter(domainId, @@ -251,7 +279,7 @@ ReturnValue_t CoreComponent::getParameter(uint8_t domainId, parameterWrapper->set(parameters.upperOpLimit); break; default: - return INVALID_MATRIX_ID; + return INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/thermal/ThermalComponentCore.h b/thermal/ThermalComponentCore.h new file mode 100644 index 00000000..da9424e6 --- /dev/null +++ b/thermal/ThermalComponentCore.h @@ -0,0 +1,117 @@ +#ifndef FSFW_THERMAL_THERMALCOMPONENTCORE_H_ +#define FSFW_THERMAL_THERMALCOMPONENTCORE_H_ + +#include "ThermalMonitorReporter.h" +#include "ThermalComponentIF.h" +#include "AbstractTemperatureSensor.h" +#include "ThermalModule.h" + +#include "../datapoollocal/LocalPoolVariable.h" + +/** + * @brief + * @details + */ +class ThermalComponentCore: public ThermalComponentIF { +public: + struct Parameters { + float lowerOpLimit; + float upperOpLimit; + float heaterOn; + float hysteresis; + float heaterSwitchoff; + }; + + static const uint16_t COMPONENT_TEMP_CONFIRMATION = 5; + + /** + * Some documentation + * @param reportingObjectId + * @param domainId + * @param temperaturePoolId + * @param targetStatePoolId + * @param currentStatePoolId + * @param requestPoolId + * @param dataSet + * @param parameters + * @param initialTargetState + */ + ThermalComponentCore(object_id_t reportingObjectId, uint8_t domainId, + gp_id_t temperaturePoolId, gp_id_t targetStatePoolId, + gp_id_t currentStatePoolId, gp_id_t requestPoolId, + LocalPoolDataSetBase* dataSet, Parameters parameters, + StateRequest initialTargetState = + ThermalComponentIF::STATE_REQUEST_OPERATIONAL); + + void addSensor(AbstractTemperatureSensor* firstRedundantSensor); + void addFirstRedundantSensor( + AbstractTemperatureSensor* firstRedundantSensor); + void addSecondRedundantSensor( + AbstractTemperatureSensor* secondRedundantSensor); + void addThermalModule(ThermalModule* thermalModule, Priority priority); + + void setPriority(Priority priority); + + virtual ~ThermalComponentCore(); + + virtual HeaterRequest performOperation(uint8_t opCode); + + void markStateIgnored(); + + object_id_t getObjectId(); + + uint8_t getDomainId() const; + + virtual float getLowerOpLimit(); + + ReturnValue_t setTargetState(int8_t newState); + + virtual void setOutputInvalid(); + + virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex); + +protected: + + AbstractTemperatureSensor *sensor = nullptr; + AbstractTemperatureSensor *firstRedundantSensor = nullptr; + AbstractTemperatureSensor *secondRedundantSensor = nullptr; + ThermalModuleIF *thermalModule = nullptr; + + lp_var_t temperature; + lp_var_t targetState; + lp_var_t currentState; + lp_var_t heaterRequest; + + bool isHeating = false; + + bool isSafeComponent = false; + + float minTemp = 999; + + float maxTemp = AbstractTemperatureSensor::ZERO_KELVIN_C; + + Parameters parameters; + + const uint8_t domainId; + + ThermalMonitorReporter temperatureMonitor; + + virtual float getTemperature(); + virtual State getState(float temperature, Parameters parameters, + int8_t targetState); + + virtual void checkLimits(State state); + + virtual HeaterRequest getHeaterRequest(int8_t targetState, + float temperature, Parameters parameters); + + virtual State getIgnoredState(int8_t state); + + void updateMinMaxTemp(); + + virtual Parameters getParameters(); +}; + +#endif /* FSFW_THERMAL_THERMALCOMPONENT_CORE_H_ */ diff --git a/thermal/ThermalComponentIF.h b/thermal/ThermalComponentIF.h index 522d4e44..89c2b2d0 100644 --- a/thermal/ThermalComponentIF.h +++ b/thermal/ThermalComponentIF.h @@ -10,11 +10,11 @@ class ThermalComponentIF : public HasParametersIF { public: static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TCS_1; - static const Event COMPONENT_TEMP_LOW = MAKE_EVENT(1, SEVERITY::LOW); - static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, SEVERITY::LOW); - static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, SEVERITY::LOW); - static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, SEVERITY::LOW); - static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(5, SEVERITY::LOW); //!< Is thrown when a device should start-up, but the temperature is out of OP range. P1: thermalState of the component, P2: 0 + static const Event COMPONENT_TEMP_LOW = MAKE_EVENT(1, severity::LOW); + static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, severity::LOW); + static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, severity::LOW); + static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, severity::LOW); + static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(5, severity::LOW); //!< Is thrown when a device should start-up, but the temperature is out of OP range. P1: thermalState of the component, P2: 0 static const uint8_t INTERFACE_ID = CLASS_ID::THERMAL_COMPONENT_IF; static const ReturnValue_t INVALID_TARGET_STATE = MAKE_RETURN_CODE(1); @@ -49,18 +49,18 @@ public: SAFE = 0, //!< SAFE IDLE, //!< IDLE PAYLOAD, //!< PAYLOAD - NUMBER_OF_PRIORITIES //!< MAX_PRIORITY + NUMBER_OF_PRIORITIES //!< MAX_PRIORITY }; /** * The elements are ordered by priority, lowest have highest priority */ enum HeaterRequest { - HEATER_REQUEST_EMERGENCY_OFF = 0, //!< REQUEST_EMERGENCY_OFF - HEATER_REQUEST_EMERGENCY_ON, //!< REQUEST_EMERGENCY_ON - HEATER_REQUEST_OFF, //!< REQUEST_OFF - HEATER_REQUEST_ON, //!< REQUEST_ON - HEATER_DONT_CARE //!< DONT_CARE + HEATER_REQUEST_EMERGENCY_OFF = 0, //!< REQUEST_EMERGENCY_OFF + HEATER_REQUEST_EMERGENCY_ON, //!< REQUEST_EMERGENCY_ON + HEATER_REQUEST_OFF, //!< REQUEST_OFF + HEATER_REQUEST_ON, //!< REQUEST_ON + HEATER_DONT_CARE //!< DONT_CARE }; virtual ~ThermalComponentIF() { diff --git a/thermal/ThermalModule.cpp b/thermal/ThermalModule.cpp index c573008e..457a6743 100644 --- a/thermal/ThermalModule.cpp +++ b/thermal/ThermalModule.cpp @@ -1,28 +1,31 @@ -#include "../monitoring/LimitViolationReporter.h" -#include "../monitoring/MonitoringMessageContent.h" #include "ThermalModule.h" - #include "AbstractTemperatureSensor.h" -ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, - uint32_t currentStatePoolId, uint32_t targetStatePoolId, - DataSet *dataSet, Parameters parameters, +#include "../monitoring/LimitViolationReporter.h" +#include "../monitoring/MonitoringMessageContent.h" + + +ThermalModule::ThermalModule(gp_id_t moduleTemperaturePoolId, + gp_id_t currentStatePoolId, gp_id_t targetStatePoolId, + LocalPoolDataSetBase *dataSet, Parameters parameters, RedundantHeater::Parameters heaterParameters) : - oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating( - false), parameters(parameters), moduleTemperature( - moduleTemperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), currentState( - currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE), targetState( - targetStatePoolId, dataSet, PoolVariableIF::VAR_READ) { + oldStrategy(ACTIVE_SINGLE), parameters(parameters), + moduleTemperature(moduleTemperaturePoolId, dataSet, + PoolVariableIF::VAR_WRITE), + currentState(currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE), + targetState(targetStatePoolId, dataSet, PoolVariableIF::VAR_READ) { heater = new RedundantHeater(heaterParameters); } -ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, DataSet* dataSet) : - oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating( - false), parameters( { 0, 0 }), moduleTemperature( - moduleTemperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), heater( - NULL), currentState(PoolVariableIF::INVALID, dataSet, - PoolVariableIF::VAR_WRITE), targetState(PoolVariableIF::INVALID, - dataSet, PoolVariableIF::VAR_READ) { +ThermalModule::ThermalModule(gp_id_t moduleTemperaturePoolId, + LocalPoolDataSetBase* dataSet) : + oldStrategy(ACTIVE_SINGLE), parameters( { 0, 0 }), + moduleTemperature(moduleTemperaturePoolId, dataSet, + PoolVariableIF::VAR_WRITE), + currentState(gp_id_t(), dataSet, + PoolVariableIF::VAR_WRITE), + targetState(gp_id_t(), dataSet, + PoolVariableIF::VAR_READ) { } ThermalModule::~ThermalModule() { @@ -30,7 +33,7 @@ ThermalModule::~ThermalModule() { } void ThermalModule::performOperation(uint8_t opCode) { - if (heater != NULL) { + if (heater != nullptr) { heater->performOperation(0); } } @@ -42,7 +45,7 @@ void ThermalModule::performMode(Strategy strategy) { ThermalComponentIF::HeaterRequest componentHeaterRequest = letComponentsPerformAndDeciceIfWeNeedToHeat(safeOnly); - if (heater == NULL) { + if (heater == nullptr) { informComponentsAboutHeaterState(false, NONE); return; } @@ -53,8 +56,8 @@ void ThermalModule::performMode(Strategy strategy) { //Components overwrite the module request. heating = ((componentHeaterRequest == ThermalComponentIF::HEATER_REQUEST_ON) - || (componentHeaterRequest - == ThermalComponentIF::HEATER_REQUEST_EMERGENCY_ON)); + or (componentHeaterRequest + == ThermalComponentIF::HEATER_REQUEST_EMERGENCY_ON)); } bool dual = (strategy == ACTIVE_DUAL); @@ -76,7 +79,7 @@ void ThermalModule::performMode(Strategy strategy) { } float ThermalModule::getTemperature() { - return moduleTemperature; + return moduleTemperature.value; } void ThermalModule::registerSensor(AbstractTemperatureSensor * sensor) { @@ -85,7 +88,8 @@ void ThermalModule::registerSensor(AbstractTemperatureSensor * sensor) { void ThermalModule::registerComponent(ThermalComponentIF* component, ThermalComponentIF::Priority priority) { - components.push_back(ComponentData( { component, priority, ThermalComponentIF::HEATER_DONT_CARE })); + components.push_back(ComponentData( { component, priority, + ThermalComponentIF::HEATER_DONT_CARE })); } void ThermalModule::calculateTemperature() { @@ -94,12 +98,13 @@ void ThermalModule::calculateTemperature() { std::list::iterator iter = sensors.begin(); for (; iter != sensors.end(); iter++) { if ((*iter)->isValid()) { - moduleTemperature = moduleTemperature + (*iter)->getTemperature(); + moduleTemperature = moduleTemperature.value + + (*iter)->getTemperature(); numberOfValidSensors++; } } if (numberOfValidSensors != 0) { - moduleTemperature = moduleTemperature / numberOfValidSensors; + moduleTemperature = moduleTemperature.value / numberOfValidSensors; moduleTemperature.setValid(PoolVariableIF::VALID); } else { moduleTemperature = INVALID_TEMPERATURE; @@ -117,9 +122,10 @@ ThermalComponentIF* ThermalModule::findComponent(object_id_t objectId) { return NULL; } -ThermalComponentIF::HeaterRequest ThermalModule::letComponentsPerformAndDeciceIfWeNeedToHeat( - bool safeOnly) { - ThermalComponentIF::HeaterRequest heaterRequests[ThermalComponentIF::NUMBER_OF_PRIORITIES]; +ThermalComponentIF::HeaterRequest +ThermalModule::letComponentsPerformAndDeciceIfWeNeedToHeat(bool safeOnly) { + ThermalComponentIF::HeaterRequest + heaterRequests[ThermalComponentIF::NUMBER_OF_PRIORITIES]; survivalTargetTemp = -999; targetTemp = -999; @@ -224,7 +230,7 @@ bool ThermalModule::calculateModuleHeaterRequestAndSetModuleStatus( limit = survivalTargetTemp; } - if (moduleTemperature >= limit) { + if (moduleTemperature.value >= limit) { currentState = OPERATIONAL; } else { currentState = NON_OPERATIONAL; @@ -250,15 +256,16 @@ bool ThermalModule::calculateModuleHeaterRequestAndSetModuleStatus( } void ThermalModule::setHeating(bool on) { - DataSet mySet; - PoolVariable writableTargetState(targetState.getDataPoolId(), - &mySet, PoolVariableIF::VAR_WRITE); - if (on) { - writableTargetState = STATE_REQUEST_HEATING; - } else { - writableTargetState = STATE_REQUEST_PASSIVE; + ReturnValue_t result = targetState.read(); + if(result == HasReturnvaluesIF::RETURN_OK) { + if(on) { + targetState.value = STATE_REQUEST_HEATING; + } + else { + targetState.value = STATE_REQUEST_PASSIVE; + } } - mySet.commit(PoolVariableIF::VALID); + targetState.setValid(true); } void ThermalModule::updateTargetTemperatures(ThermalComponentIF* component, diff --git a/thermal/ThermalModule.h b/thermal/ThermalModule.h index 19ab9a54..0abe51c7 100644 --- a/thermal/ThermalModule.h +++ b/thermal/ThermalModule.h @@ -1,16 +1,23 @@ -#ifndef THERMALMODULE_H_ -#define THERMALMODULE_H_ +#ifndef FSFW_THERMAL_THERMALMODULE_H_ +#define FSFW_THERMAL_THERMALMODULE_H_ -#include "../datapool/DataSet.h" -#include "../datapool/PoolVariable.h" -#include "../devicehandlers/HealthDevice.h" -#include "../events/EventReportingProxyIF.h" #include "ThermalModuleIF.h" -#include #include "tcsDefinitions.h" #include "RedundantHeater.h" + +#include "../datapoollocal/LocalPoolDataSetBase.h" +#include "../datapoollocal/LocalPoolVariable.h" +#include "../devicehandlers/HealthDevice.h" +#include "../events/EventReportingProxyIF.h" + +#include + + class PowerSwitchIF; +/** + * @brief Allows creation of different thermal control domains within a system. + */ class ThermalModule: public ThermalModuleIF { friend class ThermalController; public: @@ -19,11 +26,12 @@ public: float hysteresis; }; - ThermalModule(uint32_t moduleTemperaturePoolId, uint32_t currentStatePoolId, - uint32_t targetStatePoolId, DataSet *dataSet, Parameters parameters, - RedundantHeater::Parameters heaterParameters); + ThermalModule(gp_id_t moduleTemperaturePoolId, gp_id_t currentStatePoolId, + gp_id_t targetStatePoolId, LocalPoolDataSetBase *dataSet, + Parameters parameters, RedundantHeater::Parameters heaterParameters); - ThermalModule(uint32_t moduleTemperaturePoolId, DataSet *dataSet); + ThermalModule(gp_id_t moduleTemperaturePoolId, + LocalPoolDataSetBase *dataSet); virtual ~ThermalModule(); @@ -59,20 +67,20 @@ protected: Strategy oldStrategy; - float survivalTargetTemp; + float survivalTargetTemp = 0.0; - float targetTemp; + float targetTemp = 0.0; - bool heating; + bool heating = false; Parameters parameters; - db_float_t moduleTemperature; + lp_var_t moduleTemperature; - RedundantHeater *heater; + RedundantHeater *heater = nullptr; - db_int8_t currentState; - db_int8_t targetState; + lp_var_t currentState; + lp_var_t targetState; std::list sensors; std::list components; @@ -89,4 +97,4 @@ protected: void updateTargetTemperatures(ThermalComponentIF *component, bool isSafe); }; -#endif /* THERMALMODULE_H_ */ +#endif /* FSFW_THERMAL_THERMALMODULE_H_ */ diff --git a/thermal/ThermalMonitor.h b/thermal/ThermalMonitor.h deleted file mode 100644 index 5c6806c1..00000000 --- a/thermal/ThermalMonitor.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef FRAMEWORK_THERMAL_THERMALMONITOR_H_ -#define FRAMEWORK_THERMAL_THERMALMONITOR_H_ - -#include "../monitoring/MonitorReporter.h" -#include "ThermalComponentIF.h" - -class ThermalMonitor: public MonitorReporter { -public: - template - ThermalMonitor(Args ... args) : - MonitorReporter(std::forward(args)...) { - } - ~ThermalMonitor(); - ReturnValue_t translateState(ThermalComponentIF::State state, float sample, - float lowerLimit, float upperLimit, bool componentIsOperational = true); - - bool isAboveHighLimit(); -protected: - virtual void sendTransitionEvent(float currentValue, ReturnValue_t state); - -}; - -#endif /* FRAMEWORK_THERMAL_THERMALMONITOR_H_ */ diff --git a/thermal/ThermalMonitor.cpp b/thermal/ThermalMonitorReporter.cpp similarity index 76% rename from thermal/ThermalMonitor.cpp rename to thermal/ThermalMonitorReporter.cpp index 11abfbe5..cefc6110 100644 --- a/thermal/ThermalMonitor.cpp +++ b/thermal/ThermalMonitorReporter.cpp @@ -1,10 +1,12 @@ -#include "ThermalMonitor.h" +#include "ThermalMonitorReporter.h" #include "ThermalComponentIF.h" + #include "../monitoring/MonitoringIF.h" -ThermalMonitor::~ThermalMonitor() { + +ThermalMonitorReporter::~ThermalMonitorReporter() { } -void ThermalMonitor::sendTransitionEvent(float currentValue, +void ThermalMonitorReporter::sendTransitionEvent(float currentValue, ReturnValue_t state) { switch (state) { case MonitoringIF::BELOW_LOW_LIMIT: @@ -28,7 +30,7 @@ void ThermalMonitor::sendTransitionEvent(float currentValue, } } -bool ThermalMonitor::isAboveHighLimit() { +bool ThermalMonitorReporter::isAboveHighLimit() { if (oldState == ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT) { return true; } else { @@ -36,7 +38,8 @@ bool ThermalMonitor::isAboveHighLimit() { } } -ReturnValue_t ThermalMonitor::translateState(ThermalComponentIF::State state, float sample, float lowerLimit, +ReturnValue_t ThermalMonitorReporter::translateState( + ThermalComponentIF::State state, float sample, float lowerLimit, float upperLimit, bool componentIsOperational) { if (ThermalComponentIF::isIgnoredState(state)) { setToUnchecked(); @@ -44,10 +47,12 @@ ReturnValue_t ThermalMonitor::translateState(ThermalComponentIF::State state, fl } switch (state) { case ThermalComponentIF::OUT_OF_RANGE_LOW: - return monitorStateIs(MonitoringIF::BELOW_LOW_LIMIT, sample, lowerLimit); + return monitorStateIs(MonitoringIF::BELOW_LOW_LIMIT, sample, + lowerLimit); case ThermalComponentIF::NON_OPERATIONAL_LOW: if (componentIsOperational) { - return monitorStateIs(ThermalComponentIF::BELOW_OPERATIONAL_LIMIT, sample, lowerLimit); + return monitorStateIs(ThermalComponentIF::BELOW_OPERATIONAL_LIMIT, + sample, lowerLimit); } else { return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0); } @@ -55,12 +60,14 @@ ReturnValue_t ThermalMonitor::translateState(ThermalComponentIF::State state, fl return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0); case ThermalComponentIF::NON_OPERATIONAL_HIGH: if (componentIsOperational) { - return monitorStateIs(ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT, sample, upperLimit); + return monitorStateIs(ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT, + sample, upperLimit); } else { return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0); } case ThermalComponentIF::OUT_OF_RANGE_HIGH: - return monitorStateIs(MonitoringIF::ABOVE_HIGH_LIMIT, sample, upperLimit); + return monitorStateIs(MonitoringIF::ABOVE_HIGH_LIMIT, sample, + upperLimit); default: //Never reached, all states covered. return HasReturnvaluesIF::RETURN_FAILED; diff --git a/thermal/ThermalMonitorReporter.h b/thermal/ThermalMonitorReporter.h new file mode 100644 index 00000000..4fb68a99 --- /dev/null +++ b/thermal/ThermalMonitorReporter.h @@ -0,0 +1,28 @@ +#ifndef FSFW_THERMAL_THERMALMONITORREPORTER_H_ +#define FSFW_THERMAL_THERMALMONITORREPORTER_H_ + +#include "ThermalComponentIF.h" +#include "../monitoring/MonitorReporter.h" + + +/** + * @brief Monitor Reporter implementation for thermal components. + */ +class ThermalMonitorReporter: public MonitorReporter { +public: + template + ThermalMonitorReporter(Args ... args) : + MonitorReporter(std::forward(args)...) { + } + ~ThermalMonitorReporter(); + ReturnValue_t translateState(ThermalComponentIF::State state, float sample, + float lowerLimit, float upperLimit, + bool componentIsOperational = true); + + bool isAboveHighLimit(); +protected: + virtual void sendTransitionEvent(float currentValue, ReturnValue_t state); + +}; + +#endif /* FSFW_THERMAL_THERMALMONITORREPORTERREPORTER_H_ */ diff --git a/thermal/tcsDefinitions.h b/thermal/tcsDefinitions.h index ad258ced..37e5b849 100644 --- a/thermal/tcsDefinitions.h +++ b/thermal/tcsDefinitions.h @@ -2,7 +2,7 @@ #define TCSDEFINITIONS_H_ -static const uint32_t INVALID_TEMPERATURE = 999; +static const float INVALID_TEMPERATURE = 999; #endif /* TCSDEFINITIONS_H_ */ diff --git a/timemanager/CMakeLists.txt b/timemanager/CMakeLists.txt new file mode 100644 index 00000000..3367775f --- /dev/null +++ b/timemanager/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + CCSDSTime.cpp + Countdown.cpp + Stopwatch.cpp + TimeMessage.cpp + TimeStamper.cpp +) diff --git a/timemanager/Clock.h b/timemanager/Clock.h index acb68e2e..bc112388 100644 --- a/timemanager/Clock.h +++ b/timemanager/Clock.h @@ -2,7 +2,7 @@ #define FRAMEWORK_TIMEMANAGER_CLOCK_H_ #include "../returnvalues/HasReturnvaluesIF.h" -#include "../ipc/MutexFactory.h" +#include "../ipc/MutexHelper.h" #include "../globalfunctions/timevalOperations.h" #include diff --git a/tmstorage/CMakeLists.txt b/tmstorage/CMakeLists.txt new file mode 100644 index 00000000..7990d85a --- /dev/null +++ b/tmstorage/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + TmStoreMessage.cpp +) diff --git a/tmstorage/TmStoreBackendIF.h b/tmstorage/TmStoreBackendIF.h index a441808e..4b2a8836 100644 --- a/tmstorage/TmStoreBackendIF.h +++ b/tmstorage/TmStoreBackendIF.h @@ -31,22 +31,22 @@ public: static const ReturnValue_t INVALID_REQUEST = MAKE_RETURN_CODE(15); static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MEMORY; - static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, SEVERITY::LOW); //!< Initiating sending data to store failed. Low, par1: returnCode, par2: integer (debug info) - static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, SEVERITY::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0 - static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, SEVERITY::LOW); //!< Initiating reading data from store failed. Low, par1: returnCode, par2: 0 - static const Event STORE_READ_FAILED = MAKE_EVENT(3, SEVERITY::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0 - static const Event UNEXPECTED_MSG = MAKE_EVENT(4, SEVERITY::LOW); //!< An unexpected TM packet or data message occurred. Low, par1: 0, par2: integer (debug info) - static const Event STORING_FAILED = MAKE_EVENT(5, SEVERITY::LOW); //!< Storing data failed. May simply be a full store. Low, par1: returnCode, par2: integer (sequence count of failed packet). - static const Event TM_DUMP_FAILED = MAKE_EVENT(6, SEVERITY::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode, par2: integer (sequence count of failed packet). - static const Event STORE_INIT_FAILED = MAKE_EVENT(7, SEVERITY::LOW); //!< Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info) - static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, SEVERITY::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero. - static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, SEVERITY::LOW); //!< Data was read out, but it is inconsistent. Low par1: Memory address of corruption, par2: integer (debug info) - static const Event STORE_INITIALIZE = MAKE_EVENT(10, SEVERITY::INFO); //!< Info event indicating the store will be initialized, either at boot or after IOB switch. Info. pars: 0 - static const Event INIT_DONE = MAKE_EVENT(11, SEVERITY::INFO); //!< Info event indicating the store was successfully initialized, either at boot or after IOB switch. Info. pars: 0 - static const Event DUMP_FINISHED = MAKE_EVENT(12, SEVERITY::INFO); //!< Info event indicating that dumping finished successfully. par1: Number of dumped packets. par2: APID/SSC (16bits each) - static const Event DELETION_FINISHED = MAKE_EVENT(13, SEVERITY::INFO); //!< Info event indicating that deletion finished successfully. par1: Number of deleted packets. par2: APID/SSC (16bits each) - static const Event DELETION_FAILED = MAKE_EVENT(14, SEVERITY::LOW); //!< Info event indicating that something went wrong during deletion. pars: 0 - static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, SEVERITY::INFO);//!< Info that the a auto catalog report failed + static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, severity::LOW); //!< Initiating sending data to store failed. Low, par1: returnCode, par2: integer (debug info) + static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, severity::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0 + static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, severity::LOW); //!< Initiating reading data from store failed. Low, par1: returnCode, par2: 0 + static const Event STORE_READ_FAILED = MAKE_EVENT(3, severity::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0 + static const Event UNEXPECTED_MSG = MAKE_EVENT(4, severity::LOW); //!< An unexpected TM packet or data message occurred. Low, par1: 0, par2: integer (debug info) + static const Event STORING_FAILED = MAKE_EVENT(5, severity::LOW); //!< Storing data failed. May simply be a full store. Low, par1: returnCode, par2: integer (sequence count of failed packet). + static const Event TM_DUMP_FAILED = MAKE_EVENT(6, severity::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode, par2: integer (sequence count of failed packet). + static const Event STORE_INIT_FAILED = MAKE_EVENT(7, severity::LOW); //!< Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info) + static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, severity::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero. + static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, severity::LOW); //!< Data was read out, but it is inconsistent. Low par1: Memory address of corruption, par2: integer (debug info) + static const Event STORE_INITIALIZE = MAKE_EVENT(10, severity::INFO); //!< Info event indicating the store will be initialized, either at boot or after IOB switch. Info. pars: 0 + static const Event INIT_DONE = MAKE_EVENT(11, severity::INFO); //!< Info event indicating the store was successfully initialized, either at boot or after IOB switch. Info. pars: 0 + static const Event DUMP_FINISHED = MAKE_EVENT(12, severity::INFO); //!< Info event indicating that dumping finished successfully. par1: Number of dumped packets. par2: APID/SSC (16bits each) + static const Event DELETION_FINISHED = MAKE_EVENT(13, severity::INFO); //!< Info event indicating that deletion finished successfully. par1: Number of deleted packets. par2: APID/SSC (16bits each) + static const Event DELETION_FAILED = MAKE_EVENT(14, severity::LOW); //!< Info event indicating that something went wrong during deletion. pars: 0 + static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, severity::INFO);//!< Info that the a auto catalog report failed virtual ~TmStoreBackendIF() {} virtual ReturnValue_t performOperation(uint8_t opCode) = 0; diff --git a/tmtcpacket/CMakeLists.txt b/tmtcpacket/CMakeLists.txt new file mode 100644 index 00000000..fe3d2a4d --- /dev/null +++ b/tmtcpacket/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + SpacePacket.cpp + SpacePacketBase.cpp +) + +add_subdirectory(packetmatcher) +add_subdirectory(pus) \ No newline at end of file diff --git a/tmtcpacket/packetmatcher/CMakeLists.txt b/tmtcpacket/packetmatcher/CMakeLists.txt new file mode 100644 index 00000000..e9a8d03b --- /dev/null +++ b/tmtcpacket/packetmatcher/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + PacketMatchTree.cpp +) diff --git a/tmtcpacket/packetmatcher/PacketMatchTree.cpp b/tmtcpacket/packetmatcher/PacketMatchTree.cpp index a4579657..ac72b3e7 100644 --- a/tmtcpacket/packetmatcher/PacketMatchTree.cpp +++ b/tmtcpacket/packetmatcher/PacketMatchTree.cpp @@ -3,19 +3,30 @@ #include "ServiceMatcher.h" #include "SubserviceMatcher.h" +// This should be configurable.. +const LocalPool::LocalPoolConfig PacketMatchTree::poolConfig = { + {10, sizeof(ServiceMatcher)}, + {20, sizeof(SubServiceMatcher)}, + {2, sizeof(ApidMatcher)}, + {40, sizeof(PacketMatchTree::Node)} +}; + PacketMatchTree::PacketMatchTree(Node* root) : - MatchTree(root, 2), factoryBackend(0, POOL_SIZES, - N_ELEMENTS, false, true), factory(&factoryBackend) { + MatchTree(root, 2), + factoryBackend(0, poolConfig, false, true), + factory(&factoryBackend) { } PacketMatchTree::PacketMatchTree(iterator root) : - MatchTree(root.element, 2), factoryBackend(0, - POOL_SIZES, N_ELEMENTS, false, true), factory(&factoryBackend) { + MatchTree(root.element, 2), + factoryBackend(0, poolConfig, false, true), + factory(&factoryBackend) { } PacketMatchTree::PacketMatchTree() : - MatchTree((Node*) NULL, 2), factoryBackend(0, - POOL_SIZES, N_ELEMENTS, false, true), factory(&factoryBackend) { + MatchTree((Node*) NULL, 2), + factoryBackend(0, poolConfig, false, true), + factory(&factoryBackend) { } PacketMatchTree::~PacketMatchTree() { @@ -172,11 +183,6 @@ ReturnValue_t PacketMatchTree::initialize() { return factoryBackend.initialize(); } -const uint16_t PacketMatchTree::POOL_SIZES[N_POOLS] = { sizeof(ServiceMatcher), - sizeof(SubServiceMatcher), sizeof(ApidMatcher), - sizeof(PacketMatchTree::Node) }; -//Maximum number of types and subtypes to filter should be more than sufficient. -const uint16_t PacketMatchTree::N_ELEMENTS[N_POOLS] = { 10, 20, 2, 40 }; ReturnValue_t PacketMatchTree::changeMatch(bool addToMatch, uint16_t apid, uint8_t type, uint8_t subtype) { diff --git a/tmtcpacket/packetmatcher/PacketMatchTree.h b/tmtcpacket/packetmatcher/PacketMatchTree.h index 86fb087e..54fc856c 100644 --- a/tmtcpacket/packetmatcher/PacketMatchTree.h +++ b/tmtcpacket/packetmatcher/PacketMatchTree.h @@ -23,8 +23,9 @@ protected: ReturnValue_t cleanUpElement(iterator position); private: static const uint8_t N_POOLS = 4; - LocalPool factoryBackend; + LocalPool factoryBackend; PlacementFactory factory; + static const LocalPool::LocalPoolConfig poolConfig; static const uint16_t POOL_SIZES[N_POOLS]; static const uint16_t N_ELEMENTS[N_POOLS]; template diff --git a/tmtcpacket/pus/CMakeLists.txt b/tmtcpacket/pus/CMakeLists.txt new file mode 100644 index 00000000..fcfc82d2 --- /dev/null +++ b/tmtcpacket/pus/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + TcPacketBase.cpp + TcPacketStored.cpp + TmPacketBase.cpp + TmPacketMinimal.cpp + TmPacketStored.cpp +) diff --git a/tmtcservices/CMakeLists.txt b/tmtcservices/CMakeLists.txt new file mode 100644 index 00000000..c30af214 --- /dev/null +++ b/tmtcservices/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + CommandingServiceBase.cpp + PusServiceBase.cpp + PusVerificationReport.cpp + TmTcBridge.cpp + TmTcMessage.cpp + VerificationReporter.cpp +) \ No newline at end of file diff --git a/unittest/core/CatchSetup.cpp b/unittest/core/CatchSetup.cpp index f8543fd2..cb5bd33e 100644 --- a/unittest/core/CatchSetup.cpp +++ b/unittest/core/CatchSetup.cpp @@ -1,8 +1,7 @@ #include "CatchDefinitions.h" +#include "CatchFactory.h" #include -#include - #ifdef GCOV #include diff --git a/unittest/internal/InternalUnitTester.h b/unittest/internal/InternalUnitTester.h index b301b923..d0b1c106 100644 --- a/unittest/internal/InternalUnitTester.h +++ b/unittest/internal/InternalUnitTester.h @@ -2,7 +2,7 @@ #define FRAMEWORK_TEST_UNITTESTCLASS_H_ #include "UnittDefinitions.h" -#include +#include "../../returnvalues/HasReturnvaluesIF.h" /** * @brief Can be used for internal testing, for example for hardware specific diff --git a/unittest/internal/UnittDefinitions.cpp b/unittest/internal/UnittDefinitions.cpp index 0bdbfcc7..6265e9fd 100644 --- a/unittest/internal/UnittDefinitions.cpp +++ b/unittest/internal/UnittDefinitions.cpp @@ -1,4 +1,4 @@ -#include +#include "UnittDefinitions.h" ReturnValue_t unitt::put_error(std::string errorId) { sif::error << "Unit Tester error: Failed at test ID " diff --git a/unittest/internal/osal/IntTestMq.cpp b/unittest/internal/osal/IntTestMq.cpp index 63016374..8d95f51e 100644 --- a/unittest/internal/osal/IntTestMq.cpp +++ b/unittest/internal/osal/IntTestMq.cpp @@ -1,7 +1,8 @@ -#include -#include -#include -#include +#include "IntTestMq.h" +#include "../UnittDefinitions.h" + +#include "../../ipc/MessageQueueIF.h" +#include "../../ipc/QueueFactory.h" #include diff --git a/unittest/internal/osal/IntTestMutex.cpp b/unittest/internal/osal/IntTestMutex.cpp index 3fd668df..01581347 100644 --- a/unittest/internal/osal/IntTestMutex.cpp +++ b/unittest/internal/osal/IntTestMutex.cpp @@ -1,10 +1,10 @@ #include "IntTestMutex.h" -#include -#include +#include "../../ipc/MutexFactory.h" +#include "../UnittDefinitions.h" #if defined(hosted) -#include +#include "../../osal/hosted/Mutex.h" #include #include #endif @@ -20,7 +20,7 @@ void testmutex::testMutex() { // timed_mutex from the C++ library specifies undefined behaviour if // the timed mutex is locked twice from the same thread. #if defined(hosted) - // hold on, this actually worked ? :-D This calls the function from + // This calls the function from // another thread and stores the returnvalue in a future. auto future = std::async(&MutexIF::lockMutex, mutex, 1); result = future.get(); diff --git a/unittest/internal/osal/IntTestSemaphore.cpp b/unittest/internal/osal/IntTestSemaphore.cpp index 534a6a6d..f260b6a5 100644 --- a/unittest/internal/osal/IntTestSemaphore.cpp +++ b/unittest/internal/osal/IntTestSemaphore.cpp @@ -1,8 +1,9 @@ #include "IntTestSemaphore.h" -#include -#include -#include -#include +#include "../UnittDefinitions.h" + +#include "../../tasks/SemaphoreFactory.h" +#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../timemanager/Stopwatch.h" void testsemaph::testBinSemaph() { diff --git a/unittest/internal/serialize/IntTestSerialization.cpp b/unittest/internal/serialize/IntTestSerialization.cpp index 3f231a41..1e33ff33 100644 --- a/unittest/internal/serialize/IntTestSerialization.cpp +++ b/unittest/internal/serialize/IntTestSerialization.cpp @@ -1,8 +1,9 @@ #include "IntTestSerialization.h" -#include -#include -#include -#include +#include "../UnittDefinitions.h" +#include "../../serialize/SerializeElement.h" +#include "../../serialize/SerialBufferAdapter.h" +#include "../../serialize/SerializeIF.h" + #include using retval = HasReturnvaluesIF; diff --git a/unittest/internal/serialize/IntTestSerialization.h b/unittest/internal/serialize/IntTestSerialization.h index f8841b82..e8dbd35a 100644 --- a/unittest/internal/serialize/IntTestSerialization.h +++ b/unittest/internal/serialize/IntTestSerialization.h @@ -1,6 +1,7 @@ -#ifndef UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ -#define UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ -#include +#ifndef FSFW_UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ +#define FSFW_UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ + +#include "../../returnvalues/HasReturnvaluesIF.h" #include namespace testserialize { @@ -12,4 +13,4 @@ ReturnValue_t test_serial_buffer_adapter(); extern std::array test_array; } -#endif /* UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ */ +#endif /* FSFW_UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ */ diff --git a/unittest/testcfg/CatchFactory.cpp b/unittest/testcfg/CatchFactory.cpp new file mode 100644 index 00000000..c74a8126 --- /dev/null +++ b/unittest/testcfg/CatchFactory.cpp @@ -0,0 +1,60 @@ +#include "CatchFactory.h" + +#include +#include + +#include +#include +#include + +/** + * @brief Produces system objects. + * @details + * Build tasks by using SystemObject Interface (Interface). + * Header files of all tasks must be included + * Please note that an object has to implement the system object interface + * if the interface validity is checked or retrieved later by using the + * get(object_id) function from the ObjectManagerIF. + * + * Framework objects are created first. + * + * @ingroup init + */ +void Factory::produce(void) { + setStaticFrameworkObjectIds(); + new EventManager(objects::EVENT_MANAGER); + new HealthTable(objects::HEALTH_TABLE); + //new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); + + { + static constexpr uint8_t NUMBER_OF_POOLS = 5; + const uint16_t element_sizes[NUMBER_OF_POOLS] = {16, 32, 64, 128, 1024}; + const uint16_t n_elements[NUMBER_OF_POOLS] = {100, 50, 25, 15, 5}; + new PoolManager(objects::TC_STORE, element_sizes, + n_elements); + } + + { + static constexpr uint8_t NUMBER_OF_POOLS = 5; + const uint16_t element_sizes[NUMBER_OF_POOLS] = {16, 32, 64, 128, 1024}; + const uint16_t n_elements[NUMBER_OF_POOLS] = {100, 50, 25, 15, 5}; + new PoolManager(objects::TM_STORE, element_sizes, + n_elements); + } + + { + static constexpr uint8_t NUMBER_OF_POOLS = 6; + const uint16_t element_sizes[NUMBER_OF_POOLS] = {32, 64, 512, + 1024, 2048, 4096}; + const uint16_t n_elements[NUMBER_OF_POOLS] = {200, 100, 50, 25, 15, 5}; + new PoolManager(objects::IPC_STORE, element_sizes, + n_elements); + } + +} + +void Factory::setStaticFrameworkObjectIds() { + +} + + diff --git a/unittest/testcfg/objects/Factory.h b/unittest/testcfg/CatchFactory.h similarity index 100% rename from unittest/testcfg/objects/Factory.h rename to unittest/testcfg/CatchFactory.h diff --git a/unittest/testcfg/objects/Factory.cpp b/unittest/testcfg/objects/Factory.cpp deleted file mode 100644 index e05b7942..00000000 --- a/unittest/testcfg/objects/Factory.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "Factory.h" - -#include -#include - -#include -#include - -/** - * @brief Produces system objects. - * @details - * Build tasks by using SystemObject Interface (Interface). - * Header files of all tasks must be included - * Please note that an object has to implement the system object interface - * if the interface validity is checked or retrieved later by using the - * get(object_id) function from the ObjectManagerIF. - * - * Framework objects are created first. - * - * @ingroup init - */ -void Factory::produce(void) { - setStaticFrameworkObjectIds(); - new EventManager(objects::EVENT_MANAGER); - new HealthTable(objects::HEALTH_TABLE); - new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); - -} - -void Factory::setStaticFrameworkObjectIds() { - -} - - diff --git a/unittest/testcfg/testcfg.mk b/unittest/testcfg/testcfg.mk index 64fa87f6..31d3b60a 100644 --- a/unittest/testcfg/testcfg.mk +++ b/unittest/testcfg/testcfg.mk @@ -3,6 +3,7 @@ CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp) CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp) CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp) CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp) +CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) INCLUDES += $(CURRENTPATH) INCLUDES += $(CURRENTPATH)/objects diff --git a/unittest/tests/action/TestActionHelper.cpp b/unittest/tests/action/TestActionHelper.cpp index d5b2e467..944ad705 100644 --- a/unittest/tests/action/TestActionHelper.cpp +++ b/unittest/tests/action/TestActionHelper.cpp @@ -1,106 +1,107 @@ -//#include "TestActionHelper.h" -//#include -//#include -//#include -//#include "../../core/CatchDefinitions.h" -// -// -//TEST_CASE( "Action Helper" , "[ActionHelper]") { -// ActionHelperOwnerMockBase testDhMock; -// MessageQueueMockBase testMqMock; -// ActionHelper actionHelper = ActionHelper( -// &testDhMock, dynamic_cast(&testMqMock)); -// CommandMessage actionMessage; -// ActionId_t testActionId = 777; -// std::array testParams {1, 2, 3}; -// store_address_t paramAddress; -// StorageManagerIF *ipcStore = tglob::getIpcStoreHandle(); -// ipcStore->addData(¶mAddress, testParams.data(), 3); -// REQUIRE(actionHelper.initialize() == retval::CATCH_OK); -// -// SECTION ("Simple tests") { -// ActionMessage::setCommand(&actionMessage, testActionId, paramAddress); -// CHECK(not testDhMock.executeActionCalled); -// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK); -// CHECK(testDhMock.executeActionCalled); -// // No message is sent if everything is alright. -// CHECK(not testMqMock.wasMessageSent()); -// store_address_t invalidAddress; -// ActionMessage::setCommand(&actionMessage, testActionId, invalidAddress); -// actionHelper.handleActionMessage(&actionMessage); -// CHECK(testMqMock.wasMessageSent()); -// const uint8_t* ptr = nullptr; -// size_t size = 0; -// REQUIRE(ipcStore->getData(paramAddress, &ptr, &size) == static_cast(StorageManagerIF::DATA_DOES_NOT_EXIST)); -// REQUIRE(ptr == nullptr); -// REQUIRE(size == 0); -// testDhMock.getBuffer(&ptr, &size); -// REQUIRE(size == 3); -// for(uint8_t i = 0; i<3;i++){ -// REQUIRE(ptr[i] == (i+1)); -// } -// testDhMock.clearBuffer(); -// } -// -// SECTION("Handle failures"){ -// actionMessage.setCommand(1234); -// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == static_cast(CommandMessage::UNKNOWN_COMMAND)); -// CHECK(not testMqMock.wasMessageSent()); -// uint16_t step = 5; -// ReturnValue_t status = 0x1234; -// actionHelper.step(step, testMqMock.getId(), testActionId, status); -// step += 1; -// CHECK(testMqMock.wasMessageSent()); -// CommandMessage testMessage; -// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); -// REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); -// REQUIRE(testMessage.getParameter() == static_cast(testActionId)); -// uint32_t parameter2 = ((uint32_t)step << 16) | (uint32_t)status; -// REQUIRE(testMessage.getParameter2() == parameter2); -// REQUIRE(ActionMessage::getStep(&testMessage) == step); -// } -// -// SECTION("Handle finish"){ -// CHECK(not testMqMock.wasMessageSent()); -// ReturnValue_t status = 0x9876; -// actionHelper.finish(testMqMock.getId(), testActionId, status); -// CHECK(testMqMock.wasMessageSent()); -// CommandMessage testMessage; -// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); -// REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::COMPLETION_FAILED)); -// REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId); -// REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast(status)); -// } -// -// SECTION("Handle failed"){ -// store_address_t toLongParamAddress = StorageManagerIF::INVALID_ADDRESS; -// std::array toLongData = {5, 4, 3, 2, 1}; -// REQUIRE(ipcStore->addData(&toLongParamAddress, toLongData.data(), 5) == retval::CATCH_OK); -// ActionMessage::setCommand(&actionMessage, testActionId, toLongParamAddress); -// CHECK(not testDhMock.executeActionCalled); -// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK); -// REQUIRE(ipcStore->getData(toLongParamAddress).first == static_cast(StorageManagerIF::DATA_DOES_NOT_EXIST)); -// CommandMessage testMessage; -// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); -// REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); -// REQUIRE(ActionMessage::getReturnCode(&testMessage) == 0xAFFE); -// REQUIRE(ActionMessage::getStep(&testMessage) == 0); -// REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId); -// } -// -// SECTION("Missing IPC Data"){ -// ActionMessage::setCommand(&actionMessage, testActionId, StorageManagerIF::INVALID_ADDRESS); -// CHECK(not testDhMock.executeActionCalled); -// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK); -// CommandMessage testMessage; -// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); -// REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); -// REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast(StorageManagerIF::ILLEGAL_STORAGE_ID)); -// REQUIRE(ActionMessage::getStep(&testMessage) == 0); -// } -// -// -// SECTION("Data Reply"){ -// -// } -//} +#include "TestActionHelper.h" +#include +#include +#include +#include "../../core/CatchDefinitions.h" + + +TEST_CASE( "Action Helper" , "[ActionHelper]") { + ActionHelperOwnerMockBase testDhMock; + MessageQueueMockBase testMqMock; + ActionHelper actionHelper = ActionHelper( + &testDhMock, dynamic_cast(&testMqMock)); + CommandMessage actionMessage; + ActionId_t testActionId = 777; + std::array testParams {1, 2, 3}; + store_address_t paramAddress; + StorageManagerIF *ipcStore = tglob::getIpcStoreHandle(); + REQUIRE(ipcStore != nullptr); + ipcStore->addData(¶mAddress, testParams.data(), 3); + REQUIRE(actionHelper.initialize() == retval::CATCH_OK); + + SECTION ("Simple tests") { + ActionMessage::setCommand(&actionMessage, testActionId, paramAddress); + CHECK(not testDhMock.executeActionCalled); + REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK); + CHECK(testDhMock.executeActionCalled); + // No message is sent if everything is alright. + CHECK(not testMqMock.wasMessageSent()); + store_address_t invalidAddress; + ActionMessage::setCommand(&actionMessage, testActionId, invalidAddress); + actionHelper.handleActionMessage(&actionMessage); + CHECK(testMqMock.wasMessageSent()); + const uint8_t* ptr = nullptr; + size_t size = 0; + REQUIRE(ipcStore->getData(paramAddress, &ptr, &size) == static_cast(StorageManagerIF::DATA_DOES_NOT_EXIST)); + REQUIRE(ptr == nullptr); + REQUIRE(size == 0); + testDhMock.getBuffer(&ptr, &size); + REQUIRE(size == 3); + for(uint8_t i = 0; i<3;i++){ + REQUIRE(ptr[i] == (i+1)); + } + testDhMock.clearBuffer(); + } + + SECTION("Handle failures"){ + actionMessage.setCommand(1234); + REQUIRE(actionHelper.handleActionMessage(&actionMessage) == static_cast(CommandMessage::UNKNOWN_COMMAND)); + CHECK(not testMqMock.wasMessageSent()); + uint16_t step = 5; + ReturnValue_t status = 0x1234; + actionHelper.step(step, testMqMock.getId(), testActionId, status); + step += 1; + CHECK(testMqMock.wasMessageSent()); + CommandMessage testMessage; + REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); + REQUIRE(testMessage.getParameter() == static_cast(testActionId)); + uint32_t parameter2 = ((uint32_t)step << 16) | (uint32_t)status; + REQUIRE(testMessage.getParameter2() == parameter2); + REQUIRE(ActionMessage::getStep(&testMessage) == step); + } + + SECTION("Handle finish"){ + CHECK(not testMqMock.wasMessageSent()); + ReturnValue_t status = 0x9876; + actionHelper.finish(testMqMock.getId(), testActionId, status); + CHECK(testMqMock.wasMessageSent()); + CommandMessage testMessage; + REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::COMPLETION_FAILED)); + REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId); + REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast(status)); + } + + SECTION("Handle failed"){ + store_address_t toLongParamAddress = StorageManagerIF::INVALID_ADDRESS; + std::array toLongData = {5, 4, 3, 2, 1}; + REQUIRE(ipcStore->addData(&toLongParamAddress, toLongData.data(), 5) == retval::CATCH_OK); + ActionMessage::setCommand(&actionMessage, testActionId, toLongParamAddress); + CHECK(not testDhMock.executeActionCalled); + REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK); + REQUIRE(ipcStore->getData(toLongParamAddress).first == static_cast(StorageManagerIF::DATA_DOES_NOT_EXIST)); + CommandMessage testMessage; + REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); + REQUIRE(ActionMessage::getReturnCode(&testMessage) == 0xAFFE); + REQUIRE(ActionMessage::getStep(&testMessage) == 0); + REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId); + } + + SECTION("Missing IPC Data"){ + ActionMessage::setCommand(&actionMessage, testActionId, StorageManagerIF::INVALID_ADDRESS); + CHECK(not testDhMock.executeActionCalled); + REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK); + CommandMessage testMessage; + REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); + REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast(StorageManagerIF::ILLEGAL_STORAGE_ID)); + REQUIRE(ActionMessage::getStep(&testMessage) == 0); + } + + + SECTION("Data Reply"){ + + } +} diff --git a/unittest/tests/action/TestActionHelper.h b/unittest/tests/action/TestActionHelper.h index 9bc93d3e..4ba417eb 100644 --- a/unittest/tests/action/TestActionHelper.h +++ b/unittest/tests/action/TestActionHelper.h @@ -1,131 +1,132 @@ -//#ifndef UNITTEST_HOSTED_TESTACTIONHELPER_H_ -//#define UNITTEST_HOSTED_TESTACTIONHELPER_H_ -// -//#include -//#include -//#include -//#include -// -// -//class ActionHelperOwnerMockBase: public HasActionsIF { -//public: -// bool getCommandQueueCalled = false; -// bool executeActionCalled = false; -// static const size_t MAX_SIZE = 3; -// uint8_t buffer[MAX_SIZE] = {0, 0, 0}; -// size_t size = 0; -// -// MessageQueueId_t getCommandQueue() const override { -// return tconst::testQueueId; -// } -// -// ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, -// const uint8_t* data, size_t size) override { -// executeActionCalled = true; -// if(size > MAX_SIZE){ -// return 0xAFFE; -// } -// this->size = size; -// memcpy(buffer, data, size); -// return HasReturnvaluesIF::RETURN_OK; -// } -// -// void clearBuffer(){ -// this->size = 0; -// for(size_t i = 0; isize; -// } -// if(ptr != nullptr){ -// *ptr = buffer; -// } -// } -//}; -// -// -//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( MessageQueueMessage* message ) { -// messageSent = true; -// lastMessage = (*message); -// return HasReturnvaluesIF::RETURN_OK; -// }; -// virtual ReturnValue_t receiveMessage(MessageQueueMessage* message, -// MessageQueueId_t *receivedFrom) { -// (*message) = lastMessage; -// lastMessage.clear(); -// return HasReturnvaluesIF::RETURN_OK; -// } -// virtual ReturnValue_t receiveMessage(MessageQueueMessage* message) { -// (*message) = lastMessage; -// 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, -// MessageQueueMessage* message, MessageQueueId_t sentFrom, -// bool ignoreFault = false ) { -// messageSent = true; -// lastMessage = (*message); -// return HasReturnvaluesIF::RETURN_OK; -// } -// virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, -// MessageQueueMessage* message, bool ignoreFault = false ) override { -// messageSent = true; -// lastMessage = (*message); -// return HasReturnvaluesIF::RETURN_OK; -// } -// virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, -// MessageQueueId_t sentFrom, bool ignoreFault = false ) { -// messageSent = true; -// lastMessage = (*message); -// return HasReturnvaluesIF::RETURN_OK; -// } -// virtual ReturnValue_t sendToDefault( MessageQueueMessage* message ) { -// messageSent = true; -// lastMessage = (*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_ */ +#ifndef UNITTEST_HOSTED_TESTACTIONHELPER_H_ +#define UNITTEST_HOSTED_TESTACTIONHELPER_H_ + +#include +#include +#include +#include + + +class ActionHelperOwnerMockBase: public HasActionsIF { +public: + bool getCommandQueueCalled = false; + bool executeActionCalled = false; + static const size_t MAX_SIZE = 3; + uint8_t buffer[MAX_SIZE] = {0, 0, 0}; + size_t size = 0; + + MessageQueueId_t getCommandQueue() const override { + return tconst::testQueueId; + } + + ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, + const uint8_t* data, size_t size) override { + executeActionCalled = true; + if(size > MAX_SIZE){ + return 0xAFFE; + } + this->size = size; + memcpy(buffer, data, size); + return HasReturnvaluesIF::RETURN_OK; + } + + void clearBuffer(){ + this->size = 0; + for(size_t i = 0; isize; + } + if(ptr != nullptr){ + *ptr = buffer; + } + } +}; + + +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/RingBufferTest.cpp b/unittest/tests/container/RingBufferTest.cpp index 8b82d407..9c1c8a23 100644 --- a/unittest/tests/container/RingBufferTest.cpp +++ b/unittest/tests/container/RingBufferTest.cpp @@ -1,7 +1,7 @@ -#include -#include #include "../../core/CatchDefinitions.h" +#include "../../container/SimpleRingBuffer.h" +#include #include TEST_CASE("Ring Buffer Test" , "[RingBufferTest]") { diff --git a/unittest/tests/container/TestArrayList.cpp b/unittest/tests/container/TestArrayList.cpp index 914188cb..2f884276 100644 --- a/unittest/tests/container/TestArrayList.cpp +++ b/unittest/tests/container/TestArrayList.cpp @@ -1,5 +1,6 @@ -#include -#include +#include "../../container/ArrayList.h" +#include "../../returnvalues/HasReturnvaluesIF.h" + #include #include "../../core/CatchDefinitions.h" diff --git a/unittest/tests/container/TestDynamicFifo.cpp b/unittest/tests/container/TestDynamicFifo.cpp index 6c9b7415..bb19131e 100644 --- a/unittest/tests/container/TestDynamicFifo.cpp +++ b/unittest/tests/container/TestDynamicFifo.cpp @@ -1,7 +1,7 @@ -#include -#include -#include +#include "../../container/DynamicFIFO.h" +#include "../../container/FIFO.h" +#include "../../returnvalues/HasReturnvaluesIF.h" #include #include diff --git a/unittest/tests/container/TestFifo.cpp b/unittest/tests/container/TestFifo.cpp index 3775f424..bd727e00 100644 --- a/unittest/tests/container/TestFifo.cpp +++ b/unittest/tests/container/TestFifo.cpp @@ -1,7 +1,7 @@ -#include -#include -#include +#include "../../container/DynamicFIFO.h" +#include "../../container/FIFO.h" +#include "../../returnvalues/HasReturnvaluesIF.h" #include #include "../../core/CatchDefinitions.h" diff --git a/unittest/tests/container/TestFixedArrayList.cpp b/unittest/tests/container/TestFixedArrayList.cpp index 737932e3..5a1bd280 100644 --- a/unittest/tests/container/TestFixedArrayList.cpp +++ b/unittest/tests/container/TestFixedArrayList.cpp @@ -1,7 +1,7 @@ #include "../../core/CatchDefinitions.h" -#include -#include +#include "../../container/FixedArrayList.h" +#include "../../returnvalues/HasReturnvaluesIF.h" #include diff --git a/unittest/tests/container/TestFixedMap.cpp b/unittest/tests/container/TestFixedMap.cpp index 079062f0..da0c84e3 100644 --- a/unittest/tests/container/TestFixedMap.cpp +++ b/unittest/tests/container/TestFixedMap.cpp @@ -1,5 +1,5 @@ -#include -#include +#include "../../container/FixedMap.h" +#include "../../returnvalues/HasReturnvaluesIF.h" #include #include "../../core/CatchDefinitions.h" diff --git a/unittest/tests/container/TestFixedOrderedMultimap.cpp b/unittest/tests/container/TestFixedOrderedMultimap.cpp index 95194cb5..e625b559 100644 --- a/unittest/tests/container/TestFixedOrderedMultimap.cpp +++ b/unittest/tests/container/TestFixedOrderedMultimap.cpp @@ -1,5 +1,5 @@ -#include -#include +#include "../../container/FixedOrderedMultimap.h" +#include "../../returnvalues/HasReturnvaluesIF.h" #include #include "../../core/CatchDefinitions.h" diff --git a/unittest/tests/osal/TestMessageQueue.cpp b/unittest/tests/osal/TestMessageQueue.cpp index 8e59fa08..441d32e7 100644 --- a/unittest/tests/osal/TestMessageQueue.cpp +++ b/unittest/tests/osal/TestMessageQueue.cpp @@ -1,8 +1,8 @@ -#include -#include -#include "catch.hpp" +#include "../../ipc/MessageQueueIF.h" +#include "../../ipc/QueueFactory.h" +#include #include -#include "core/CatchDefinitions.h" +#include "../../core/CatchDefinitions.h" TEST_CASE("MessageQueue Basic Test","[TestMq]") { MessageQueueIF* testSenderMq = diff --git a/unittest/tests/serialize/TestSerialBufferAdapter.cpp b/unittest/tests/serialize/TestSerialBufferAdapter.cpp index 9919ed84..07cd3f9c 100644 --- a/unittest/tests/serialize/TestSerialBufferAdapter.cpp +++ b/unittest/tests/serialize/TestSerialBufferAdapter.cpp @@ -1,4 +1,4 @@ -#include +#include "../../serialize/SerialBufferAdapter.h" #include #include "../../core/CatchDefinitions.h" diff --git a/unittest/tests/serialize/TestSerialLinkedPacket.cpp b/unittest/tests/serialize/TestSerialLinkedPacket.cpp index 0a09e430..fbe48894 100644 --- a/unittest/tests/serialize/TestSerialLinkedPacket.cpp +++ b/unittest/tests/serialize/TestSerialLinkedPacket.cpp @@ -1,8 +1,9 @@ -#include +#include "TestSerialLinkedPacket.h" +#include "../../core/CatchDefinitions.h" + +#include "../../globalfunctions/arrayprinter.h" #include -#include "../../core/CatchDefinitions.h" -#include "TestSerialLinkedPacket.h" TEST_CASE("Serial Linked Packet" , "[SerLinkPacket]") { diff --git a/unittest/tests/serialize/TestSerialization.cpp b/unittest/tests/serialize/TestSerialization.cpp index 4c9ba181..6e31170a 100644 --- a/unittest/tests/serialize/TestSerialization.cpp +++ b/unittest/tests/serialize/TestSerialization.cpp @@ -1,4 +1,4 @@ -#include +#include "../../serialize/SerializeAdapter.h" #include "catch.hpp" #include diff --git a/unittest/tests/storagemanager/TestPool.cpp b/unittest/tests/storagemanager/TestPool.cpp index f278c40c..daeb6bb5 100644 --- a/unittest/tests/storagemanager/TestPool.cpp +++ b/unittest/tests/storagemanager/TestPool.cpp @@ -1,296 +1,295 @@ -//#include "CatchDefinitions.h" -// -//#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; -// std::array receptionArray; -// store_address_t testStoreId; -// ReturnValue_t result = retval::CATCH_FAILED; -// uint8_t *pointer = nullptr; -// const uint8_t * constPointer = nullptr; -// -// for(size_t i = 0; i < testDataArray.size(); i++) { -// testDataArray[i] = i; -// } -// size_t size = 10; -// -// SECTION ( "Basic tests") { -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// result = simplePool.getData(testStoreId, &constPointer, &size); -// REQUIRE(result == retval::CATCH_OK); -// memcpy(receptionArray.data(), constPointer, size); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// memset(receptionArray.data(), 0, size); -// result = simplePool.modifyData(testStoreId, &pointer, &size); -// memcpy(receptionArray.data(), pointer, size); -// REQUIRE(result == retval::CATCH_OK); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// result = simplePool.deleteData(testStoreId); -// REQUIRE(result == retval::CATCH_OK); -// result = simplePool.addData(&testStoreId, testDataArray.data(), 15); -// CHECK (result == (int) StorageManagerIF::DATA_TOO_LARGE); -// } -// -// SECTION ( "Reservation Tests ") { -// pointer = nullptr; -// result = simplePool.getFreeElement(&testStoreId, size, &pointer); -// REQUIRE (result == retval::CATCH_OK); -// memcpy(pointer, testDataArray.data(), size); -// constPointer = nullptr; -// result = simplePool.getData(testStoreId, &constPointer, &size); -// -// REQUIRE (result == retval::CATCH_OK); -// memcpy(receptionArray.data(), constPointer, size); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// } -// -// SECTION ( "Add, delete, add, add when full") { -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// result = simplePool.getData(testStoreId, &constPointer, &size); -// REQUIRE( result == retval::CATCH_OK); -// memcpy(receptionArray.data(), constPointer, size); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// -// result = simplePool.deleteData(testStoreId); -// REQUIRE(result == retval::CATCH_OK); -// -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// result = simplePool.getData(testStoreId, &constPointer, &size); -// REQUIRE( result == retval::CATCH_OK); -// memcpy(receptionArray.data(), constPointer, size); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// -// store_address_t newAddress; -// result = simplePool.addData(&newAddress, testDataArray.data(), size); -// REQUIRE(result == (int) StorageManagerIF::DATA_STORAGE_FULL); -// -// // Packet Index to high intentionally -// newAddress.packetIndex = 2; -// pointer = testDataArray.data(); -// result = simplePool.modifyData(newAddress, &pointer, &size); -// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID); -// -// result = simplePool.deleteData(newAddress); -// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID); -// -// newAddress.packetIndex = 0; -// newAddress.poolIndex = 2; -// result = simplePool.deleteData(newAddress); -// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID); -// } -// -// SECTION ( "Initialize and clear store, delete with pointer") { -// result = simplePool.initialize(); -// REQUIRE(result == retval::CATCH_OK); -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// simplePool.clearStore(); -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// result = simplePool.modifyData(testStoreId, &pointer, &size); -// REQUIRE(result == retval::CATCH_OK); -// store_address_t newId; -// result = simplePool.deleteData(pointer, size, &testStoreId); -// REQUIRE(result == retval::CATCH_OK); -// REQUIRE(testStoreId.raw != (uint32_t) StorageManagerIF::INVALID_ADDRESS); -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// } -//} -// -//int runIdx = 0; -// -//TEST_CASE( "Local Pool Extended Tests [3 Pools]" , "[TestPool2]") { -// LocalPool::LocalPoolConfig* config; -// if(runIdx == 0) { -// config = new LocalPool::LocalPoolConfig{{10, 5}, {5, 10}, {2, 20}}; -// } -// else { -// // shufle the order, they should be sort implictely so that the -// // order is ascending for the page sizes. -// config = new LocalPool::LocalPoolConfig{{5, 10}, {2, 20}, {10, 5}}; -// size_t lastSize = 0; -// for(const auto& pair: *config) { -// CHECK(pair.second > lastSize); -// lastSize = pair.second; -// } -// } -// runIdx++; -// -// LocalPool simplePool(0, *config); -// 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 = 0; -// -// SECTION ("Basic tests") { -// size = 8; -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// // Should be on second page of the pool now for 8 bytes -// CHECK(testStoreId.poolIndex == 1); -// CHECK(testStoreId.packetIndex == 0); -// -// size = 15; -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// // Should be on third page of the pool now for 15 bytes -// CHECK(testStoreId.poolIndex == 2); -// CHECK(testStoreId.packetIndex == 0); -// -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// // Should be on third page of the pool now for 15 bytes -// CHECK(testStoreId.poolIndex == 2); -// CHECK(testStoreId.packetIndex == 1); -// -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// // Should be on third page of the pool now for 15 bytes -// REQUIRE(result == (int) LocalPool::DATA_STORAGE_FULL); -// -// size = 8; -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// // Should still work -// CHECK(testStoreId.poolIndex == 1); -// CHECK(testStoreId.packetIndex == 1); -// -// // fill the rest of the pool -// for(uint8_t idx = 2; idx < 5; idx++) { -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// CHECK(testStoreId.poolIndex == 1); -// CHECK(testStoreId.packetIndex == idx); -// } -// } -// -// SECTION ("Fill Count and Clearing") { -// //SECTION("Basic tests"); -// uint8_t bytesWritten = 0; -// simplePool.getFillCount(receptionArray.data(), &bytesWritten); -// // fill count should be all zeros now. -// CHECK(bytesWritten == 4); -// CHECK(receptionArray[0] == 0); -// CHECK(receptionArray[1] == 0); -// CHECK(receptionArray[2] == 0); -// CHECK(receptionArray[3] == 0); -// -// // now fill the store completely. -// size = 5; -// for(uint8_t idx = 0; idx < 10; idx++) { -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// CHECK(testStoreId.poolIndex == 0); -// CHECK(testStoreId.packetIndex == idx); -// } -// size = 10; -// for(uint8_t idx = 0; idx < 5; idx++) { -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// CHECK(testStoreId.poolIndex == 1); -// CHECK(testStoreId.packetIndex == idx); -// } -// size = 20; -// for(uint8_t idx = 0; idx < 2; idx++) { -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// CHECK(testStoreId.poolIndex == 2); -// CHECK(testStoreId.packetIndex == idx); -// } -// bytesWritten = 0; -// simplePool.getFillCount(receptionArray.data(), &bytesWritten); -// // fill count should be all 100 now. -// CHECK(bytesWritten == 4); -// CHECK(receptionArray[0] == 100); -// CHECK(receptionArray[1] == 100); -// CHECK(receptionArray[2] == 100); -// CHECK(receptionArray[3] == 100); -// -// // now clear the store -// simplePool.clearStore(); -// bytesWritten = 0; -// simplePool.getFillCount(receptionArray.data(), &bytesWritten); -// CHECK(bytesWritten == 4); -// CHECK(receptionArray[0] == 0); -// CHECK(receptionArray[1] == 0); -// CHECK(receptionArray[2] == 0); -// CHECK(receptionArray[3] == 0); -// -// // now fill one page -// size = 5; -// for(uint8_t idx = 0; idx < 10; idx++) { -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// CHECK(testStoreId.poolIndex == 0); -// CHECK(testStoreId.packetIndex == idx); -// } -// bytesWritten = 0; -// simplePool.getFillCount(receptionArray.data(), &bytesWritten); -// // First page full, median fill count is 33 % -// CHECK(bytesWritten == 4); -// CHECK(receptionArray[0] == 100); -// CHECK(receptionArray[1] == 0); -// CHECK(receptionArray[2] == 0); -// CHECK(receptionArray[3] == 33); -// -// // now fill second page -// size = 10; -// for(uint8_t idx = 0; idx < 5; idx++) { -// result = simplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// CHECK(testStoreId.poolIndex == 1); -// CHECK(testStoreId.packetIndex == idx); -// } -// bytesWritten = 0; -// simplePool.getFillCount(receptionArray.data(), &bytesWritten); -// // First and second page full, median fill count is 66 % -// CHECK(bytesWritten == 4); -// CHECK(receptionArray[0] == 100); -// CHECK(receptionArray[1] == 100); -// CHECK(receptionArray[2] == 0); -// CHECK(receptionArray[3] == 66); -// -// // now clear first page -// simplePool.clearPage(0); -// bytesWritten = 0; -// simplePool.getFillCount(receptionArray.data(), &bytesWritten); -// // Second page full, median fill count is 33 % -// CHECK(bytesWritten == 4); -// CHECK(receptionArray[0] == 0); -// CHECK(receptionArray[1] == 100); -// CHECK(receptionArray[2] == 0); -// CHECK(receptionArray[3] == 33); -// } -// -// delete(config); -//} +#include "CatchDefinitions.h" + +#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; + std::array receptionArray; + store_address_t testStoreId; + ReturnValue_t result = retval::CATCH_FAILED; + uint8_t *pointer = nullptr; + const uint8_t * constPointer = nullptr; + + for(size_t i = 0; i < testDataArray.size(); i++) { + testDataArray[i] = i; + } + size_t size = 10; + + SECTION ( "Basic tests") { + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + result = simplePool.getData(testStoreId, &constPointer, &size); + REQUIRE(result == retval::CATCH_OK); + memcpy(receptionArray.data(), constPointer, size); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + memset(receptionArray.data(), 0, size); + result = simplePool.modifyData(testStoreId, &pointer, &size); + memcpy(receptionArray.data(), pointer, size); + REQUIRE(result == retval::CATCH_OK); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + result = simplePool.deleteData(testStoreId); + REQUIRE(result == retval::CATCH_OK); + result = simplePool.addData(&testStoreId, testDataArray.data(), 15); + CHECK (result == (int) StorageManagerIF::DATA_TOO_LARGE); + } + + SECTION ( "Reservation Tests ") { + pointer = nullptr; + result = simplePool.getFreeElement(&testStoreId, size, &pointer); + REQUIRE (result == retval::CATCH_OK); + memcpy(pointer, testDataArray.data(), size); + constPointer = nullptr; + result = simplePool.getData(testStoreId, &constPointer, &size); + + REQUIRE (result == retval::CATCH_OK); + memcpy(receptionArray.data(), constPointer, size); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + } + + SECTION ( "Add, delete, add, add when full") { + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + result = simplePool.getData(testStoreId, &constPointer, &size); + REQUIRE( result == retval::CATCH_OK); + memcpy(receptionArray.data(), constPointer, size); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + + result = simplePool.deleteData(testStoreId); + REQUIRE(result == retval::CATCH_OK); + + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + result = simplePool.getData(testStoreId, &constPointer, &size); + REQUIRE( result == retval::CATCH_OK); + memcpy(receptionArray.data(), constPointer, size); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + + store_address_t newAddress; + result = simplePool.addData(&newAddress, testDataArray.data(), size); + REQUIRE(result == (int) StorageManagerIF::DATA_STORAGE_FULL); + + // Packet Index to high intentionally + newAddress.packetIndex = 2; + pointer = testDataArray.data(); + result = simplePool.modifyData(newAddress, &pointer, &size); + REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID); + + result = simplePool.deleteData(newAddress); + REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID); + + newAddress.packetIndex = 0; + newAddress.poolIndex = 2; + result = simplePool.deleteData(newAddress); + REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID); + } + + SECTION ( "Initialize and clear store, delete with pointer") { + result = simplePool.initialize(); + REQUIRE(result == retval::CATCH_OK); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + simplePool.clearStore(); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + result = simplePool.modifyData(testStoreId, &pointer, &size); + REQUIRE(result == retval::CATCH_OK); + store_address_t newId; + result = simplePool.deleteData(pointer, size, &testStoreId); + REQUIRE(result == retval::CATCH_OK); + REQUIRE(testStoreId.raw != (uint32_t) StorageManagerIF::INVALID_ADDRESS); + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + } +} + +int runIdx = 0; + +TEST_CASE( "Local Pool Extended Tests [3 Pools]" , "[TestPool2]") { + LocalPool::LocalPoolConfig* config; + if(runIdx == 0) { + config = new LocalPool::LocalPoolConfig{{10, 5}, {5, 10}, {2, 20}}; + } + else { + // shufle the order, they should be sort implictely so that the + // order is ascending for the page sizes. + config = new LocalPool::LocalPoolConfig{{5, 10}, {2, 20}, {10, 5}}; + size_t lastSize = 0; + for(const auto& pair: *config) { + CHECK(pair.second > lastSize); + lastSize = pair.second; + } + } + runIdx++; + + LocalPool simplePool(0, *config); + 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 = 0; + + SECTION ("Basic tests") { + size = 8; + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + // Should be on second page of the pool now for 8 bytes + CHECK(testStoreId.poolIndex == 1); + CHECK(testStoreId.packetIndex == 0); + + size = 15; + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + // Should be on third page of the pool now for 15 bytes + CHECK(testStoreId.poolIndex == 2); + CHECK(testStoreId.packetIndex == 0); + + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + // Should be on third page of the pool now for 15 bytes + CHECK(testStoreId.poolIndex == 2); + CHECK(testStoreId.packetIndex == 1); + + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + // Should be on third page of the pool now for 15 bytes + REQUIRE(result == (int) LocalPool::DATA_STORAGE_FULL); + + size = 8; + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + // Should still work + CHECK(testStoreId.poolIndex == 1); + CHECK(testStoreId.packetIndex == 1); + + // fill the rest of the pool + for(uint8_t idx = 2; idx < 5; idx++) { + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + CHECK(testStoreId.poolIndex == 1); + CHECK(testStoreId.packetIndex == idx); + } + } + + SECTION ("Fill Count and Clearing") { + //SECTION("Basic tests"); + uint8_t bytesWritten = 0; + simplePool.getFillCount(receptionArray.data(), &bytesWritten); + // fill count should be all zeros now. + CHECK(bytesWritten == 4); + CHECK(receptionArray[0] == 0); + CHECK(receptionArray[1] == 0); + CHECK(receptionArray[2] == 0); + CHECK(receptionArray[3] == 0); + + // now fill the store completely. + size = 5; + for(uint8_t idx = 0; idx < 10; idx++) { + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + CHECK(testStoreId.poolIndex == 0); + CHECK(testStoreId.packetIndex == idx); + } + size = 10; + for(uint8_t idx = 0; idx < 5; idx++) { + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + CHECK(testStoreId.poolIndex == 1); + CHECK(testStoreId.packetIndex == idx); + } + size = 20; + for(uint8_t idx = 0; idx < 2; idx++) { + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + CHECK(testStoreId.poolIndex == 2); + CHECK(testStoreId.packetIndex == idx); + } + bytesWritten = 0; + simplePool.getFillCount(receptionArray.data(), &bytesWritten); + // fill count should be all 100 now. + CHECK(bytesWritten == 4); + CHECK(receptionArray[0] == 100); + CHECK(receptionArray[1] == 100); + CHECK(receptionArray[2] == 100); + CHECK(receptionArray[3] == 100); + + // now clear the store + simplePool.clearStore(); + bytesWritten = 0; + simplePool.getFillCount(receptionArray.data(), &bytesWritten); + CHECK(bytesWritten == 4); + CHECK(receptionArray[0] == 0); + CHECK(receptionArray[1] == 0); + CHECK(receptionArray[2] == 0); + CHECK(receptionArray[3] == 0); + + // now fill one page + size = 5; + for(uint8_t idx = 0; idx < 10; idx++) { + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + CHECK(testStoreId.poolIndex == 0); + CHECK(testStoreId.packetIndex == idx); + } + bytesWritten = 0; + simplePool.getFillCount(receptionArray.data(), &bytesWritten); + // First page full, median fill count is 33 % + CHECK(bytesWritten == 4); + CHECK(receptionArray[0] == 100); + CHECK(receptionArray[1] == 0); + CHECK(receptionArray[2] == 0); + CHECK(receptionArray[3] == 33); + + // now fill second page + size = 10; + for(uint8_t idx = 0; idx < 5; idx++) { + result = simplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + CHECK(testStoreId.poolIndex == 1); + CHECK(testStoreId.packetIndex == idx); + } + bytesWritten = 0; + simplePool.getFillCount(receptionArray.data(), &bytesWritten); + // First and second page full, median fill count is 66 % + CHECK(bytesWritten == 4); + CHECK(receptionArray[0] == 100); + CHECK(receptionArray[1] == 100); + CHECK(receptionArray[2] == 0); + CHECK(receptionArray[3] == 66); + + // now clear first page + simplePool.clearPage(0); + bytesWritten = 0; + simplePool.getFillCount(receptionArray.data(), &bytesWritten); + // Second page full, median fill count is 33 % + CHECK(bytesWritten == 4); + CHECK(receptionArray[0] == 0); + CHECK(receptionArray[1] == 100); + CHECK(receptionArray[2] == 0); + CHECK(receptionArray[3] == 33); + } + + delete(config); +}