diff --git a/CHANGELOG b/CHANGELOG index 7aafcc369..8b13b68d5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,10 +15,50 @@ a C file without issues - 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 +- setNormalDatapoolEntriesInvalid is not an abstract method and a default implementation was provided +- getTransitionDelayMs is now an abstract method + +### DeviceHandlerIF + +- Typo for UNKNOWN_DEVICE_REPLY ### Events diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..02849ca44 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,143 @@ +cmake_minimum_required(VERSION 3.13) + +set(LIB_FSFW_NAME fsfw) +add_library(${LIB_FSFW_NAME}) + +set_property(CACHE OS_FSFW PROPERTY STRINGS host linux rtems freertos) + +if(NOT OS_FSFW) + message(STATUS "No OS for FSFW via OS_FSFW set. Assuming host OS") + # Assume host OS and autodetermine from OS_FSFW + if(UNIX) + set(OS_FSFW "linux" + CACHE STRING + "OS abstraction layer used in the FSFW" + ) + elseif(WIN32) + set(OS_FSFW "host" + CACHE STRING "OS abstraction layer used in the FSFW" + ) + endif() + +endif() + +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") + target_link_libraries(${LIB_FSFW_NAME} ${LIB_OS_NAME}) +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) + +if(FSFW_USE_DATALINKLAYER) + add_subdirectory(datalinklayer) +endif() + +add_subdirectory(datapool) +add_subdirectory(datapoollocal) +add_subdirectory(housekeeping) +add_subdirectory(devicehandlers) +add_subdirectory(events) +add_subdirectory(fdir) +add_subdirectory(globalfunctions) +add_subdirectory(health) +add_subdirectory(internalError) +add_subdirectory(ipc) +add_subdirectory(memory) +add_subdirectory(modes) +add_subdirectory(monitoring) +add_subdirectory(objectmanager) +add_subdirectory(osal) +add_subdirectory(parameters) +add_subdirectory(power) +add_subdirectory(pus) + +if(FSFW_USE_RMAP) + add_subdirectory(rmap) +endif() + +add_subdirectory(serialize) +add_subdirectory(serviceinterface) +add_subdirectory(storagemanager) +add_subdirectory(subsystem) +add_subdirectory(tasks) +add_subdirectory(tcdistribution) +add_subdirectory(thermal) +add_subdirectory(timemanager) +add_subdirectory(tmstorage) +add_subdirectory(tmtcpacket) +add_subdirectory(tmtcservices) + +# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. +# If this is not given, we include the default configuration and emit a warning. +if(NOT FSFW_CONFIG_PATH) + message(WARNING "Flight Software Framework configuration path not set!") + message(WARNING "Setting default configuration!") + add_subdirectory(defaultcfg/fsfwconfig) +endif() + +# FSFW might be part of a possibly complicated folder structure, so we +# extract the absolute path of the fsfwconfig folder. +if(IS_ABSOLUTE ${FSFW_CONFIG_PATH}) + set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH}) +else() + get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE + ${FSFW_CONFIG_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR} + ) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX) + set(WARNING_FLAGS + -Wall + -Wextra + -Wshadow=local + -Wimplicit-fallthrough=1 + -Wno-unused-parameter + -Wno-psabi + ) +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(COMPILER_FLAGS "/permissive-") +endif() + +# Required include paths to compile the FSFW +target_include_directories(${LIB_FSFW_NAME} INTERFACE + ${CMAKE_SOURCE_DIR} + ${FSFW_CONFIG_PATH_ABSOLUTE} +) + +# Includes path required to compile FSFW itself as well +# We assume that the fsfwconfig folder uses include relative to the project +# root here! +target_include_directories(${LIB_FSFW_NAME} PRIVATE + ${CMAKE_SOURCE_DIR} + ${FSFW_CONFIG_PATH_ABSOLUTE} +) + +# Machine specific options can be set with the ABI_FLAGS variable. +target_compile_options(${LIB_FSFW_NAME} PRIVATE + ${WARNING_FLAGS} + ${COMPILER_FLAGS} + ${ABI_FLAGS} +) diff --git a/action/CMakeLists.txt b/action/CMakeLists.txt new file mode 100644 index 000000000..a62d4044b --- /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/container/CMakeLists.txt b/container/CMakeLists.txt new file mode 100644 index 000000000..904cde55b --- /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 000000000..6f6607388 --- /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 695517310..2a4024680 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 f5182ceb3..6e83fe80b 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 000000000..fa4f67867 --- /dev/null +++ b/controller/ExtendedControllerBase.cpp @@ -0,0 +1,113 @@ +#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(); + 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 000000000..02c5728e1 --- /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 000000000..a1fa1e52b --- /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/coordinates/Sgp4Propagator.h b/coordinates/Sgp4Propagator.h index 3949547e1..f813c6f4d 100644 --- a/coordinates/Sgp4Propagator.h +++ b/coordinates/Sgp4Propagator.h @@ -1,7 +1,9 @@ #ifndef SGP4PROPAGATOR_H_ #define SGP4PROPAGATOR_H_ +#ifndef WIN32 #include +#endif #include "../contrib/sgp4/sgp4unit.h" #include "../returnvalues/HasReturnvaluesIF.h" diff --git a/datalinklayer/CMakeLists.txt b/datalinklayer/CMakeLists.txt new file mode 100644 index 000000000..148e7c5de --- /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/MapPacketExtraction.cpp b/datalinklayer/MapPacketExtraction.cpp index d64348e15..845ed7c17 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 507f13dbe..ddb867fb2 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 000000000..0d53e1ba1 --- /dev/null +++ b/datapool/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + HkSwitchHelper.cpp + PoolDataSetBase.cpp + PoolEntry.cpp +) \ No newline at end of file diff --git a/datapool/PoolDataSetBase.cpp b/datapool/PoolDataSetBase.cpp index 1acd3fd3b..cb2348f72 100644 --- a/datapool/PoolDataSetBase.cpp +++ b/datapool/PoolDataSetBase.cpp @@ -59,6 +59,11 @@ uint16_t PoolDataSetBase::getFillCount() const { ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if(registeredVariables[count] == nullptr) { + // configuration error. + return HasReturnvaluesIF::RETURN_FAILED; + } + // These checks are often performed by the respective // variable implementation too, but I guess a double check does not hurt. if (registeredVariables[count]->getReadWriteMode() != diff --git a/datapoolglob/ControllerSet.cpp b/datapoolglob/ControllerSet.cpp deleted file mode 100644 index 54fc6e8c9..000000000 --- a/datapoolglob/ControllerSet.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include - -ControllerSet::ControllerSet() { - -} - -ControllerSet::~ControllerSet() { -} - -void ControllerSet::setInvalid() { - read(); - setToDefault(); - commit(PoolVariableIF::INVALID); -} diff --git a/datapoolglob/ControllerSet.h b/datapoolglob/ControllerSet.h deleted file mode 100644 index 5da113973..000000000 --- a/datapoolglob/ControllerSet.h +++ /dev/null @@ -1,15 +0,0 @@ -#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/datapoolglob/DataPoolAdmin.cpp b/datapoolglob/DataPoolAdmin.cpp deleted file mode 100644 index 6ede0841e..000000000 --- a/datapoolglob/DataPoolAdmin.cpp +++ /dev/null @@ -1,301 +0,0 @@ -#include "DataPoolAdmin.h" -#include "GlobalDataSet.h" -#include "GlobalDataPool.h" -#include "PoolRawAccess.h" - -#include "../ipc/CommandMessage.h" -#include "../ipc/QueueFactory.h" -#include "../parameters/ParameterMessage.h" - -DataPoolAdmin::DataPoolAdmin(object_id_t objectId) : - SystemObject(objectId), storage(NULL), commandQueue(NULL), memoryHelper( - this, NULL), actionHelper(this, NULL) { - commandQueue = QueueFactory::instance()->createMessageQueue(); -} - -DataPoolAdmin::~DataPoolAdmin() { - QueueFactory::instance()->deleteMessageQueue(commandQueue); -} - -ReturnValue_t DataPoolAdmin::performOperation(uint8_t opCode) { - handleCommand(); - return RETURN_OK; -} - -MessageQueueId_t DataPoolAdmin::getCommandQueue() const { - return commandQueue->getId(); -} - -ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { - if (actionId != SET_VALIDITY) { - return INVALID_ACTION_ID; - } - - if (size != 5) { - return INVALID_PARAMETERS; - } - - uint32_t address = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) - | data[3]; - - uint8_t valid = data[4]; - - uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); - - GlobDataSet mySet; - PoolRawAccess variable(poolId, 0, &mySet, PoolVariableIF::VAR_READ_WRITE); - ReturnValue_t status = mySet.read(); - if (status != RETURN_OK) { - return INVALID_ADDRESS; - } - if (valid != 0) { - variable.setValid(PoolVariableIF::VALID); - } else { - variable.setValid(PoolVariableIF::INVALID); - } - - mySet.commit(); - - return EXECUTION_FINISHED; -} - -ReturnValue_t DataPoolAdmin::getParameter(uint8_t domainId, - uint16_t parameterId, ParameterWrapper* parameterWrapper, - const ParameterWrapper* newValues, uint16_t startAtIndex) { - return HasReturnvaluesIF::RETURN_FAILED; -} - -void DataPoolAdmin::handleCommand() { - CommandMessage command; - ReturnValue_t result = commandQueue->receiveMessage(&command); - if (result != RETURN_OK) { - return; - } - - result = actionHelper.handleActionMessage(&command); - - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - - result = handleParameterCommand(&command); - if (result == HasReturnvaluesIF::RETURN_OK) { - return; - } - - result = memoryHelper.handleMemoryCommand(&command); - if (result != RETURN_OK) { - command.setToUnknownCommand(); - commandQueue->reply(&command); - } -} - -ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, - const uint8_t* data, size_t size, uint8_t** dataPointer) { - uint32_t poolId = 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(); - if (status != RETURN_OK) { - return INVALID_ADDRESS; - } - uint8_t typeSize = varToGetSize.getSizeOfType(); - - if (size % typeSize != 0) { - return INVALID_SIZE; - } - - if (size > varToGetSize.getSizeTillEnd()) { - return INVALID_SIZE; - } - const uint8_t* readPosition = data; - - for (; size > 0; size -= typeSize) { - GlobDataSet rawSet; - PoolRawAccess variable(poolId, arrayIndex, &rawSet, - PoolVariableIF::VAR_READ_WRITE); - status = rawSet.read(); - if (status == RETURN_OK) { - status = variable.setEntryFromBigEndian(readPosition, typeSize); - if (status == RETURN_OK) { - status = rawSet.commit(); - } - } - arrayIndex += 1; - readPosition += typeSize; - } - return ACTIVITY_COMPLETED; -} - -ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, size_t size, - uint8_t** dataPointer, uint8_t* copyHere) { - uint32_t poolId = 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(); - if (status != RETURN_OK) { - return INVALID_ADDRESS; - } - uint8_t typeSize = varToGetSize.getSizeOfType(); - if (size > varToGetSize.getSizeTillEnd()) { - return INVALID_SIZE; - } - uint8_t* ptrToCopy = copyHere; - for (; size > 0; size -= typeSize) { - GlobDataSet rawSet; - PoolRawAccess variable(poolId, arrayIndex, &rawSet, - PoolVariableIF::VAR_READ); - status = rawSet.read(); - if (status == RETURN_OK) { - size_t temp = 0; - status = variable.getEntryEndianSafe(ptrToCopy, &temp, size); - if (status != RETURN_OK) { - return RETURN_FAILED; - } - } else { - //Error reading parameter. - } - arrayIndex += 1; - ptrToCopy += typeSize; - } - return ACTIVITY_COMPLETED; -} - -ReturnValue_t DataPoolAdmin::initialize() { - ReturnValue_t result = SystemObject::initialize(); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = memoryHelper.initialize(commandQueue); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - storage = objectManager->get(objects::IPC_STORE); - if (storage == NULL) { - return HasReturnvaluesIF::RETURN_FAILED; - } - - result = actionHelper.initialize(commandQueue); - - return result; -} - -//mostly identical to ParameterHelper::handleParameterMessage() -ReturnValue_t DataPoolAdmin::handleParameterCommand(CommandMessage* command) { - ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - switch (command->getCommand()) { - case ParameterMessage::CMD_PARAMETER_DUMP: { - uint8_t domain = HasParametersIF::getDomain( - ParameterMessage::getParameterId(command)); - uint16_t parameterId = HasParametersIF::getMatrixId( - ParameterMessage::getParameterId(command)); - - DataPoolParameterWrapper wrapper; - result = wrapper.set(domain, parameterId); - - if (result == HasReturnvaluesIF::RETURN_OK) { - result = sendParameter(command->getSender(), - ParameterMessage::getParameterId(command), &wrapper); - } - } - break; - case ParameterMessage::CMD_PARAMETER_LOAD: { - - uint8_t domain = HasParametersIF::getDomain( - ParameterMessage::getParameterId(command)); - uint16_t parameterId = HasParametersIF::getMatrixId( - ParameterMessage::getParameterId(command)); - uint8_t index = HasParametersIF::getIndex( - ParameterMessage::getParameterId(command)); - - const uint8_t *storedStream; - size_t storedStreamSize; - result = storage->getData(ParameterMessage::getStoreId(command), - &storedStream, &storedStreamSize); - if (result != HasReturnvaluesIF::RETURN_OK) { - break; - } - - ParameterWrapper streamWrapper; - result = streamWrapper.set(storedStream, storedStreamSize); - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(ParameterMessage::getStoreId(command)); - break; - } - - DataPoolParameterWrapper poolWrapper; - result = poolWrapper.set(domain, parameterId); - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(ParameterMessage::getStoreId(command)); - break; - } - - result = poolWrapper.copyFrom(&streamWrapper, index); - - storage->deleteData(ParameterMessage::getStoreId(command)); - - if (result == HasReturnvaluesIF::RETURN_OK) { - result = sendParameter(command->getSender(), - ParameterMessage::getParameterId(command), &poolWrapper); - } - } - break; - default: - return HasReturnvaluesIF::RETURN_FAILED; - } - - if (result != HasReturnvaluesIF::RETURN_OK) { - rejectCommand(command->getSender(), result, command->getCommand()); - } - - return HasReturnvaluesIF::RETURN_OK; - -} - -//identical to ParameterHelper::sendParameter() -ReturnValue_t DataPoolAdmin::sendParameter(MessageQueueId_t to, uint32_t id, - const DataPoolParameterWrapper* wrapper) { - size_t serializedSize = wrapper->getSerializedSize(); - - uint8_t *storeElement; - store_address_t address; - - ReturnValue_t result = storage->getFreeElement(&address, serializedSize, - &storeElement); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - size_t storeElementSize = 0; - - result = wrapper->serialize(&storeElement, &storeElementSize, - serializedSize, SerializeIF::Endianness::BIG); - - if (result != HasReturnvaluesIF::RETURN_OK) { - storage->deleteData(address); - return result; - } - - CommandMessage reply; - - ParameterMessage::setParameterDumpReply(&reply, id, address); - - commandQueue->sendMessage(to, &reply); - - return HasReturnvaluesIF::RETURN_OK; -} - -//identical to ParameterHelper::rejectCommand() -void DataPoolAdmin::rejectCommand(MessageQueueId_t to, ReturnValue_t reason, - Command_t initialCommand) { - CommandMessage reply; - reply.setReplyRejected(reason, initialCommand); - commandQueue->sendMessage(to, &reply); -} diff --git a/datapoolglob/DataPoolAdmin.h b/datapoolglob/DataPoolAdmin.h deleted file mode 100644 index d8871b651..000000000 --- a/datapoolglob/DataPoolAdmin.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef FSFW_DATAPOOLGLOB_DATAPOOLADMIN_H_ -#define FSFW_DATAPOOLGLOB_DATAPOOLADMIN_H_ - -#include "DataPoolParameterWrapper.h" - -#include "../objectmanager/SystemObject.h" -#include "../returnvalues/HasReturnvaluesIF.h" -#include "../tasks/ExecutableObjectIF.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, - public AcceptsMemoryMessagesIF, - public HasReturnvaluesIF, - public ReceivesParameterMessagesIF, - public SystemObject { -public: - static const ActionId_t SET_VALIDITY = 1; - - DataPoolAdmin(object_id_t objectId); - - ~DataPoolAdmin(); - - ReturnValue_t performOperation(uint8_t opCode); - - MessageQueueId_t getCommandQueue() const; - - ReturnValue_t handleMemoryLoad(uint32_t address, const uint8_t* data, - size_t size, uint8_t** dataPointer); - ReturnValue_t handleMemoryDump(uint32_t address, size_t size, - uint8_t** dataPointer, uint8_t* copyHere); - - ReturnValue_t executeAction(ActionId_t actionId, - MessageQueueId_t commandedBy, const uint8_t* data, size_t size); - - //not implemented as ParameterHelper is no used - ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex); - - ReturnValue_t initialize(); -private: - StorageManagerIF *storage; - MessageQueueIF* commandQueue; - MemoryHelper memoryHelper; - SimpleActionHelper actionHelper; - void handleCommand(); - ReturnValue_t handleParameterCommand(CommandMessage *command); - ReturnValue_t sendParameter(MessageQueueId_t to, uint32_t id, - const DataPoolParameterWrapper* wrapper); - void rejectCommand(MessageQueueId_t to, ReturnValue_t reason, - Command_t initialCommand); -}; - -#endif /* FSFW_DATAPOOLGLOB_DATAPOOLADMIN_H_ */ diff --git a/datapoolglob/DataPoolParameterWrapper.cpp b/datapoolglob/DataPoolParameterWrapper.cpp deleted file mode 100644 index 3a57d90df..000000000 --- a/datapoolglob/DataPoolParameterWrapper.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "../datapoolglob/GlobalDataSet.h" -#include "../datapoolglob/DataPoolParameterWrapper.h" -#include "../datapoolglob/PoolRawAccess.h" -#include "../parameters/HasParametersIF.h" - - -DataPoolParameterWrapper::DataPoolParameterWrapper() : - type(Type::UNKNOWN_TYPE), rows(0), columns(0), poolId( - PoolVariableIF::NO_PARAMETER) { - -} - -DataPoolParameterWrapper::~DataPoolParameterWrapper() { - -} - -ReturnValue_t DataPoolParameterWrapper::set(uint8_t domainId, - uint16_t parameterId) { - poolId = (domainId << 16) + parameterId; - - GlobDataSet mySet; - PoolRawAccess raw(poolId, 0, &mySet, PoolVariableIF::VAR_READ); - ReturnValue_t status = mySet.read(); - if (status != HasReturnvaluesIF::RETURN_OK) { - //should only fail for invalid pool id - return HasParametersIF::INVALID_MATRIX_ID; - } - - type = raw.getType(); - rows = raw.getArraySize(); - columns = 1; - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t DataPoolParameterWrapper::serialize(uint8_t** buffer, - size_t* size, size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result; - - result = SerializeAdapter::serialize(&type, buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - result = SerializeAdapter::serialize(&columns, buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - result = SerializeAdapter::serialize(&rows, buffer, size, maxSize, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - for (uint8_t index = 0; index < rows; index++){ - GlobDataSet mySet; - PoolRawAccess raw(poolId, index, &mySet,PoolVariableIF::VAR_READ); - mySet.read(); - result = raw.serialize(buffer,size,maxSize,streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK){ - return result; - } - } - return HasReturnvaluesIF::RETURN_OK; -} - -//same as ParameterWrapper -size_t DataPoolParameterWrapper::getSerializedSize() const { - size_t serializedSize = 0; - serializedSize += type.getSerializedSize(); - serializedSize += sizeof(rows); - serializedSize += sizeof(columns); - serializedSize += rows * columns * type.getSize(); - - return serializedSize; -} - -ReturnValue_t DataPoolParameterWrapper::deSerialize(const uint8_t** buffer, - size_t* size, Endianness streamEndianness) { - return HasReturnvaluesIF::RETURN_FAILED; -} - -template -ReturnValue_t DataPoolParameterWrapper::deSerializeData(uint8_t startingRow, - uint8_t startingColumn, const void* from, uint8_t fromRows) { - //treat from as a continuous Stream as we copy all of it - const uint8_t *fromAsStream = (const uint8_t *) from; - - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - - for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) { - - GlobDataSet mySet; - PoolRawAccess raw(poolId, startingRow + fromRow, &mySet, - PoolVariableIF::VAR_READ_WRITE); - mySet.read(); - - result = raw.setEntryFromBigEndian(fromAsStream, sizeof(T)); - - fromAsStream += sizeof(T); - - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - - mySet.commit(); - } - - return HasReturnvaluesIF::RETURN_OK; -} - -ReturnValue_t DataPoolParameterWrapper::copyFrom(const ParameterWrapper* from, - uint16_t startWritingAtIndex) { - if (poolId == PoolVariableIF::NO_PARAMETER) { - return ParameterWrapper::NOT_SET; - } - - if (type != from->type) { - return ParameterWrapper::DATATYPE_MISSMATCH; - } - - //check if from fits into this - uint8_t startingRow = startWritingAtIndex / columns; - uint8_t startingColumn = startWritingAtIndex % columns; - - if ((from->rows > (rows - startingRow)) - || (from->columns > (columns - startingColumn))) { - return ParameterWrapper::TOO_BIG; - } - - ReturnValue_t result; - //copy data - if (from->pointsToStream) { - switch (type) { - case Type::UINT8_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::INT8_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::UINT16_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::INT16_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::UINT32_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::INT32_T: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::FLOAT: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - case Type::DOUBLE: - result = deSerializeData(startingRow, startingColumn, - from->readonlyData, from->rows); - break; - default: - result = ParameterWrapper::UNKNOW_DATATYPE; - break; - } - } else { - //not supported - return HasReturnvaluesIF::RETURN_FAILED; - } - - return result; -} diff --git a/datapoolglob/DataPoolParameterWrapper.h b/datapoolglob/DataPoolParameterWrapper.h deleted file mode 100644 index b1e505a75..000000000 --- a/datapoolglob/DataPoolParameterWrapper.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef DATAPOOLPARAMETERWRAPPER_H_ -#define DATAPOOLPARAMETERWRAPPER_H_ - -#include "../globalfunctions/Type.h" -#include "../parameters/ParameterWrapper.h" - -class DataPoolParameterWrapper: public SerializeIF { -public: - DataPoolParameterWrapper(); - virtual ~DataPoolParameterWrapper(); - - ReturnValue_t set(uint8_t domainId, uint16_t parameterId); - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - virtual size_t getSerializedSize() const override; - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - - ReturnValue_t copyFrom(const ParameterWrapper *from, - uint16_t startWritingAtIndex); - -private: - Type type; - uint8_t rows; - uint8_t columns; - - uint32_t poolId; - - template - ReturnValue_t deSerializeData(uint8_t startingRow, uint8_t startingColumn, - const void *from, uint8_t fromRows); - -}; - -#endif /* DATAPOOLPARAMETERWRAPPER_H_ */ diff --git a/datapoolglob/GlobalDataPool.cpp b/datapoolglob/GlobalDataPool.cpp deleted file mode 100644 index afb27b772..000000000 --- a/datapoolglob/GlobalDataPool.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#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 deleted file mode 100644 index ce5b132c0..000000000 --- a/datapoolglob/GlobalDataPool.h +++ /dev/null @@ -1,149 +0,0 @@ -#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 deleted file mode 100644 index 1e99f8051..000000000 --- a/datapoolglob/GlobalDataSet.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#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 deleted file mode 100644 index 2f0edbd5c..000000000 --- a/datapoolglob/GlobalDataSet.h +++ /dev/null @@ -1,98 +0,0 @@ -#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 deleted file mode 100644 index a995bfaf2..000000000 --- a/datapoolglob/GlobalPoolVariable.h +++ /dev/null @@ -1,213 +0,0 @@ -#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 deleted file mode 100644 index d61d605d7..000000000 --- a/datapoolglob/GlobalPoolVariable.tpp +++ /dev/null @@ -1,117 +0,0 @@ -#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 deleted file mode 100644 index 0f5daacd8..000000000 --- a/datapoolglob/GlobalPoolVector.h +++ /dev/null @@ -1,185 +0,0 @@ -#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 deleted file mode 100644 index 013a682a4..000000000 --- a/datapoolglob/GlobalPoolVector.tpp +++ /dev/null @@ -1,117 +0,0 @@ -#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/datapoolglob/PIDReader.h b/datapoolglob/PIDReader.h deleted file mode 100644 index 9431e1d40..000000000 --- a/datapoolglob/PIDReader.h +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef PIDREADER_H_ -#define PIDREADER_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" - -template class PIDReaderList; - -template -class PIDReader: public PoolVariableIF { - template friend class PIDReaderList; -protected: - uint32_t parameterId; - uint8_t valid; - 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]; - return HasReturnvaluesIF::RETURN_OK; - } else { - value = 0; - valid = false; - sif::error << "PIDReader: read of PID 0x" << std::hex << parameterId - << std::dec << " failed." << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * Never commit, is read-only. - * Reason is the possibility to access a single DP vector element, but if we commit, - * we set validity of the whole vector. - */ - ReturnValue_t commit(uint32_t lockTimeout) override { - return HasReturnvaluesIF::RETURN_FAILED; - } - ReturnValue_t commitWithoutLock() override { - return HasReturnvaluesIF::RETURN_FAILED; - } - - /** - * Empty ctor for List initialization - */ - PIDReader() : - parameterId(PoolVariableIF::NO_PARAMETER), valid( - PoolVariableIF::INVALID), value(0) { - - } -public: - /** - * \brief This is the local copy of the data pool entry. - */ - T value; - /** - * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is - * passed). - * \details It DOES NOT fetch the current value from the data pool, but sets the value - * attribute to default (0). The value is fetched within the read() operation. - * \param set_id This is the id in the global data pool this instance of the access class - * corresponds to. - * \param dataSet The data set in which the variable shall register itself. If NULL, - * the variable is not registered. - * \param setWritable If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. - */ - PIDReader(uint32_t setParameterId, DataSetIF *dataSet) : - parameterId(setParameterId), valid(PoolVariableIF::INVALID), value( - 0) { - if (dataSet != NULL) { - dataSet->registerVariable(this); - } - } - - 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. - */ - PIDReader(const PIDReader &rhs) : - parameterId(rhs.parameterId), valid(rhs.valid), value(rhs.value) { - } - - /** - * \brief The classes destructor is empty. - */ - ~PIDReader() { - - } - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const { - return GlobalDataPool::PIDToDataPoolId(parameterId); - } - uint32_t getParameterId() const { - return parameterId; - } - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const { - return VAR_READ; - } - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const { - if (valid) - return true; - else - return false; - } - - uint8_t getValid() { - return valid; - } - - void setValid(bool valid) { - this->valid = valid; - } - - operator T() { - return value; - } - - PIDReader& operator=(T newValue) { - value = newValue; - return *this; - } - - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const override { - return SerializeAdapter::serialize(&value, buffer, size, maxSize, - streamEndianness); - } - - virtual size_t getSerializedSize() const override { - return SerializeAdapter::getSerializedSize(&value); - } - - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override { - return SerializeAdapter::deSerialize(&value, buffer, size, - streamEndianness); - } -}; - -#endif /* PIDREADER_H_ */ diff --git a/datapoolglob/PIDReaderList.h b/datapoolglob/PIDReaderList.h deleted file mode 100644 index ae99f3aa2..000000000 --- a/datapoolglob/PIDReaderList.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ -#define FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ - -#include "../datapool/PoolVariableIF.h" -#include "../datapoolglob/PIDReader.h" -template -class PIDReaderList { -private: - PIDReader variables[n_var]; -public: - PIDReaderList( const uint32_t setPid[n_var], DataSetIF* dataSet) { - //I really should have a look at the new init list c++ syntax. - if (dataSet == NULL) { - return; - } - for (uint8_t count = 0; count < n_var; count++) { - variables[count].parameterId = setPid[count]; - dataSet->registerVariable(&variables[count]); - } - } - - PIDReader &operator [](int i) { return variables[i]; } -}; - - - -#endif /* FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ */ diff --git a/datapoolglob/PoolRawAccess.cpp b/datapoolglob/PoolRawAccess.cpp deleted file mode 100644 index 53706c6d3..000000000 --- a/datapoolglob/PoolRawAccess.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#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 deleted file mode 100644 index 15643a41c..000000000 --- a/datapoolglob/PoolRawAccess.h +++ /dev/null @@ -1,220 +0,0 @@ -#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/CMakeLists.txt b/datapoollocal/CMakeLists.txt new file mode 100644 index 000000000..c6b187cd2 --- /dev/null +++ b/datapoollocal/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + LocalDataPoolManager.cpp + LocalDataSet.cpp + LocalPoolDataSetBase.cpp + LocalPoolObjectBase.cpp + SharedLocalDataSet.cpp +) \ No newline at end of file diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h index 95d483032..c4024cf9e 100644 --- a/datapoollocal/LocalDataPoolManager.h +++ b/datapoollocal/LocalDataPoolManager.h @@ -48,7 +48,7 @@ class HousekeepingPacketUpdate; * @author R. Mueller */ class LocalDataPoolManager { - template friend class LocalPoolVar; + template friend class LocalPoolVariable; template friend class LocalPoolVector; friend class LocalPoolDataSetBase; friend void (Factory::setStaticFrameworkObjectIds)(); diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h index c18d54433..7b7e443e1 100644 --- a/datapoollocal/LocalPoolVariable.h +++ b/datapoollocal/LocalPoolVariable.h @@ -22,10 +22,10 @@ * @ingroup data_pool */ template -class LocalPoolVar: public LocalPoolObjectBase { +class LocalPoolVariable: public LocalPoolObjectBase { public: //! Default ctor is forbidden. - LocalPoolVar() = delete; + LocalPoolVariable() = delete; /** * This constructor is used by the data creators to have pool variable @@ -43,7 +43,7 @@ public: * 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, + LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr, pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); @@ -64,7 +64,7 @@ public: * @param setReadWriteMode Specify the read-write mode of the pool variable. * */ - LocalPoolVar(object_id_t poolOwner, lp_id_t poolId, + LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr, pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); /** @@ -73,10 +73,10 @@ public: * @param dataSet * @param setReadWriteMode */ - LocalPoolVar(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr, + LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr, pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); - virtual~ LocalPoolVar() {}; + virtual~ LocalPoolVariable() {}; /** * @brief This is the local copy of the data pool entry. @@ -118,23 +118,23 @@ public: ReturnValue_t commit(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; - LocalPoolVar &operator=(const T& newValue); - LocalPoolVar &operator=(const LocalPoolVar& newPoolVariable); + LocalPoolVariable &operator=(const T& newValue); + LocalPoolVariable &operator=(const LocalPoolVariable& newPoolVariable); //! Explicit type conversion operator. Allows casting the class to //! its template type to perform operations on value. explicit operator T() const; - bool operator==(const LocalPoolVar& other) const; + bool operator==(const LocalPoolVariable& other) const; bool operator==(const T& other) const; - bool operator!=(const LocalPoolVar& other) const; + bool operator!=(const LocalPoolVariable& other) const; bool operator!=(const T& other) const; - bool operator<(const LocalPoolVar& other) const; + bool operator<(const LocalPoolVariable& other) const; bool operator<(const T& other) const; - bool operator>(const LocalPoolVar& other) const; + bool operator>(const LocalPoolVariable& other) const; bool operator>(const T& other) const; protected: @@ -160,7 +160,7 @@ protected: // std::ostream is the type for object std::cout template friend std::ostream& operator<< (std::ostream &out, - const LocalPoolVar &var); + const LocalPoolVariable &var); private: }; @@ -168,18 +168,18 @@ private: #include "LocalPoolVariable.tpp" template -using lp_var_t = LocalPoolVar; +using lp_var_t = LocalPoolVariable; -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; +using lp_bool_t = LocalPoolVariable; +using lp_uint8_t = LocalPoolVariable; +using lp_uint16_t = LocalPoolVariable; +using lp_uint32_t = LocalPoolVariable; +using lp_uint64_t = LocalPoolVariable; +using lp_int8_t = LocalPoolVariable; +using lp_int16_t = LocalPoolVariable; +using lp_int32_t = LocalPoolVariable; +using lp_int64_t = LocalPoolVariable; +using lp_float_t = LocalPoolVariable; +using lp_double_t = LocalPoolVariable; #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ */ diff --git a/datapoollocal/LocalPoolVariable.tpp b/datapoollocal/LocalPoolVariable.tpp index b9f7b906e..48649ad58 100644 --- a/datapoollocal/LocalPoolVariable.tpp +++ b/datapoollocal/LocalPoolVariable.tpp @@ -6,32 +6,32 @@ #endif template -inline LocalPoolVar::LocalPoolVar(HasLocalDataPoolIF* hkOwner, +inline LocalPoolVariable::LocalPoolVariable(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, +inline LocalPoolVariable::LocalPoolVariable(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, +inline LocalPoolVariable::LocalPoolVariable(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) { +inline ReturnValue_t LocalPoolVariable::read(dur_millis_t lockTimeout) { MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, lockTimeout); return readWithoutLock(); } template -inline ReturnValue_t LocalPoolVar::readWithoutLock() { +inline ReturnValue_t LocalPoolVariable::readWithoutLock() { if(readWriteMode == pool_rwm_t::VAR_WRITE) { sif::debug << "LocalPoolVar: Invalid read write " "mode for read() call." << std::endl; @@ -53,14 +53,14 @@ inline ReturnValue_t LocalPoolVar::readWithoutLock() { } template -inline ReturnValue_t LocalPoolVar::commit(dur_millis_t lockTimeout) { +inline ReturnValue_t LocalPoolVariable::commit(dur_millis_t lockTimeout) { MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, lockTimeout); return commitWithoutLock(); } template -inline ReturnValue_t LocalPoolVar::commitWithoutLock() { +inline ReturnValue_t LocalPoolVariable::commitWithoutLock() { if(readWriteMode == pool_rwm_t::VAR_READ) { sif::debug << "LocalPoolVar: Invalid read write " "mode for commit() call." << std::endl; @@ -81,88 +81,88 @@ inline ReturnValue_t LocalPoolVar::commitWithoutLock() { } template -inline ReturnValue_t LocalPoolVar::serialize(uint8_t** buffer, size_t* size, +inline ReturnValue_t LocalPoolVariable::serialize(uint8_t** buffer, size_t* size, const size_t max_size, SerializeIF::Endianness streamEndianness) const { return SerializeAdapter::serialize(&value, buffer, size ,max_size, streamEndianness); } template -inline size_t LocalPoolVar::getSerializedSize() const { +inline size_t LocalPoolVariable::getSerializedSize() const { return SerializeAdapter::getSerializedSize(&value); } template -inline ReturnValue_t LocalPoolVar::deSerialize(const uint8_t** buffer, +inline ReturnValue_t LocalPoolVariable::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) { + const LocalPoolVariable &var) { out << var.value; return out; } template -inline LocalPoolVar::operator T() const { +inline LocalPoolVariable::operator T() const { return value; } template -inline LocalPoolVar & LocalPoolVar::operator=(const T& newValue) { +inline LocalPoolVariable & LocalPoolVariable::operator=(const T& newValue) { value = newValue; return *this; } template -inline LocalPoolVar& LocalPoolVar::operator =( - const LocalPoolVar& newPoolVariable) { +inline LocalPoolVariable& LocalPoolVariable::operator =( + const LocalPoolVariable& newPoolVariable) { value = newPoolVariable.value; return *this; } template -inline bool LocalPoolVar::operator ==(const LocalPoolVar &other) const { +inline bool LocalPoolVariable::operator ==(const LocalPoolVariable &other) const { return this->value == other.value; } template -inline bool LocalPoolVar::operator ==(const T &other) const { +inline bool LocalPoolVariable::operator ==(const T &other) const { return this->value == other; } template -inline bool LocalPoolVar::operator !=(const LocalPoolVar &other) const { +inline bool LocalPoolVariable::operator !=(const LocalPoolVariable &other) const { return not (*this == other); } template -inline bool LocalPoolVar::operator !=(const T &other) const { +inline bool LocalPoolVariable::operator !=(const T &other) const { return not (*this == other); } template -inline bool LocalPoolVar::operator <(const LocalPoolVar &other) const { +inline bool LocalPoolVariable::operator <(const LocalPoolVariable &other) const { return this->value < other.value; } template -inline bool LocalPoolVar::operator <(const T &other) const { +inline bool LocalPoolVariable::operator <(const T &other) const { return this->value < other; } template -inline bool LocalPoolVar::operator >(const LocalPoolVar &other) const { +inline bool LocalPoolVariable::operator >(const LocalPoolVariable &other) const { return not (*this < other); } template -inline bool LocalPoolVar::operator >(const T &other) const { +inline bool LocalPoolVariable::operator >(const T &other) const { return not (*this < other); } diff --git a/defaultcfg/fsfwconfig/CMakeLists.txt b/defaultcfg/fsfwconfig/CMakeLists.txt new file mode 100644 index 000000000..b8b41c930 --- /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/fsfwconfig/FSFWConfig.h b/defaultcfg/fsfwconfig/FSFWConfig.h index 1386bf66f..e1815d050 100644 --- a/defaultcfg/fsfwconfig/FSFWConfig.h +++ b/defaultcfg/fsfwconfig/FSFWConfig.h @@ -15,25 +15,17 @@ //! 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 -//! simulataneously. This will increase the required RAM for -//! each CSB service ! -#define FSFW_CSB_FIFO_DEPTH 6 - //! If FSFW_OBJ_EVENT_TRANSLATION is set to one, //! additional output which requires the translation files translateObjects //! and translateEvents (and their compiled source files) #define FSFW_OBJ_EVENT_TRANSLATION 0 #if FSFW_OBJ_EVENT_TRANSLATION == 1 -#define FSFW_DEBUG_OUTPUT 1 //! Specify whether info events are printed too. #define FSFW_DEBUG_INFO 1 -#include -#include +#include "objects/translateObjects.h" +#include "events/translateEvents.h" #else -#define FSFW_DEBUG_OUTPUT 0 #endif //! When using the newlib nano library, C99 support for stdio facilities @@ -52,6 +44,12 @@ static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8; 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; + +//! Defines the FIFO depth of each commanding service base which +//! also determines how many commands a CSB service can handle in one cycle +//! simulataneously. This will increase the required RAM for +//! each CSB service ! +static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; } #endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/defaultcfg/fsfwconfig/OBSWConfig.h b/defaultcfg/fsfwconfig/OBSWConfig.h index a9f576386..8ad2cb675 100644 --- a/defaultcfg/fsfwconfig/OBSWConfig.h +++ b/defaultcfg/fsfwconfig/OBSWConfig.h @@ -3,6 +3,10 @@ #include "OBSWVersion.h" +#include "objects/systemObjectList.h" +#include "events/subsystemIdRanges.h" +#include "returnvalues/classIds.h" + #ifdef __cplusplus namespace config { #endif diff --git a/devicehandlers/CMakeLists.txt b/devicehandlers/CMakeLists.txt new file mode 100644 index 000000000..50c1008fb --- /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/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index b5d43d77d..d2d4ecb8d 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -3,8 +3,6 @@ #include "DeviceTmReportingWrapper.h" #include "../serviceinterface/ServiceInterfaceStream.h" -#include "../datapoolglob/GlobalDataSet.h" -#include "../datapoolglob/GlobalPoolVariable.h" #include "../objectmanager/ObjectManager.h" #include "../storagemanager/StorageManagerIF.h" #include "../thermal/ThermalComponentIF.h" @@ -13,9 +11,11 @@ #include "../ipc/MessageQueueMessage.h" #include "../ipc/QueueFactory.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; @@ -56,9 +56,10 @@ void DeviceHandlerBase::setHkDestination(object_id_t 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); } @@ -86,7 +87,6 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { decrementDeviceReplyMap(); fdirInstance->checkForFailures(); hkSwitcher.performOperation(); - hkManager.performHkOperation(); performOperationHook(); return RETURN_OK; } @@ -111,6 +111,9 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { break; case CommunicationAction::GET_READ: doGetRead(); + // This will be performed after datasets have been updated by the + // custom device implementation. + hkManager.performHkOperation(); break; default: break; @@ -208,16 +211,18 @@ ReturnValue_t DeviceHandlerBase::initialize() { fillCommandAndReplyMap(); - //Set temperature target state to NON_OP. - GlobDataSet mySet; - gp_uint8_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() { @@ -505,15 +510,17 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) { } Clock::getUptime(&timeoutStart); - if (mode == MODE_OFF) { - GlobDataSet mySet; - gp_uint8_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); } @@ -919,11 +926,6 @@ void DeviceHandlerBase::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { setMode(getBaseMode(mode)); } -uint32_t DeviceHandlerBase::getTransitionDelayMs(Mode_t modeFrom, - Mode_t modeTo) { - return 0; -} - ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) { if(powerSwitcher == nullptr) { return NO_SWITCH; @@ -976,17 +978,15 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, } if ((commandedMode == MODE_ON) && (mode == MODE_OFF) - && (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) { - GlobDataSet mySet; - gp_uint8_t thermalState(deviceThermalStatePoolId, &mySet, - PoolVariableIF::VAR_READ); - gp_uint8_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; } } @@ -999,32 +999,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); - GlobDataSet mySet; - gp_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; @@ -1050,6 +1033,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; @@ -1222,10 +1232,12 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, } } //Try to cast to GlobDataSet and commit data. - if (!neverInDataPool) { - GlobDataSet* 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(); } } } @@ -1262,7 +1274,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 } } @@ -1371,8 +1384,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. @@ -1385,6 +1398,12 @@ 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; } @@ -1429,3 +1448,17 @@ 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; +} + +void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() { + for(const auto& reply: deviceReplyMap) { + if(reply.second.dataSet != nullptr) { + reply.second.dataSet->setValidity(false, true); + } + } +} diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 627a64238..45450f627 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -4,6 +4,7 @@ #include "DeviceHandlerIF.h" #include "DeviceCommunicationIF.h" #include "DeviceHandlerFailureIsolation.h" +#include "DeviceHandlerThermalSet.h" #include "../objectmanager/SystemObject.h" #include "../tasks/ExecutableObjectIF.h" @@ -103,8 +104,21 @@ public: size_t cmdQueueSize = 20); void setHkDestination(object_id_t hkDestination); - void setThermalStateRequestPoolIds(uint32_t thermalStatePoolId, - uint32_t thermalRequestPoolId); + + /** + * 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 @@ -240,9 +254,10 @@ protected: * * @param[out] id the device command id that has been built * @return - * - @c RETURN_OK to send command after setting #rawPacket and #rawPacketLen. - * - @c NOTHING_TO_SEND when no command is to be sent. - * - Anything else triggers an even with the returnvalue as a parameter. + * - @c RETURN_OK to send command after setting #rawPacket and + * #rawPacketLen. + * - @c NOTHING_TO_SEND when no command is to be sent. + * - Anything else triggers an even with the returnvalue as a parameter. */ virtual ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) = 0; @@ -259,7 +274,8 @@ protected: * and filling them in doStartUp(), doShutDown() and doTransition() so no * modes have to be checked here. * - * #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 @@ -270,19 +286,23 @@ protected: virtual ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) = 0; /** - * @brief Build a device command packet from data supplied by a direct command. + * @brief Build a device command packet from data supplied by a + * direct command. * * @details - * #rawPacket and #rawPacketLen should be set by this method to the packet to be sent. - * The existence of the command in the command map and the command size check - * against 0 are done by the base class. + * #rawPacket and #rawPacketLen should be set by this method to the packet + * to be sent. The existence of the command in the command map and the + * command size check against 0 are done by the base class. * - * @param deviceCommand the command to build, already checked against deviceCommandMap + * @param deviceCommand the command to build, already checked against + * deviceCommandMap * @param commandData pointer to the data from the direct command * @param commandDataLen length of commandData * @return - * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen have been set. - * - Anything else triggers an event with the returnvalue as a parameter + * - @c RETURN_OK to send command after #rawPacket and #rawPacketLen + * have been set. + * - Anything else triggers an event with the + * returnvalue as a parameter */ virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t * commandData, size_t commandDataLen) = 0; @@ -470,7 +490,7 @@ protected: * @param modeTo * @return time in ms */ - virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo); + virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) = 0; /** * Return the switches connected to the device. @@ -667,7 +687,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) - LocalPoolDataSetBase* dataSet; + LocalPoolDataSetBase* dataSet = nullptr; //! The command that expects this reply. DeviceCommandMap::iterator command; }; @@ -694,19 +714,7 @@ 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; - - /** - * 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; + DeviceHandlerThermalSet* thermalSet = nullptr; /** * Optional Error code. Can be set in doStartUp(), doShutDown() and @@ -732,15 +740,39 @@ 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; + + /** + * @brief Set all datapool variables that are update periodically in + * normal mode invalid + * @details + * The default implementation will set all datasets which have been added + * in #fillCommandAndReplyMap to invalid. It will also set all pool + * variables inside the dataset to invalid. The user can override this + * method optionally. + */ + virtual void setNormalDatapoolEntriesInvalid(); + + /** + * 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 */ @@ -770,7 +802,6 @@ protected: * * The submode is left unchanged. * - * * @param newMode */ void setMode(Mode_t newMode); @@ -823,8 +854,6 @@ protected: virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); /** - * Is the combination of mode and submode valid? - * * @param mode * @param submode * @return @@ -835,27 +864,27 @@ protected: Submode_t submode); /** - * Get the Rmap action for the current step. - * + * Get the communication action for the current step. * The step number can be read from #pstStep. - * - * @return The Rmap action to execute in this step + * @return The communication action to execute in this step */ - 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 @@ -868,7 +897,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); @@ -878,42 +909,46 @@ 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 devices can have different channels to send + * raw replies * * @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); /** - * notify child about mode change + * @brief Notify child about mode change. */ virtual void modeChanged(void); /** * 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 @@ -926,34 +961,28 @@ protected: DeviceCommandId_t alternateReplyID = 0); /** - * get the state of the PCDU switches in the datapool - * + * Get the state of the PCDU switches in the local 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. - */ - virtual void setNormalDatapoolEntriesInvalid() = 0; - /** * build a list of sids and pass it to the #hkSwitcher */ 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 */ @@ -992,17 +1021,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(); @@ -1043,9 +1075,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; @@ -1102,10 +1135,14 @@ 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); @@ -1115,16 +1152,17 @@ private: /** * 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. * @@ -1184,7 +1222,7 @@ 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, @@ -1208,6 +1246,9 @@ private: void parseReply(const uint8_t* receivedData, size_t receivedDataLen); + + void handleTransitionToOnMode(Mode_t commandedMode, + Submode_t commandedSubmode); }; #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */ diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 491a2c083..e56487515 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -4,6 +4,7 @@ #include "DeviceHandlerMessage.h" #include "../action/HasActionsIF.h" +#include "../datapoollocal/locPoolDefinitions.h" #include "../events/Event.h" #include "../modes/HasModesIF.h" #include "../ipc/MessageQueueSenderIF.h" @@ -21,12 +22,13 @@ using DeviceCommandId_t = uint32_t; */ class DeviceHandlerIF { public: + static constexpr DeviceCommandId_t NO_COMMAND = -1; + static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20; + static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10; - static const uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20; - static const uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10; - - static constexpr Command_t NO_COMMAND = -1; + using dh_heater_request_t = uint8_t; + using dh_thermal_state_t = int8_t; /** * @brief This is the mode the device handler is in. @@ -129,7 +131,7 @@ public: // Standard codes used in interpretDeviceReply static const ReturnValue_t DEVICE_DID_NOT_EXECUTE = MAKE_RETURN_CODE(0xC0); //the device reported, that it did not execute the command static const ReturnValue_t DEVICE_REPORTED_ERROR = MAKE_RETURN_CODE(0xC1); - static const ReturnValue_t UNKNOW_DEVICE_REPLY = MAKE_RETURN_CODE(0xC2); //the deviceCommandId reported by scanforReply is unknown + static const ReturnValue_t UNKNOWN_DEVICE_REPLY = MAKE_RETURN_CODE(0xC2); //the deviceCommandId reported by scanforReply is unknown static const ReturnValue_t DEVICE_REPLY_INVALID = MAKE_RETURN_CODE(0xC3); //syntax etc is correct but still not ok, eg parameters where none are expected // Standard codes used in buildCommandFromCommand @@ -142,7 +144,7 @@ public: * This is used by the child class to tell the base class what to do. */ enum CommunicationAction: uint8_t { - PERFORM_OPERATION, + PERFORM_OPERATION, SEND_WRITE,//!< Send write GET_WRITE, //!< Get write SEND_READ, //!< Send read @@ -150,6 +152,14 @@ public: NOTHING //!< Do nothing. }; + static constexpr uint32_t DEFAULT_THERMAL_SET_ID = sid_t::INVALID_SET_ID - 1; + + static constexpr lp_id_t DEFAULT_THERMAL_STATE_POOL_ID = + localpool::INVALID_LPID - 2; + static constexpr lp_id_t DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID = + localpool::INVALID_LPID - 1; + + /** * Default Destructor */ diff --git a/devicehandlers/DeviceHandlerThermalSet.h b/devicehandlers/DeviceHandlerThermalSet.h new file mode 100644 index 000000000..239012e26 --- /dev/null +++ b/devicehandlers/DeviceHandlerThermalSet.h @@ -0,0 +1,44 @@ +#ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ +#define FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ + +#include "DeviceHandlerIF.h" +#include "../datapoollocal/StaticLocalDataSet.h" +#include "../datapoollocal/LocalPoolVariable.h" + + +class DeviceHandlerThermalSet: public StaticLocalDataSet<2> { +public: + + DeviceHandlerThermalSet(HasLocalDataPoolIF* hkOwner, uint32_t setId = + DeviceHandlerIF::DEFAULT_THERMAL_SET_ID, + lp_id_t thermalStateId = + DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, + lp_id_t heaterRequestId = + DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID): + DeviceHandlerThermalSet(hkOwner->getObjectId(), setId, + thermalStateId, heaterRequestId) {} + + DeviceHandlerThermalSet(object_id_t deviceHandler, uint32_t setId = + DeviceHandlerIF::DEFAULT_THERMAL_SET_ID, + lp_id_t thermalStateId = + DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, + lp_id_t thermalStateRequestId = + DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID): + StaticLocalDataSet(sid_t(deviceHandler, setId)), + thermalStatePoolId(thermalStateId), + heaterRequestPoolId(thermalStateRequestId) {} + + const lp_id_t thermalStatePoolId; + const lp_id_t heaterRequestPoolId; + + lp_var_t thermalState = + lp_var_t( + thermalStatePoolId, sid.objectId, this); + lp_var_t heaterRequest = + lp_var_t( + heaterRequestPoolId, sid.objectId, this); +}; + + + +#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */ diff --git a/events/CMakeLists.txt b/events/CMakeLists.txt new file mode 100644 index 000000000..4e935167a --- /dev/null +++ b/events/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + EventManager.cpp + EventMessage.cpp +) + +add_subdirectory(eventmatching) \ No newline at end of file diff --git a/events/EventManager.cpp b/events/EventManager.cpp index 71d1e2e62..6cc97eb6c 100644 --- a/events/EventManager.cpp +++ b/events/EventManager.cpp @@ -1,27 +1,28 @@ #include "EventManager.h" #include "EventMessage.h" -#include +#include #include "../serviceinterface/ServiceInterfaceStream.h" #include "../ipc/QueueFactory.h" #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); @@ -42,7 +43,7 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) { EventMessage message; result = eventReportQueue->receiveMessage(&message); if (result == HasReturnvaluesIF::RETURN_OK) { -#ifdef DEBUG +#if FSFW_OBJ_EVENT_TRANSLATION == 1 printEvent(&message); #endif notifyListeners(&message); @@ -113,13 +114,13 @@ ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener, return result; } -#ifdef DEBUG +#if FSFW_OBJ_EVENT_TRANSLATION == 1 void EventManager::printEvent(EventMessage* message) { const char *string = 0; switch (message->getSeverity()) { case severity::INFO: -#ifdef DEBUG_INFO_EVENT +#if DEBUG_INFO_EVENT == 1 string = translateObject(message->getReporter()); sif::info << "EVENT: "; if (string != 0) { diff --git a/events/EventManager.h b/events/EventManager.h index 2602aeb23..c6bd07be8 100644 --- a/events/EventManager.h +++ b/events/EventManager.h @@ -1,16 +1,20 @@ -#ifndef EVENTMANAGER_H_ -#define EVENTMANAGER_H_ +#ifndef FSFW_EVENT_EVENTMANAGER_H_ +#define FSFW_EVENT_EVENTMANAGER_H_ -#include "eventmatching/EventMatchTree.h" #include "EventManagerIF.h" +#include "eventmatching/EventMatchTree.h" + +#include + #include "../objectmanager/SystemObject.h" #include "../storagemanager/LocalPool.h" #include "../tasks/ExecutableObjectIF.h" #include "../ipc/MessageQueueIF.h" #include "../ipc/MutexIF.h" + #include -#ifdef DEBUG +#if FSFW_OBJ_EVENT_TRANSLATION == 1 // forward declaration, should be implemented by mission extern const char* translateObject(object_id_t object); extern const char* translateEvents(Event event); @@ -49,13 +53,15 @@ 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]; void notifyListeners(EventMessage *message); -#ifdef DEBUG +#if FSFW_OBJ_EVENT_TRANSLATION == 1 void printEvent(EventMessage *message); #endif @@ -64,4 +70,4 @@ protected: void unlockMutex(); }; -#endif /* EVENTMANAGER_H_ */ +#endif /* FSFW_EVENT_EVENTMANAGER_H_ */ diff --git a/events/EventManagerIF.h b/events/EventManagerIF.h index f9ac420b3..253e6910c 100644 --- a/events/EventManagerIF.h +++ b/events/EventManagerIF.h @@ -1,10 +1,11 @@ #ifndef EVENTMANAGERIF_H_ #define EVENTMANAGERIF_H_ -#include "eventmatching/eventmatching.h" #include "EventMessage.h" +#include "eventmatching/eventmatching.h" #include "../objectmanager/ObjectManagerIF.h" #include "../ipc/MessageQueueSenderIF.h" +#include "../ipc/MessageQueueIF.h" class EventManagerIF { public: @@ -16,7 +17,8 @@ public: virtual MessageQueueId_t getEventReportQueue() = 0; - virtual ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false) = 0; + virtual ReturnValue_t registerListener(MessageQueueId_t listener, + bool forwardAllButSelected = false) = 0; virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0; virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, @@ -31,18 +33,22 @@ public: bool reporterInverted = false) = 0; static void triggerEvent(object_id_t reportingObject, Event event, - uint32_t parameter1 = 0, uint32_t parameter2 = 0, MessageQueueId_t sentFrom = 0) { + uint32_t parameter1 = 0, uint32_t parameter2 = 0, + MessageQueueId_t sentFrom = 0) { EventMessage message(event, reportingObject, parameter1, parameter2); triggerEvent(&message, sentFrom); } - static void triggerEvent(EventMessage* message, MessageQueueId_t sentFrom = 0) { - static MessageQueueId_t eventmanagerQueue = 0; - if (eventmanagerQueue == 0) { + + static void triggerEvent(EventMessage* message, + MessageQueueId_t sentFrom = 0) { + static MessageQueueId_t eventmanagerQueue = MessageQueueIF::NO_QUEUE; + if (eventmanagerQueue == MessageQueueIF::NO_QUEUE) { EventManagerIF *eventmanager = objectManager->get( objects::EVENT_MANAGER); - if (eventmanager != NULL) { - eventmanagerQueue = eventmanager->getEventReportQueue(); + if (eventmanager == nullptr) { + return; } + eventmanagerQueue = eventmanager->getEventReportQueue(); } MessageQueueSenderIF::sendMessage(eventmanagerQueue, message, sentFrom); } diff --git a/events/eventmatching/CMakeLists.txt b/events/eventmatching/CMakeLists.txt new file mode 100644 index 000000000..81ff9ed84 --- /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 000000000..f5ffbba8d --- /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/FaultCounter.cpp b/fdir/FaultCounter.cpp index 443adb52e..6519a3a88 100644 --- a/fdir/FaultCounter.cpp +++ b/fdir/FaultCounter.cpp @@ -76,7 +76,7 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint16_t parameterId, parameterWrapper->set(timer.timeout); break; default: - return INVALID_MATRIX_ID; + return INVALID_IDENTIFIER_ID; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/fsfw.mk b/fsfw.mk index c58475540..3df63060e 100644 --- a/fsfw.mk +++ b/fsfw.mk @@ -9,7 +9,6 @@ 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) diff --git a/globalfunctions/CMakeLists.txt b/globalfunctions/CMakeLists.txt new file mode 100644 index 000000000..2b3dcf8ed --- /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/Type.cpp b/globalfunctions/Type.cpp index ae595b812..fa6d2f281 100644 --- a/globalfunctions/Type.cpp +++ b/globalfunctions/Type.cpp @@ -1,4 +1,3 @@ -#include "../serialize/SerializeAdapter.h" #include "Type.h" #include "../serialize/SerializeAdapter.h" diff --git a/globalfunctions/Type.h b/globalfunctions/Type.h index be499ffc6..fa894e3e9 100644 --- a/globalfunctions/Type.h +++ b/globalfunctions/Type.h @@ -1,9 +1,13 @@ -#ifndef TYPE_H_ -#define TYPE_H_ +#ifndef FSFW_GLOBALFUNCTIONS_TYPE_H_ +#define FSFW_GLOBALFUNCTIONS_TYPE_H_ #include "../returnvalues/HasReturnvaluesIF.h" #include "../serialize/SerializeIF.h" +#include +/** + * @brief Type definition for CCSDS or ECSS. + */ class Type: public SerializeIF { public: enum ActualType_t { @@ -53,6 +57,11 @@ private: template struct PodTypeConversion { + static_assert(not std::is_same::value, + "Do not use boolean for the PoolEntry type, use uint8_t " + "instead! The ECSS standard defines a boolean as a one bit " + "field. Therefore it is preferred to store a boolean as an " + "uint8_t"); static const Type::ActualType_t type = Type::UNKNOWN_TYPE; }; template<> @@ -88,4 +97,4 @@ struct PodTypeConversion { static const Type::ActualType_t type = Type::DOUBLE; }; -#endif /* TYPE_H_ */ +#endif /* FSFW_GLOBALFUNCTIONS_TYPE_H_ */ diff --git a/globalfunctions/math/CMakeLists.txt b/globalfunctions/math/CMakeLists.txt new file mode 100644 index 000000000..a9c4ded78 --- /dev/null +++ b/globalfunctions/math/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + QuaternionOperations.cpp +) diff --git a/globalfunctions/timevalOperations.h b/globalfunctions/timevalOperations.h index 3977d5d96..db68f3304 100644 --- a/globalfunctions/timevalOperations.h +++ b/globalfunctions/timevalOperations.h @@ -2,7 +2,12 @@ #define TIMEVALOPERATIONS_H_ #include + +#ifdef WIN32 +#include +#else #include +#endif timeval& operator+=(timeval& lhs, const timeval& rhs); diff --git a/health/CMakeLists.txt b/health/CMakeLists.txt new file mode 100644 index 000000000..d5f3ccd30 --- /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/housekeeping/CMakeLists.txt b/housekeeping/CMakeLists.txt new file mode 100644 index 000000000..fecad2e3d --- /dev/null +++ b/housekeeping/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + HousekeepingMessage.cpp + PeriodicHousekeepingHelper.cpp +) \ No newline at end of file diff --git a/internalError/CMakeLists.txt b/internalError/CMakeLists.txt new file mode 100644 index 000000000..2b383914c --- /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 000000000..fa91116d4 --- /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 3424266bd..bfb672891 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -1,16 +1,16 @@ -#include "../datapoolglob/GlobalDataSet.h" #include "InternalErrorReporter.h" -#include "../datapoolglob/GlobalPoolVariable.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(); } @@ -18,28 +18,42 @@ InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); } +void InternalErrorReporter::setDiagnosticPrintout(bool enable) { + this->diagnosticPrintout = enable; +} + ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { - - GlobDataSet mySet; - gp_uint32_t queueHitsInPool(queuePoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - gp_uint32_t tmHitsInPool(tmPoolId, &mySet, - PoolVariableIF::VAR_READ_WRITE); - - gp_uint32_t 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; } @@ -53,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(); @@ -62,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(); @@ -85,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(); } @@ -103,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(); @@ -112,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 9aa24a0fa..8d33c06e2 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 000000000..6a3afe33e --- /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/CommandMessageCleaner.cpp b/ipc/CommandMessageCleaner.cpp index 6a99b4d2d..6a3640699 100644 --- a/ipc/CommandMessageCleaner.cpp +++ b/ipc/CommandMessageCleaner.cpp @@ -1,4 +1,4 @@ -#include "../ipc/CommandMessageCleaner.h" +#include "CommandMessageCleaner.h" #include "../devicehandlers/DeviceHandlerMessage.h" #include "../health/HealthMessage.h" @@ -7,11 +7,12 @@ #include "../monitoring/MonitoringMessage.h" #include "../subsystem/modes/ModeSequenceMessage.h" #include "../tmstorage/TmStoreMessage.h" +#include "../housekeeping/HousekeepingMessage.h" #include "../parameters/ParameterMessage.h" void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { switch(message->getMessageType()){ - case messagetypes::MODE_COMMAND: + case messagetypes::MODE_COMMAND: ModeMessage::clear(message); break; case messagetypes::HEALTH_COMMAND: @@ -38,6 +39,9 @@ void CommandMessageCleaner::clearCommandMessage(CommandMessage* message) { case messagetypes::PARAMETER: ParameterMessage::clear(message); break; + case messagetypes::HOUSEKEEPING: + HousekeepingMessage::clear(message); + break; default: messagetypes::clearMissionMessage(message); break; diff --git a/ipc/MessageQueueMessageIF.h b/ipc/MessageQueueMessageIF.h index b5a30c086..33e01e7d0 100644 --- a/ipc/MessageQueueMessageIF.h +++ b/ipc/MessageQueueMessageIF.h @@ -1,7 +1,7 @@ #ifndef FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ #define FRAMEWORK_IPC_MESSAGEQUEUEMESSAGEIF_H_ -#include +#include "messageQueueDefinitions.h" #include #include diff --git a/ipc/MutexFactory.h b/ipc/MutexFactory.h index f8133d814..db505ff94 100644 --- a/ipc/MutexFactory.h +++ b/ipc/MutexFactory.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_IPC_MUTEXFACTORY_H_ -#define FRAMEWORK_IPC_MUTEXFACTORY_H_ +#ifndef FSFW_IPC_MUTEXFACTORY_H_ +#define FSFW_IPC_MUTEXFACTORY_H_ #include "MutexIF.h" /** @@ -31,4 +31,4 @@ private: -#endif /* FRAMEWORK_IPC_MUTEXFACTORY_H_ */ +#endif /* FSFW_IPC_MUTEXFACTORY_H_ */ diff --git a/ipc/MutexHelper.h b/ipc/MutexHelper.h index 3dc369213..97001ade9 100644 --- a/ipc/MutexHelper.h +++ b/ipc/MutexHelper.h @@ -16,8 +16,8 @@ public: << timeoutMs << " milliseconds!" << std::endl; } else if(status != HasReturnvaluesIF::RETURN_OK){ - sif::error << "MutexHelper: Lock of Mutex failed with code " << - status << std::endl; + sif::error << "MutexHelper: Lock of Mutex failed with code " + << status << std::endl; } } diff --git a/ipc/QueueFactory.h b/ipc/QueueFactory.h index 9853d2562..6fc0643e8 100644 --- a/ipc/QueueFactory.h +++ b/ipc/QueueFactory.h @@ -3,6 +3,7 @@ #include "MessageQueueIF.h" #include "MessageQueueMessage.h" + #include /** diff --git a/memory/CMakeLists.txt b/memory/CMakeLists.txt new file mode 100644 index 000000000..9edb9031f --- /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 000000000..dcec6346e --- /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 000000000..8e5c719bc --- /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/monitoring/AbsLimitMonitor.h b/monitoring/AbsLimitMonitor.h index 2e60f6f8c..5feb369c0 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 000000000..d26e807c3 --- /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 85d92b6b9..04f634374 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 66e6725e8..c4448ceda 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 5173c4798..967f0f62f 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 "LimitViolationReporter.h" +#include "MonitoringIF.h" +#include "MonitoringMessageContent.h" +#include "MonitorReporter.h" + +#include "../datapoollocal/LocalPoolVariable.h" -#include "../datapoolglob/GlobalDataSet.h" -#include "../datapoolglob/PIDReader.h" -#include "../monitoring/LimitViolationReporter.h" -#include "../monitoring/MonitoringIF.h" -#include "../monitoring/MonitoringMessageContent.h" -#include "../monitoring/MonitorReporter.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) { - GlobDataSet 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; } + + LocalPoolVariable poolVariable; }; -#endif /* MONITORBASE_H_ */ +#endif /* FSFW_MONITORING_MONITORBASE_H_ */ diff --git a/monitoring/MonitorReporter.h b/monitoring/MonitorReporter.h index ca2b534b9..9028e7e4a 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 040539ef1..32c625307 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 { @@ -64,4 +64,4 @@ public: -#endif /* MONITORINGIF_H_ */ +#endif /* FSFW_MONITORING_MONITORINGIF_H_ */ diff --git a/monitoring/MonitoringMessageContent.h b/monitoring/MonitoringMessageContent.h index c82506f3a..44d326565 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 9b60aeb63..c4b3c5375 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 000000000..72aaec896 --- /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/osal/CMakeLists.txt b/osal/CMakeLists.txt new file mode 100644 index 000000000..02ff24057 --- /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/Endiness.h b/osal/Endiness.h index 65cc0a10f..9d3fdef0f 100644 --- a/osal/Endiness.h +++ b/osal/Endiness.h @@ -22,9 +22,23 @@ #else #error "Can't decide which end is which!" #endif +#else + +#ifdef WIN32 +#include +#if REG_DWORD == REG_DWORD_LITTLE_ENDIAN +#define BYTE_ORDER_SYSTEM LITTLE_ENDIAN +#else +#define BYTE_ORDER_SYSTEM BIG_ENDIAN +#endif + + #else #error __BYTE_ORDER__ not defined #endif + +#endif + #endif diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp index dd1e48ca9..a420ec489 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.cpp +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -1,7 +1,10 @@ -#include "../../osal/FreeRTOS/BinSemaphUsingTask.h" -#include "../../osal/FreeRTOS/TaskManagement.h" +#include "BinSemaphUsingTask.h" +#include "TaskManagement.h" #include "../../serviceinterface/ServiceInterfaceStream.h" +#if (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ + tskKERNEL_VERSION_MAJOR > 8 + BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { handle = TaskManagement::getCurrentTaskHandle(); if(handle == nullptr) { @@ -16,6 +19,10 @@ BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); } +void BinarySemaphoreUsingTask::refreshTaskHandle() { + handle = TaskManagement::getCurrentTaskHandle(); +} + ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType, uint32_t timeoutMs) { TickType_t timeout = 0; @@ -93,3 +100,6 @@ uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( higherPriorityTaskWoken); return notificationValue; } + +#endif /* (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ + tskKERNEL_VERSION_MAJOR > 8 */ diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h index f3c0b0eaf..ec434853e 100644 --- a/osal/FreeRTOS/BinSemaphUsingTask.h +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ +#ifndef FSFW_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ +#define FSFW_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ #include "../../returnvalues/HasReturnvaluesIF.h" #include "../../tasks/SemaphoreIF.h" @@ -7,13 +7,20 @@ #include #include +#if (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ + tskKERNEL_VERSION_MAJOR > 8 + /** * @brief Binary Semaphore implementation using the task notification value. * The notification value should therefore not be used - * for other purposes. + * for other purposes! * @details * Additional information: https://www.freertos.org/RTOS-task-notifications.html * and general semaphore documentation. + * This semaphore is bound to the task it is created in! + * Take care of building this class with the correct executing task, + * (for example in the initializeAfterTaskCreation() function) or + * by calling refreshTaskHandle() with the correct executing task. */ class BinarySemaphoreUsingTask: public SemaphoreIF, public HasReturnvaluesIF { @@ -25,6 +32,16 @@ public: //! @brief Default dtor virtual~ BinarySemaphoreUsingTask(); + /** + * This function can be used to get the correct task handle from the + * currently executing task. + * + * This is required because the task notification value will be used + * as a binary semaphore, and the semaphore might be created by another + * task. + */ + void refreshTaskHandle(); + ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, uint32_t timeoutMs = portMAX_DELAY) override; ReturnValue_t release() override; @@ -67,10 +84,13 @@ public: * - @c RETURN_FAILED on failure */ static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, - BaseType_t * higherPriorityTaskWoken); + BaseType_t* higherPriorityTaskWoken); protected: TaskHandle_t handle; }; -#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ +#endif /* (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ + tskKERNEL_VERSION_MAJOR > 8 */ + +#endif /* FSFW_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 8cc3c4957..6fee5c353 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -1,5 +1,5 @@ -#include "../../osal/FreeRTOS/BinarySemaphore.h" -#include "../../osal/FreeRTOS/TaskManagement.h" +#include "BinarySemaphore.h" +#include "TaskManagement.h" #include "../../serviceinterface/ServiceInterfaceStream.h" BinarySemaphore::BinarySemaphore() { diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index c6cedc539..8969d5038 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ -#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#ifndef FSFW_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#define FSFW_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #include "../../returnvalues/HasReturnvaluesIF.h" #include "../../tasks/SemaphoreIF.h" @@ -104,4 +104,4 @@ protected: SemaphoreHandle_t handle; }; -#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ +#endif /* FSFW_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/FreeRTOS/CMakeLists.txt b/osal/FreeRTOS/CMakeLists.txt new file mode 100644 index 000000000..95462010f --- /dev/null +++ b/osal/FreeRTOS/CMakeLists.txt @@ -0,0 +1,30 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + Clock.cpp + FixedTimeslotTask.cpp + BinarySemaphore.cpp + BinSemaphUsingTask.cpp + CountingSemaphore.cpp + CountingSemaphUsingTask.cpp + MessageQueue.cpp + Mutex.cpp + MutexFactory.cpp + PeriodicTask.cpp + QueueFactory.cpp + SemaphoreFactory.cpp + TaskFactory.cpp + Timekeeper.cpp + TaskManagement.cpp +) + +# FreeRTOS is required to link the FSFW now. It is recommended to compile +# FreeRTOS as a static library and set LIB_OS_NAME to the target name of the +# library. +if(NOT LIB_OS_NAME) + message(FATAL_ERROR + "FreeRTOS needs to be linked as a target and " + "LIB_OS_NAME needs to be set to the target" + ) +endif() + +target_link_libraries(${LIB_FSWFW_NAME} ${LIB_OS_NAME}) \ No newline at end of file diff --git a/osal/FreeRTOS/Clock.cpp b/osal/FreeRTOS/Clock.cpp index acfa98d7a..d3f4e68e1 100644 --- a/osal/FreeRTOS/Clock.cpp +++ b/osal/FreeRTOS/Clock.cpp @@ -1,6 +1,7 @@ +#include "Timekeeper.h" + #include "../../timemanager/Clock.h" #include "../../globalfunctions/timevalOperations.h" -#include "Timekeeper.h" #include #include @@ -67,6 +68,13 @@ ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { return HasReturnvaluesIF::RETURN_OK; } + +//uint32_t Clock::getUptimeSeconds() { +// timeval uptime = getUptime(); +// return uptime.tv_sec; +//} + + ReturnValue_t Clock::getClock_usecs(uint64_t* time) { timeval time_timeval; ReturnValue_t result = getClock_timeval(&time_timeval); diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp index a47341bcb..9d309acc3 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.cpp +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -1,7 +1,11 @@ -#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" -#include "../../osal/FreeRTOS/TaskManagement.h" +#include "CountingSemaphUsingTask.h" +#include "TaskManagement.h" + #include "../../serviceinterface/ServiceInterfaceStream.h" +#if (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ + tskKERNEL_VERSION_MAJOR > 8 + CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount): maxCount(maxCount) { if(initCount > maxCount) { @@ -112,3 +116,5 @@ uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( uint8_t CountingSemaphoreUsingTask::getMaxCount() const { return maxCount; } + +#endif diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h index 8977258ca..45915b6b5 100644 --- a/osal/FreeRTOS/CountingSemaphUsingTask.h +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -1,13 +1,14 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ -#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ +#ifndef FSFW_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ +#define FSFW_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ -#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h" +#include "CountingSemaphUsingTask.h" #include "../../tasks/SemaphoreIF.h" -extern "C" { #include #include -} + +#if (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ + tskKERNEL_VERSION_MAJOR > 8 /** * @brief Couting Semaphore implementation which uses the notification value @@ -16,6 +17,9 @@ extern "C" { * @details * Additional information: https://www.freertos.org/RTOS-task-notifications.html * and general semaphore documentation. + * This semaphore is bound to the task it is created in! + * Take care of calling this function with the correct executing task, + * (for example in the initializeAfterTaskCreation() function). */ class CountingSemaphoreUsingTask: public SemaphoreIF { public: @@ -99,4 +103,7 @@ private: const uint8_t maxCount; }; -#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ +#endif /* (tskKERNEL_VERSION_MAJOR == 8 && tskKERNEL_VERSION_MINOR > 2) || \ + tskKERNEL_VERSION_MAJOR > 8 */ + +#endif /* FSFW_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index d1310a6ab..a202e4806 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -1,6 +1,7 @@ -#include "../../osal/FreeRTOS/CountingSemaphore.h" +#include "CountingSemaphore.h" +#include "TaskManagement.h" + #include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../osal/FreeRTOS/TaskManagement.h" #include diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index ae2f62aee..6af1d6d26 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -1,6 +1,7 @@ #ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ #define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ -#include "../../osal/FreeRTOS/BinarySemaphore.h" + +#include "BinarySemaphore.h" /** * @brief Counting semaphores, which can be acquire more than once. diff --git a/osal/FreeRTOS/FixedTimeslotTask.cpp b/osal/FreeRTOS/FixedTimeslotTask.cpp index 062686e2b..fc5b89fe0 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.cpp +++ b/osal/FreeRTOS/FixedTimeslotTask.cpp @@ -114,38 +114,24 @@ void FixedTimeslotTask::taskFunctionality() { intervalMs = this->pst.getIntervalToPreviousSlotMs(); interval = pdMS_TO_TICKS(intervalMs); - checkMissedDeadline(xLastWakeTime, interval); - - // Wait for the interval. This exits immediately if a deadline was - // missed while also updating the last wake time. - vTaskDelayUntil(&xLastWakeTime, interval); +#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || \ + tskKERNEL_VERSION_MAJOR > 10 + BaseType_t wasDelayed = xTaskDelayUntil(&xLastWakeTime, interval); + if(wasDelayed == pdFALSE) { + handleMissedDeadline(); + } +#else + if(checkMissedDeadline(xLastWakeTime, interval)) { + handleMissedDeadline(); + } + // Wait for the interval. This exits immediately if a deadline was + // missed while also updating the last wake time. + vTaskDelayUntil(&xLastWakeTime, interval); +#endif } } } -void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval) { - /* Check whether deadline was missed while also taking overflows - * into account. Drawing this on paper with a timeline helps to understand - * it. */ - TickType_t currentTickCount = xTaskGetTickCount(); - TickType_t timeToWake = xLastWakeTime + interval; - // Time to wake has not overflown. - if(timeToWake > xLastWakeTime) { - /* If the current time has overflown exclusively or the current - * tick count is simply larger than the time to wake, a deadline was - * missed */ - if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } - } - /* Time to wake has overflown. A deadline was missed if the current time - * is larger than the time to wake */ - else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } -} - void FixedTimeslotTask::handleMissedDeadline() { if(deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); diff --git a/osal/FreeRTOS/FixedTimeslotTask.h b/osal/FreeRTOS/FixedTimeslotTask.h index 7d2cdb703..f2245ba4a 100644 --- a/osal/FreeRTOS/FixedTimeslotTask.h +++ b/osal/FreeRTOS/FixedTimeslotTask.h @@ -93,8 +93,6 @@ protected: */ void taskFunctionality(void); - void checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval); void handleMissedDeadline(); }; diff --git a/osal/FreeRTOS/FreeRTOSTaskIF.h b/osal/FreeRTOS/FreeRTOSTaskIF.h index 06fda2828..2a2d94947 100644 --- a/osal/FreeRTOS/FreeRTOSTaskIF.h +++ b/osal/FreeRTOS/FreeRTOSTaskIF.h @@ -1,13 +1,41 @@ -#ifndef FRAMEWORK_OSAL_FREERTOS_FREERTOSTASKIF_H_ -#define FRAMEWORK_OSAL_FREERTOS_FREERTOSTASKIF_H_ +#ifndef FSFW_OSAL_FREERTOS_FREERTOSTASKIF_H_ +#define FSFW_OSAL_FREERTOS_FREERTOSTASKIF_H_ #include #include class FreeRTOSTaskIF { public: - virtual~ FreeRTOSTaskIF() {} - virtual TaskHandle_t getTaskHandle() = 0; + virtual~ FreeRTOSTaskIF() {} + virtual TaskHandle_t getTaskHandle() = 0; + +protected: + + bool checkMissedDeadline(const TickType_t xLastWakeTime, + const TickType_t interval) { + /* Check whether deadline was missed while also taking overflows + * into account. Drawing this on paper with a timeline helps to understand + * it. */ + TickType_t currentTickCount = xTaskGetTickCount(); + TickType_t timeToWake = xLastWakeTime + interval; + // Time to wake has not overflown. + if(timeToWake > xLastWakeTime) { + /* If the current time has overflown exclusively or the current + * tick count is simply larger than the time to wake, a deadline was + * missed */ + if((currentTickCount < xLastWakeTime) or + (currentTickCount > timeToWake)) { + return true; + } + } + /* Time to wake has overflown. A deadline was missed if the current time + * is larger than the time to wake */ + else if((timeToWake < xLastWakeTime) and + (currentTickCount > timeToWake)) { + return true; + } + return false; + } }; -#endif /* FRAMEWORK_OSAL_FREERTOS_FREERTOSTASKIF_H_ */ +#endif /* FSFW_OSAL_FREERTOS_FREERTOSTASKIF_H_ */ diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 2dfe5ab65..fdadf8b7d 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -11,7 +11,12 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): maxMessageSize(maxMessageSize) { handle = xQueueCreate(messageDepth, maxMessageSize); if (handle == nullptr) { - sif::error << "MessageQueue::MessageQueue Creation failed" << std::endl; + sif::error << "MessageQueue::MessageQueue:" + << " Creation failed." << std::endl; + sif::error << "Specified Message Depth: " << messageDepth + << std::endl; + sif::error << "Specified Maximum Message Size: " + << maxMessageSize << std::endl; } } diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index b99bf7c8d..8fa862831 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -1,10 +1,11 @@ #ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ #define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_ +#include "TaskManagement.h" + #include "../../internalError/InternalErrorReporterIF.h" #include "../../ipc/MessageQueueIF.h" #include "../../ipc/MessageQueueMessageIF.h" -#include "../../osal/FreeRTOS/TaskManagement.h" #include #include diff --git a/osal/FreeRTOS/MutexFactory.cpp b/osal/FreeRTOS/MutexFactory.cpp index 75b63d078..d9569e35d 100644 --- a/osal/FreeRTOS/MutexFactory.cpp +++ b/osal/FreeRTOS/MutexFactory.cpp @@ -1,10 +1,12 @@ +#include "Mutex.h" + #include "../../ipc/MutexFactory.h" -#include "../FreeRTOS/Mutex.h" -//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? -> one is on heap the other on bss/data +//TODO: Different variant than the lazy loading in QueueFactory. +//What's better and why? -> one is on heap the other on bss/data //MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); -MutexFactory* MutexFactory::factoryInstance = NULL; +MutexFactory* MutexFactory::factoryInstance = nullptr; MutexFactory::MutexFactory() { } @@ -13,7 +15,7 @@ MutexFactory::~MutexFactory() { } MutexFactory* MutexFactory::instance() { - if (factoryInstance == NULL){ + if (factoryInstance == nullptr){ factoryInstance = new MutexFactory(); } return MutexFactory::factoryInstance; diff --git a/osal/FreeRTOS/PeriodicTask.cpp b/osal/FreeRTOS/PeriodicTask.cpp index 5c0a840da..2ee7bec01 100644 --- a/osal/FreeRTOS/PeriodicTask.cpp +++ b/osal/FreeRTOS/PeriodicTask.cpp @@ -80,10 +80,18 @@ void PeriodicTask::taskFunctionality() { object->performOperation(); } - checkMissedDeadline(xLastWakeTime, xPeriod); - - vTaskDelayUntil(&xLastWakeTime, xPeriod); - +#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || \ + tskKERNEL_VERSION_MAJOR > 10 + BaseType_t wasDelayed = xTaskDelayUntil(&xLastWakeTime, xPeriod); + if(wasDelayed == pdFALSE) { + handleMissedDeadline(); + } +#else + if(checkMissedDeadline(xLastWakeTime, xPeriod)) { + handleMissedDeadline(); + } + vTaskDelayUntil(&xLastWakeTime, xPeriod); +#endif } } @@ -105,29 +113,6 @@ uint32_t PeriodicTask::getPeriodMs() const { return period * 1000; } -void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval) { - /* Check whether deadline was missed while also taking overflows - * into account. Drawing this on paper with a timeline helps to understand - * it. */ - TickType_t currentTickCount = xTaskGetTickCount(); - TickType_t timeToWake = xLastWakeTime + interval; - // Time to wake has not overflown. - if(timeToWake > xLastWakeTime) { - /* If the current time has overflown exclusively or the current - * tick count is simply larger than the time to wake, a deadline was - * missed */ - if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } - } - /* Time to wake has overflown. A deadline was missed if the current time - * is larger than the time to wake */ - else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { - handleMissedDeadline(); - } -} - TaskHandle_t PeriodicTask::getTaskHandle() { return handle; } diff --git a/osal/FreeRTOS/PeriodicTask.h b/osal/FreeRTOS/PeriodicTask.h index 87b8b6d2f..36ef568f6 100644 --- a/osal/FreeRTOS/PeriodicTask.h +++ b/osal/FreeRTOS/PeriodicTask.h @@ -71,6 +71,7 @@ public: TaskHandle_t getTaskHandle() override; protected: + bool started; TaskHandle_t handle; @@ -118,8 +119,6 @@ protected: */ void taskFunctionality(void); - void checkMissedDeadline(const TickType_t xLastWakeTime, - const TickType_t interval); void handleMissedDeadline(); }; diff --git a/osal/FreeRTOS/TaskFactory.cpp b/osal/FreeRTOS/TaskFactory.cpp index 80df38b2f..3ac5cb495 100644 --- a/osal/FreeRTOS/TaskFactory.cpp +++ b/osal/FreeRTOS/TaskFactory.cpp @@ -13,32 +13,30 @@ TaskFactory::~TaskFactory() { TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } -/*** - * Keep in Mind that you need to call before this vTaskStartScheduler()! - * High taskPriority_ number means high priority. - */ + PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskPeriod period_, TaskDeadlineMissedFunction deadLineMissedFunction_) { - return (PeriodicTaskIF*) (new PeriodicTask(name_, taskPriority_, stackSize_, - period_, deadLineMissedFunction_)); + return dynamic_cast(new PeriodicTask(name_, taskPriority_, + stackSize_, period_, deadLineMissedFunction_)); } -/*** + +/** * Keep in Mind that you need to call before this vTaskStartScheduler()! */ FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskPeriod period_, TaskDeadlineMissedFunction deadLineMissedFunction_) { - return (FixedTimeslotTaskIF*) (new FixedTimeslotTask(name_, taskPriority_, - stackSize_, period_, deadLineMissedFunction_)); + return dynamic_cast(new FixedTimeslotTask(name_, + taskPriority_,stackSize_, period_, deadLineMissedFunction_)); } ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { - if (task == NULL) { + if (task == nullptr) { //delete self - vTaskDelete(NULL); + vTaskDelete(nullptr); return HasReturnvaluesIF::RETURN_OK; } else { //TODO not implemented diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index b77f12a9e..c0d0067e9 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -1,4 +1,4 @@ -#include "../../osal/FreeRTOS/TaskManagement.h" +#include "TaskManagement.h" void TaskManagement::vRequestContextSwitchFromTask() { vTaskDelay(0); @@ -22,3 +22,4 @@ size_t TaskManagement::getTaskStackHighWatermark( TaskHandle_t task) { return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t); } + diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index eb7351859..b9aece48b 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -3,10 +3,9 @@ #include "../../returnvalues/HasReturnvaluesIF.h" -extern "C" { #include #include -} + #include /** @@ -27,38 +26,37 @@ enum class CallContext { }; -class TaskManagement { -public: - /** - * @brief In this function, a function dependant on the portmacro.h header - * function calls to request a context switch can be specified. - * This can be used if sending to the queue from an ISR caused a task - * to unblock and a context switch is required. - */ - static void requestContextSwitch(CallContext callContext); +namespace TaskManagement { +/** + * @brief In this function, a function dependant on the portmacro.h header + * function calls to request a context switch can be specified. + * This can be used if sending to the queue from an ISR caused a task + * to unblock and a context switch is required. + */ +void requestContextSwitch(CallContext callContext); - /** - * If task preemption in FreeRTOS is disabled, a context switch - * can be requested manually by calling this function. - */ - static void vRequestContextSwitchFromTask(void); +/** + * If task preemption in FreeRTOS is disabled, a context switch + * can be requested manually by calling this function. + */ +void vRequestContextSwitchFromTask(void); - /** - * @return The current task handle - */ - static TaskHandle_t getCurrentTaskHandle(); +/** + * @return The current task handle + */ +TaskHandle_t getCurrentTaskHandle(); + +/** + * Get returns the minimum amount of remaining stack space in words + * that was a available to the task since the task started executing. + * Please note that the actual value in bytes depends + * on the stack depth type. + * E.g. on a 32 bit machine, a value of 200 means 800 bytes. + * @return Smallest value of stack remaining since the task was started in + * words. + */ +size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr); - /** - * Get returns the minimum amount of remaining stack space in words - * that was a available to the task since the task started executing. - * Please note that the actual value in bytes depends - * on the stack depth type. - * E.g. on a 32 bit machine, a value of 200 means 800 bytes. - * @return Smallest value of stack remaining since the task was started in - * words. - */ - static size_t getTaskStackHighWatermark( - TaskHandle_t task = nullptr); }; #endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ diff --git a/osal/FreeRTOS/Timekeeper.cpp b/osal/FreeRTOS/Timekeeper.cpp index 1031f0c4d..d986d832e 100644 --- a/osal/FreeRTOS/Timekeeper.cpp +++ b/osal/FreeRTOS/Timekeeper.cpp @@ -1,6 +1,6 @@ #include "Timekeeper.h" -#include "FreeRTOSConfig.h" +#include Timekeeper * Timekeeper::myinstance = nullptr; diff --git a/osal/host/CMakeLists.txt b/osal/host/CMakeLists.txt new file mode 100644 index 000000000..aa32990be --- /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) + target_link_libraries(${LIB_FSFW_NAME} + PRIVATE + rt + pthread + ) +endif() \ No newline at end of file diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp index 8c0eeae71..b81fa1090 100644 --- a/osal/linux/BinarySemaphore.cpp +++ b/osal/linux/BinarySemaphore.cpp @@ -1,4 +1,4 @@ -#include "../../osal/linux/BinarySemaphore.h" +#include "BinarySemaphore.h" #include "../../serviceinterface/ServiceInterfaceStream.h" extern "C" { diff --git a/osal/linux/CMakeLists.txt b/osal/linux/CMakeLists.txt new file mode 100644 index 000000000..c0096e428 --- /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/Clock.cpp b/osal/linux/Clock.cpp index 4de18f83b..6cddda35b 100644 --- a/osal/linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -76,25 +76,25 @@ timeval Clock::getUptime() { ReturnValue_t Clock::getUptime(timeval* uptime) { //TODO This is not posix compatible and delivers only seconds precision - // is the OS not called Linux? - //Linux specific file read but more precise + // Linux specific file read but more precise. double uptimeSeconds; if(std::ifstream("/proc/uptime",std::ios::in) >> uptimeSeconds){ uptime->tv_sec = uptimeSeconds; uptime->tv_usec = uptimeSeconds *(double) 1e6 - (uptime->tv_sec *1e6); } + return HasReturnvaluesIF::RETURN_OK; +} - //TODO This is not posix compatible and delivers only seconds precision - // I suggest this is moved into another clock function which will - // deliver second precision later. +// Wait for new FSFW Clock function delivering seconds uptime. +//uint32_t Clock::getUptimeSeconds() { +// //TODO This is not posix compatible and delivers only seconds precision // struct sysinfo sysInfo; // int result = sysinfo(&sysInfo); // if(result != 0){ // return HasReturnvaluesIF::RETURN_FAILED; // } // return sysInfo.uptime; - return HasReturnvaluesIF::RETURN_OK; -} +//} ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { timeval uptime; diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index bc14374ac..cfadb7931 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -3,6 +3,7 @@ #include "../../objectmanager/ObjectManagerIF.h" #include + #include /* For O_* constants */ #include /* For mode constants */ #include diff --git a/osal/linux/Mutex.h b/osal/linux/Mutex.h index ecb47a336..cfce407f7 100644 --- a/osal/linux/Mutex.h +++ b/osal/linux/Mutex.h @@ -1,10 +1,9 @@ -#ifndef OS_LINUX_MUTEX_H_ -#define OS_LINUX_MUTEX_H_ +#ifndef FSFW_OSAL_LINUX_MUTEX_H_ +#define FSFW_OSAL_LINUX_MUTEX_H_ #include "../../ipc/MutexIF.h" #include - class Mutex : public MutexIF { public: Mutex(); diff --git a/osal/linux/MutexFactory.cpp b/osal/linux/MutexFactory.cpp index 8c2faf888..80211f8bc 100644 --- a/osal/linux/MutexFactory.cpp +++ b/osal/linux/MutexFactory.cpp @@ -1,6 +1,7 @@ -#include "../../ipc/MutexFactory.h" #include "Mutex.h" +#include "../../ipc/MutexFactory.h" + //TODO: Different variant than the lazy loading in QueueFactory. What's better and why? MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); diff --git a/osal/linux/PosixThread.cpp b/osal/linux/PosixThread.cpp index ddb1f74f6..55d74de3e 100644 --- a/osal/linux/PosixThread.cpp +++ b/osal/linux/PosixThread.cpp @@ -1,5 +1,7 @@ -#include "../../serviceinterface/ServiceInterfaceStream.h" #include "PosixThread.h" + +#include "../../serviceinterface/ServiceInterfaceStream.h" + #include #include @@ -149,8 +151,10 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { status = pthread_attr_setstack(&attributes, stackPointer, stackSize); if(status != 0){ - sif::error << "Posix Thread attribute setStack failed with: " << - strerror(status) << std::endl; + sif::error << "PosixThread::createTask: pthread_attr_setstack " + " failed with: " << strerror(status) << std::endl; + sif::error << "Make sure the specified stack size is valid and is " + "larger than the minimum allowed stack size." << std::endl; } status = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED); diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index e4710933e..cfb5f12dd 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -1,6 +1,7 @@ -#include "../../tasks/SemaphoreFactory.h" #include "BinarySemaphore.h" #include "CountingSemaphore.h" + +#include "../../tasks/SemaphoreFactory.h" #include "../../serviceinterface/ServiceInterfaceStream.h" SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; diff --git a/osal/linux/TaskFactory.cpp b/osal/linux/TaskFactory.cpp index f507c7671..d18a03161 100644 --- a/osal/linux/TaskFactory.cpp +++ b/osal/linux/TaskFactory.cpp @@ -1,5 +1,6 @@ #include "FixedTimeslotTask.h" #include "PeriodicPosixTask.h" + #include "../../tasks/TaskFactory.h" #include "../../returnvalues/HasReturnvaluesIF.h" diff --git a/osal/linux/Timer.cpp b/osal/linux/Timer.cpp index ee964baa0..bae631d72 100644 --- a/osal/linux/Timer.cpp +++ b/osal/linux/Timer.cpp @@ -1,6 +1,7 @@ +#include "Timer.h" #include "../../serviceinterface/ServiceInterfaceStream.h" #include -#include "Timer.h" + Timer::Timer() { sigevent sigEvent; diff --git a/osal/windows/CMakeLists.txt b/osal/windows/CMakeLists.txt new file mode 100644 index 000000000..b6e76d6a3 --- /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/TcWinUdpPollingTask.cpp b/osal/windows/TcWinUdpPollingTask.cpp index 7b54bb2cf..06deafd10 100644 --- a/osal/windows/TcWinUdpPollingTask.cpp +++ b/osal/windows/TcWinUdpPollingTask.cpp @@ -119,7 +119,7 @@ void TcWinUdpPollingTask::setTimeout(double timeoutSeconds) { int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&timeoutMs), sizeof(DWORD)); if(result == -1) { - sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting " + sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting " "receive timeout failed with " << strerror(errno) << std::endl; } } @@ -128,17 +128,22 @@ void TcWinUdpPollingTask::handleReadError() { int error = WSAGetLastError(); switch(error) { case(WSANOTINITIALISED): { - sif::info << "TmTcWinUdpBridge::handleReadError: WSANOTINITIALISED: " + sif::info << "TcWinUdpPollingTask::handleReadError: WSANOTINITIALISED: " << "WSAStartup(...) call " << "necessary" << std::endl; break; } case(WSAEFAULT): { - sif::info << "TmTcWinUdpBridge::handleReadError: WSADEFAULT: " + sif::info << "TcWinUdpPollingTask::handleReadError: WSADEFAULT: " << "Bad address " << std::endl; break; } + case(WSAEINVAL): { + sif::info << "TcWinUdpPollingTask::handleReadError: WSAEINVAL: " + << "Invalid input parameters. " << std::endl; + break; + } default: { - sif::info << "TmTcWinUdpBridge::handleReadError: Error code: " + sif::info << "TcWinUdpPollingTask::handleReadError: Error code: " << error << std::endl; break; } diff --git a/parameters/CMakeLists.txt b/parameters/CMakeLists.txt new file mode 100644 index 000000000..fb5e45900 --- /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 005403fa5..19c12d81f 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 659b00def..23d1a1f35 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 e9f3191fc..af1f9ce83 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 31d7fe0bc..fd4481eec 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 6adc6857c..d9f1ef685 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 f07205d4b..168a535f2 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 000000000..1c625db11 --- /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 3ea0b18cc..1c30d83f3 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 "../power/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, - GlobalDataPool::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) { @@ -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 362a30dd2..b892611bc 100644 --- a/power/Fuse.h +++ b/power/Fuse.h @@ -1,17 +1,16 @@ -#ifndef FUSE_H_ -#define FUSE_H_ +#ifndef FSFW_POWER_FUSE_H_ +#define FSFW_POWER_FUSE_H_ + +#include "PowerComponentIF.h" +#include "PowerSwitchIF.h" -#include "../datapoolglob/GlobalDataSet.h" -#include "../datapoolglob/GlobalPoolVariable.h" -#include "../datapoolglob/PIDReader.h" #include "../devicehandlers/HealthDevice.h" #include "../monitoring/AbsLimitMonitor.h" -#include "../power/PowerComponentIF.h" -#include "../power/PowerSwitchIF.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../parameters/ParameterHelper.h" #include +#include "../datapoollocal/StaticLocalDataSet.h" namespace Factory { void setStaticFrameworkObjectIds(); } @@ -26,10 +25,10 @@ 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; @@ -39,8 +38,8 @@ public: 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(); @@ -70,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, @@ -85,12 +84,14 @@ private: }; PowerMonitor powerMonitor; - GlobDataSet set; - PIDReader voltage; - PIDReader current; - PIDReader state; - gp_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; @@ -103,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 6012ad4ca..c31b9a85e 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 6d1c9c06d..c1add3b91 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 c2e3a6a56..f35b4d1d3 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 50cb6acd2..1ef041e30 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 da0bd8c73..a0ccb1ca7 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 "../datapoolglob/GlobalDataSet.h" -#include "../datapoolglob/GlobalPoolVariable.h" -#include "../datapoolglob/PIDReader.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; - GlobDataSet 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 - gp_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 c6e4b2573..b1f53a35a 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: @@ -72,4 +70,4 @@ public: }; -#endif /* POWERSWITCHIF_H_ */ +#endif /* FSFW_POWER_POWERSWITCHIF_H_ */ diff --git a/power/PowerSwitcher.cpp b/power/PowerSwitcher.cpp index 6296a04c7..ed37998ec 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 0f1c02deb..f4e2138d4 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 000000000..758c26293 --- /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/Service3Housekeeping.cpp b/pus/Service3Housekeeping.cpp new file mode 100644 index 000000000..175af026b --- /dev/null +++ b/pus/Service3Housekeeping.cpp @@ -0,0 +1,295 @@ +#include "Service3Housekeeping.h" +#include "servicepackets/Service3Packets.h" +#include "../datapoollocal/HasLocalDataPoolIF.h" + + +Service3Housekeeping::Service3Housekeeping(object_id_t objectId, uint16_t apid, + uint8_t serviceId): + CommandingServiceBase(objectId, apid, serviceId, + NUM_OF_PARALLEL_COMMANDS, COMMAND_TIMEOUT_SECONDS) {} + +Service3Housekeeping::~Service3Housekeeping() {} + +ReturnValue_t Service3Housekeeping::isValidSubservice(uint8_t subservice) { + switch(static_cast(subservice)) { + case Subservice::ENABLE_PERIODIC_HK_REPORT_GENERATION: + case Subservice::DISABLE_PERIODIC_HK_REPORT_GENERATION: + case Subservice::ENABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION: + case Subservice::DISABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION: + case Subservice::REPORT_HK_REPORT_STRUCTURES: + case Subservice::REPORT_DIAGNOSTICS_REPORT_STRUCTURES : + case Subservice::GENERATE_ONE_PARAMETER_REPORT: + case Subservice::GENERATE_ONE_DIAGNOSTICS_REPORT: + case Subservice::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL: + case Subservice::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL: + return HasReturnvaluesIF::RETURN_OK; + // Telemetry or invalid subservice. + case Subservice::HK_DEFINITIONS_REPORT: + case Subservice::DIAGNOSTICS_DEFINITION_REPORT: + case Subservice::HK_REPORT: + case Subservice::DIAGNOSTICS_REPORT: + default: + return AcceptsTelecommandsIF::INVALID_SUBSERVICE; + } +} + +ReturnValue_t Service3Housekeeping::getMessageQueueAndObject(uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, + MessageQueueId_t *id, object_id_t *objectId) { + ReturnValue_t result = checkAndAcquireTargetID(objectId,tcData,tcDataLen); + if(result != RETURN_OK) { + return result; + } + return checkInterfaceAndAcquireMessageQueue(id,objectId); +} + +ReturnValue_t Service3Housekeeping::checkAndAcquireTargetID( + object_id_t* objectIdToSet, const uint8_t* tcData, size_t tcDataLen) { + if(SerializeAdapter::deSerialize(objectIdToSet, &tcData, &tcDataLen, + SerializeIF::Endianness::BIG) != HasReturnvaluesIF::RETURN_OK) { + return CommandingServiceBase::INVALID_TC; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Service3Housekeeping::checkInterfaceAndAcquireMessageQueue( + MessageQueueId_t* messageQueueToSet, object_id_t* objectId) { + // check HasLocalDataPoolIF property of target + HasLocalDataPoolIF* possibleTarget = + objectManager->get(*objectId); + if(possibleTarget == nullptr){ + return CommandingServiceBase::INVALID_OBJECT; + } + *messageQueueToSet = possibleTarget->getCommandQueue(); + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t Service3Housekeeping::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::ENABLE_PERIODIC_HK_REPORT_GENERATION: + return prepareReportingTogglingCommand(message, objectId, true, false, + tcData, tcDataLen); + case Subservice::DISABLE_PERIODIC_HK_REPORT_GENERATION: + return prepareReportingTogglingCommand(message, objectId, false, false, + tcData, tcDataLen); + case Subservice::ENABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION: + return prepareReportingTogglingCommand(message, objectId, true, true, + tcData, tcDataLen); + case Subservice::DISABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION: + return prepareReportingTogglingCommand(message, objectId, false, true, + tcData, tcDataLen); + case Subservice::REPORT_HK_REPORT_STRUCTURES: + return prepareStructureReportingCommand(message, objectId, false, tcData, + tcDataLen); + case Subservice::REPORT_DIAGNOSTICS_REPORT_STRUCTURES: + return prepareStructureReportingCommand(message, objectId, true, tcData, + tcDataLen); + case Subservice::GENERATE_ONE_PARAMETER_REPORT: + return prepareOneShotReportCommand(message, objectId, false, + tcData, tcDataLen); + case Subservice::GENERATE_ONE_DIAGNOSTICS_REPORT: + return prepareOneShotReportCommand(message, objectId, true, + tcData, tcDataLen); + case Subservice::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL: + return prepareCollectionIntervalModificationCommand(message, objectId, + false, tcData, tcDataLen); + case Subservice::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL: + return prepareCollectionIntervalModificationCommand(message, objectId, + true, tcData, tcDataLen); + case Subservice::HK_DEFINITIONS_REPORT: + case Subservice::DIAGNOSTICS_DEFINITION_REPORT: + case Subservice::HK_REPORT: + case Subservice::DIAGNOSTICS_REPORT: + // Those are telemetry packets. + return CommandingServiceBase::INVALID_TC; + default: + // should never happen, subservice was already checked. + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Service3Housekeeping::prepareReportingTogglingCommand( + CommandMessage *command, object_id_t objectId, + bool enableReporting, bool isDiagnostics, + const uint8_t* tcData, size_t tcDataLen) { + if(tcDataLen < sizeof(sid_t)) { + // TC data should consist of object ID and set ID. + return CommandingServiceBase::INVALID_TC; + } + + sid_t targetSid = buildSid(objectId, &tcData, &tcDataLen); + HousekeepingMessage::setToggleReportingCommand(command, targetSid, + enableReporting, isDiagnostics); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Service3Housekeeping::prepareStructureReportingCommand( + CommandMessage *command, object_id_t objectId, bool isDiagnostics, + const uint8_t* tcData, size_t tcDataLen) { + if(tcDataLen < sizeof(sid_t)) { + // TC data should consist of object ID and set ID. + return CommandingServiceBase::INVALID_TC; + } + + sid_t targetSid = buildSid(objectId, &tcData, &tcDataLen); + HousekeepingMessage::setStructureReportingCommand(command, targetSid, + isDiagnostics); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Service3Housekeeping::prepareOneShotReportCommand( + CommandMessage *command, object_id_t objectId, bool isDiagnostics, + const uint8_t *tcData, size_t tcDataLen) { + if(tcDataLen < sizeof(sid_t)) { + // TC data should consist of object ID and set ID. + return CommandingServiceBase::INVALID_TC; + } + + sid_t targetSid = buildSid(objectId, &tcData, &tcDataLen); + HousekeepingMessage::setOneShotReportCommand(command, targetSid, + isDiagnostics); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Service3Housekeeping::prepareCollectionIntervalModificationCommand( + CommandMessage *command, object_id_t objectId, bool isDiagnostics, + const uint8_t *tcData, size_t tcDataLen) { + if(tcDataLen < sizeof(sid_t) + sizeof(float)) { + // SID plus the size of the new collection intervL. + return CommandingServiceBase::INVALID_TC; + } + + sid_t targetSid = buildSid(objectId, &tcData, &tcDataLen); + float newCollectionInterval = 0; + SerializeAdapter::deSerialize(&newCollectionInterval, &tcData, &tcDataLen, + SerializeIF::Endianness::BIG); + HousekeepingMessage::setCollectionIntervalModificationCommand(command, + targetSid, newCollectionInterval, isDiagnostics); + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply, + Command_t previousCommand, uint32_t *state, + CommandMessage* optionalNextCommand, object_id_t objectId, + bool *isStep) { + Command_t command = reply->getCommand(); + switch(command) { + + case(HousekeepingMessage::HK_REPORT): { + ReturnValue_t result = generateHkReply(reply, + static_cast(Subservice::HK_REPORT)); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return CommandingServiceBase::EXECUTION_COMPLETE; + } + + case(HousekeepingMessage::DIAGNOSTICS_REPORT): { + ReturnValue_t result = generateHkReply(reply, + static_cast(Subservice::DIAGNOSTICS_REPORT)); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return CommandingServiceBase::EXECUTION_COMPLETE; + } + + case(HousekeepingMessage::HK_DEFINITIONS_REPORT): { + return generateHkReply(reply, static_cast( + Subservice::HK_DEFINITIONS_REPORT)); + break; + } + case(HousekeepingMessage::DIAGNOSTICS_DEFINITION_REPORT): { + return generateHkReply(reply, static_cast( + Subservice::DIAGNOSTICS_DEFINITION_REPORT)); + break; + } + + case(HousekeepingMessage::HK_REQUEST_SUCCESS): { + return CommandingServiceBase::EXECUTION_COMPLETE; + } + + case(HousekeepingMessage::HK_REQUEST_FAILURE): { + failureParameter1 = objectId; + ReturnValue_t error = HasReturnvaluesIF::RETURN_FAILED; + HousekeepingMessage::getHkRequestFailureReply(reply,&error); + failureParameter2 = error; + return CommandingServiceBase::EXECUTION_COMPLETE; + } + + default: + sif::error << "Service3Housekeeping::handleReply: Invalid reply with " + << "reply command " << command << "!" << std::endl; + return CommandingServiceBase::INVALID_REPLY; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void Service3Housekeeping::handleUnrequestedReply( + CommandMessage* reply) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + Command_t command = reply->getCommand(); + + switch(command) { + + case(HousekeepingMessage::DIAGNOSTICS_REPORT): { + result = generateHkReply(reply, + static_cast(Subservice::DIAGNOSTICS_REPORT)); + break; + } + + case(HousekeepingMessage::HK_REPORT): { + result = generateHkReply(reply, + static_cast(Subservice::HK_REPORT)); + break; + } + + default: + sif::error << "Service3Housekeeping::handleUnrequestedReply: Invalid " + << "reply with " << "reply command " << command << "!" + << std::endl; + return; + } + + if(result != HasReturnvaluesIF::RETURN_OK) { + // Configuration error + sif::debug << "Service3Housekeeping::handleUnrequestedReply:" + << "Could not generate reply!" << std::endl; + } +} + +MessageQueueId_t Service3Housekeeping::getHkQueue() const { + return commandQueue->getId(); +} + +ReturnValue_t Service3Housekeeping::generateHkReply( + const CommandMessage* hkMessage, uint8_t subserviceId) { + store_address_t storeId; + + sid_t sid = HousekeepingMessage::getHkDataReply(hkMessage, &storeId); + auto resultPair = IPCStore->getData(storeId); + if(resultPair.first != HasReturnvaluesIF::RETURN_OK) { + return resultPair.first; + } + + HkPacket hkPacket(sid, resultPair.second.data(), resultPair.second.size()); + return sendTmPacket(static_cast(subserviceId), + hkPacket.hkData, hkPacket.hkSize, nullptr, 0); +} + +sid_t Service3Housekeeping::buildSid(object_id_t objectId, + const uint8_t** tcData, size_t* tcDataLen) { + sid_t targetSid; + targetSid.objectId = objectId; + // skip deserialization of object ID, was already done. + *tcData += sizeof(object_id_t); + *tcDataLen -= sizeof(object_id_t); + // size check is expected to be performed beforehand! + SerializeAdapter::deSerialize(&targetSid.ownerSetId, tcData, tcDataLen, + SerializeIF::Endianness::BIG); + return targetSid; +} diff --git a/pus/Service3Housekeeping.h b/pus/Service3Housekeeping.h new file mode 100644 index 000000000..269710ef3 --- /dev/null +++ b/pus/Service3Housekeeping.h @@ -0,0 +1,105 @@ +#ifndef FSFW_PUS_SERVICE3HOUSEKEEPINGSERVICE_H_ +#define FSFW_PUS_SERVICE3HOUSEKEEPINGSERVICE_H_ + +#include "../housekeeping/AcceptsHkPacketsIF.h" +#include "../housekeeping/HousekeepingMessage.h" +#include "../tmtcservices/CommandingServiceBase.h" + +/** + * @brief Manges spacecraft housekeeping reports and + * sends pool variables (temperature, GPS data ...) to ground. + * + * @details Full Documentation: ECSS-E70-41A or ECSS-E-ST-70-41C. + * Implementation based on PUS-C + * + * The housekeeping service type provides means to control and adapt the + * spacecraft reporting plan according to the mission phases. + * The housekeeping service type provides the visibility of any + * on-board parameters assembled in housekeeping parameter report structures + * or diagnostic parameter report structures as required for the mission. + * The parameter report structures used by the housekeeping service can + * be predefined on-board or created when needed. + * + * @author R. Mueller + * @ingroup pus_services + */ +class Service3Housekeeping: public CommandingServiceBase, + public AcceptsHkPacketsIF { +public: + static constexpr uint8_t NUM_OF_PARALLEL_COMMANDS = 4; + static constexpr uint16_t COMMAND_TIMEOUT_SECONDS = 60; + + Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId); + virtual~ Service3Housekeeping(); +protected: + /* CSB abstract functions implementation . See CSB documentation. */ + 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; + ReturnValue_t prepareCommand(CommandMessage* message, + uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, + uint32_t *state, object_id_t objectId) override; + ReturnValue_t handleReply(const CommandMessage* reply, + Command_t previousCommand, uint32_t *state, + CommandMessage* optionalNextCommand, object_id_t objectId, + bool *isStep) override; + + virtual MessageQueueId_t getHkQueue() const; +private: + enum class Subservice { + ENABLE_PERIODIC_HK_REPORT_GENERATION = 5, //!< [EXPORT] : [TC] + DISABLE_PERIODIC_HK_REPORT_GENERATION = 6, //!< [EXPORT] : [TC] + + ENABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION = 7, //!< [EXPORT] : [TC] + DISABLE_PERIODIC_DIAGNOSTICS_REPORT_GENERATION = 8, //!< [EXPORT] : [TC] + + //! [EXPORT] : [TC] Report HK structure by supplying SID + REPORT_HK_REPORT_STRUCTURES = 9, + //! [EXPORT] : [TC] Report Diagnostics structure by supplying SID + REPORT_DIAGNOSTICS_REPORT_STRUCTURES = 11, + + //! [EXPORT] : [TM] Report corresponding to Subservice 9 TC + HK_DEFINITIONS_REPORT = 10, + //! [EXPORT] : [TM] Report corresponding to Subservice 11 TC + DIAGNOSTICS_DEFINITION_REPORT = 12, + + //! [EXPORT] : [TM] Core packet. Contains Housekeeping data + HK_REPORT = 25, + //! [EXPORT] : [TM] Core packet. Contains diagnostics data + DIAGNOSTICS_REPORT = 26, + + /* PUS-C */ + GENERATE_ONE_PARAMETER_REPORT = 27, //!< [EXPORT] : [TC] + GENERATE_ONE_DIAGNOSTICS_REPORT = 28, //!< [EXPORT] : [TC] + + MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL = 31, //!< [EXPORT] : [TC] + MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL = 32, //!< [EXPORT] : [TC] + }; + + 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 generateHkReply(const CommandMessage* hkMessage, + uint8_t subserviceId); + ReturnValue_t prepareReportingTogglingCommand(CommandMessage* command, + object_id_t objectId, bool enableReporting, bool isDiagnostics, + const uint8_t* tcData, size_t tcDataLen); + ReturnValue_t prepareStructureReportingCommand(CommandMessage* command, + object_id_t objectId, bool isDiagnostics, const uint8_t* tcData, + size_t tcDataLen); + ReturnValue_t prepareOneShotReportCommand(CommandMessage* command, + object_id_t objectId, bool isDiagnostics, const uint8_t* tcData, + size_t tcDataLen); + ReturnValue_t prepareCollectionIntervalModificationCommand( + CommandMessage* command, object_id_t objectId, bool isDiagnostics, + const uint8_t* tcData, size_t tcDataLen); + + void handleUnrequestedReply(CommandMessage* reply) override; + sid_t buildSid(object_id_t objectId, const uint8_t** tcData, + size_t* tcDataLen); +}; + +#endif /* FSFW_PUS_SERVICE3HOUSEKEEPINGSERVICE_H_ */ diff --git a/pus/servicepackets/Service3Packets.h b/pus/servicepackets/Service3Packets.h new file mode 100644 index 000000000..05732e11b --- /dev/null +++ b/pus/servicepackets/Service3Packets.h @@ -0,0 +1,21 @@ +#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE3PACKETS_H_ +#define FSFW_PUS_SERVICEPACKETS_SERVICE3PACKETS_H_ + +#include +#include + +/** + * @brief Subservices 25 and 26: TM packets + * @ingroup spacepackets + */ +class HkPacket { //!< [EXPORT] : [SUBSERVICE] 25, 26 +public: + sid_t sid; //!< [EXPORT] : [COMMENT] Structure ID (SID) of housekeeping data. + const uint8_t* hkData; //!< [EXPORT] : [MAXSIZE] Deduced size + size_t hkSize; //!< [EXPORT] : [IGNORE] + + HkPacket(sid_t sid, const uint8_t* data, size_t size): + sid(sid), hkData(data), hkSize(size) {} +}; + +#endif /* FSFW_PUS_SERVICEPACKETS_SERVICE3PACKETS_H_ */ diff --git a/rmap/CMakeLists.txt b/rmap/CMakeLists.txt new file mode 100644 index 000000000..78c99e420 --- /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/rmap/RMAP.cpp b/rmap/RMAP.cpp index 4ab8b17ba..7ea6e5329 100644 --- a/rmap/RMAP.cpp +++ b/rmap/RMAP.cpp @@ -1,8 +1,10 @@ -#include "../devicehandlers/DeviceCommunicationIF.h" -#include "rmapStructs.h" #include "RMAP.h" +#include "rmapStructs.h" #include "RMAPChannelIF.h" -#include + +#include "../devicehandlers/DeviceCommunicationIF.h" + +#include ReturnValue_t RMAP::reset(RMAPCookie* cookie) { return cookie->getChannel()->reset(); @@ -12,8 +14,8 @@ RMAP::RMAP(){ } -ReturnValue_t RMAP::sendWriteCommand(RMAPCookie *cookie, uint8_t* buffer, - uint32_t length) { +ReturnValue_t RMAP::sendWriteCommand(RMAPCookie *cookie, const uint8_t* buffer, + size_t length) { uint8_t instruction; if ((buffer == NULL) && (length != 0)) { @@ -61,7 +63,7 @@ ReturnValue_t RMAP::sendReadCommand(RMAPCookie *cookie, uint32_t expLength) { } ReturnValue_t RMAP::getReadReply(RMAPCookie *cookie, uint8_t **buffer, - uint32_t *size) { + size_t *size) { if (cookie->getChannel() == NULL) { return COMMAND_NO_CHANNEL; } diff --git a/rmap/RMAP.h b/rmap/RMAP.h index d14320cbc..83e29fede 100644 --- a/rmap/RMAP.h +++ b/rmap/RMAP.h @@ -1,8 +1,8 @@ -#ifndef RMAPpp_H_ -#define RMAPpp_H_ +#ifndef FSFW_RMAP_RMAP_H_ +#define FSFW_RMAP_RMAP_H_ #include "../returnvalues/HasReturnvaluesIF.h" -#include "RMAPCookie.h" +#include "../rmap/RMAPCookie.h" //SHOULDTODO: clean up includes for RMAP, should be enough to include RMAP.h but right now it's quite chaotic... @@ -153,8 +153,8 @@ public: * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write command * - return codes of RMAPChannelIF::sendCommand() */ - static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, uint8_t* buffer, - uint32_t length); + static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t* buffer, + size_t length); /** * get the reply to a write command @@ -204,7 +204,7 @@ public: * - return codes of RMAPChannelIF::getReply() */ static ReturnValue_t getReadReply(RMAPCookie *cookie, uint8_t **buffer, - uint32_t *size); + size_t *size); /** * @see sendReadCommand() diff --git a/rmap/RMAPChannelIF.h b/rmap/RMAPChannelIF.h index dac4a7220..0aa809c53 100644 --- a/rmap/RMAPChannelIF.h +++ b/rmap/RMAPChannelIF.h @@ -1,8 +1,9 @@ -#ifndef RMAPCHANNELIF_H_ -#define RMAPCHANNELIF_H_ +#ifndef FSFW_RMAP_RMAPCHANNELIF_H_ +#define FSFW_RMAP_RMAPCHANNELIF_H_ #include "RMAPCookie.h" #include "../returnvalues/HasReturnvaluesIF.h" +#include class RMAPChannelIF { public: @@ -73,7 +74,7 @@ public: * - @c NOT_SUPPORTED if you dont feel like implementing something... */ virtual ReturnValue_t sendCommand(RMAPCookie *cookie, uint8_t instruction, - uint8_t *data, uint32_t datalen)=0; + const uint8_t *data, size_t datalen)=0; /** * get the reply to an rmap command @@ -92,7 +93,7 @@ public: * - all RMAP standard replies */ virtual ReturnValue_t getReply(RMAPCookie *cookie, uint8_t **databuffer, - uint32_t *len)=0; + size_t *len)=0; /** * @@ -112,4 +113,4 @@ public: }; -#endif /* RMAPCHANNELIF_H_ */ +#endif /* FSFW_RMAP_RMAPCHANNELIF_H_ */ diff --git a/rmap/RMAPCookie.cpp b/rmap/RMAPCookie.cpp index 597f066c5..f8fe2d3eb 100644 --- a/rmap/RMAPCookie.cpp +++ b/rmap/RMAPCookie.cpp @@ -1,6 +1,6 @@ #include "RMAPChannelIF.h" #include "RMAPCookie.h" -#include +#include RMAPCookie::RMAPCookie() { @@ -31,7 +31,8 @@ RMAPCookie::RMAPCookie() { RMAPCookie::RMAPCookie(uint32_t set_address, uint8_t set_extended_address, - RMAPChannelIF *set_channel, uint8_t set_command_mask, uint32_t maxReplyLen) { + RMAPChannelIF *set_channel, uint8_t set_command_mask, + size_t maxReplyLen) { this->header.dest_address = 0; this->header.protocol = 0x01; this->header.instruction = 0; @@ -93,11 +94,11 @@ RMAPCookie::~RMAPCookie() { } -uint32_t RMAPCookie::getMaxReplyLen() const { +size_t RMAPCookie::getMaxReplyLen() const { return maxReplyLen; } -void RMAPCookie::setMaxReplyLen(uint32_t maxReplyLen) { +void RMAPCookie::setMaxReplyLen(size_t maxReplyLen) { this->maxReplyLen = maxReplyLen; } diff --git a/rmap/RMAPCookie.h b/rmap/RMAPCookie.h index 4c6081bdd..385426468 100644 --- a/rmap/RMAPCookie.h +++ b/rmap/RMAPCookie.h @@ -1,8 +1,9 @@ -#ifndef RMAPCOOKIE_H_ -#define RMAPCOOKIE_H_ +#ifndef FSFW_RMAP_RMAPCOOKIE_H_ +#define FSFW_RMAP_RMAPCOOKIE_H_ -#include "../devicehandlers/CookieIF.h" #include "rmapStructs.h" +#include "../devicehandlers/CookieIF.h" +#include class RMAPChannelIF; @@ -12,7 +13,8 @@ public: RMAPCookie(); RMAPCookie(uint32_t set_address, uint8_t set_extended_address, - RMAPChannelIF *set_channel, uint8_t set_command_mask, uint32_t maxReplyLen = 0); + RMAPChannelIF *set_channel, uint8_t set_command_mask, + size_t maxReplyLen = 0); virtual ~RMAPCookie(); @@ -28,8 +30,8 @@ public: void setCommandMask(uint8_t commandMask); uint8_t getCommandMask(); - uint32_t getMaxReplyLen() const; - void setMaxReplyLen(uint32_t maxReplyLen); + size_t getMaxReplyLen() const; + void setMaxReplyLen(size_t maxReplyLen); uint16_t getTransactionIdentifier() const; void setTransactionIdentifier(uint16_t id_); @@ -55,4 +57,4 @@ protected: uint8_t dataCRC; }; -#endif /* RMAPCOOKIE_H_ */ +#endif /* FSFW_RMAP_RMAPCOOKIE_H_ */ diff --git a/rmap/RmapDeviceCommunicationIF.cpp b/rmap/RmapDeviceCommunicationIF.cpp index db4a75b55..d81baabd5 100644 --- a/rmap/RmapDeviceCommunicationIF.cpp +++ b/rmap/RmapDeviceCommunicationIF.cpp @@ -5,9 +5,9 @@ RmapDeviceCommunicationIF::~RmapDeviceCommunicationIF() { } -ReturnValue_t RmapDeviceCommunicationIF::sendMessage(CookieIF* cookie, - uint8_t* data, uint32_t len) { - return RMAP::sendWriteCommand((RMAPCookie *) cookie, data, len); +ReturnValue_t RmapDeviceCommunicationIF::sendMessage(CookieIF *cookie, + const uint8_t * sendData, size_t sendLen) { + return RMAP::sendWriteCommand((RMAPCookie *) cookie, sendData, sendLen); } ReturnValue_t RmapDeviceCommunicationIF::getSendSuccess(CookieIF* cookie) { @@ -15,13 +15,13 @@ ReturnValue_t RmapDeviceCommunicationIF::getSendSuccess(CookieIF* cookie) { } ReturnValue_t RmapDeviceCommunicationIF::requestReceiveMessage( - CookieIF* cookie) { + CookieIF *cookie, size_t requestLen) { return RMAP::sendReadCommand((RMAPCookie *) cookie, ((RMAPCookie *) cookie)->getMaxReplyLen()); } ReturnValue_t RmapDeviceCommunicationIF::readReceivedMessage(CookieIF* cookie, - uint8_t** buffer, uint32_t* size) { + uint8_t** buffer, size_t * size) { return RMAP::getReadReply((RMAPCookie *) cookie, buffer, size); } diff --git a/rmap/RmapDeviceCommunicationIF.h b/rmap/RmapDeviceCommunicationIF.h index dacc720b4..1333966a7 100644 --- a/rmap/RmapDeviceCommunicationIF.h +++ b/rmap/RmapDeviceCommunicationIF.h @@ -1,10 +1,11 @@ -#ifndef MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ -#define MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ +#ifndef FSFW_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ +#define FSFW_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ #include "../devicehandlers/DeviceCommunicationIF.h" /** - * @brief This class is a implementation of a DeviceCommunicationIF for RMAP calls. It expects RMAPCookies or a derived class of RMAPCookies + * @brief This class is a implementation of a DeviceCommunicationIF for RMAP calls. + * It expects RMAPCookies or a derived class of RMAPCookies * * @details The open, close and reOpen calls are mission specific * The open call might return any child of RMAPCookies @@ -16,65 +17,73 @@ class RmapDeviceCommunicationIF: public DeviceCommunicationIF { public: virtual ~RmapDeviceCommunicationIF(); - /** - * This method is mission specific as the open call will return a mission specific cookie - * - * @param cookie A cookie, can be mission specific subclass of RMAP Cookie - * @param address The address of the RMAP Cookie - * @param maxReplyLen Maximum length of expected reply - * @return - */ - virtual ReturnValue_t open(CookieIF **cookie, uint32_t address, - uint32_t maxReplyLen) = 0; - - /** - * Use an existing cookie to open a connection to a new DeviceCommunication. - * The previous connection must not be closed. - * If the returnvalue is not RETURN_OK, the cookie is unchanged and - * can be used with the previous connection. - * + * @brief Device specific initialization, using the cookie. + * @details + * The cookie is already prepared in the factory. If the communication + * interface needs to be set up in some way and requires cookie information, + * this can be performed in this function, which is called on device handler + * initialization. * @param cookie - * @param address - * @param maxReplyLen - * @return + * @return -@c RETURN_OK if initialization was successfull + * - Everything else triggers failure event with returnvalue as parameter 1 */ - virtual ReturnValue_t reOpen(CookieIF *cookie, uint32_t address, - uint32_t maxReplyLen) = 0; - + virtual ReturnValue_t initializeInterface(CookieIF * cookie) = 0; /** - * Closing call of connection and memory free of cookie. Mission dependent call + * Called by DHB in the SEND_WRITE doSendWrite(). + * This function is used to send data to the physical device + * by implementing and calling related drivers or wrapper functions. * @param cookie + * @param data + * @param len + * @return -@c RETURN_OK for successfull send + * - Everything else triggers failure event with returnvalue as parameter 1 */ - virtual void close(CookieIF *cookie) = 0; + virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, + size_t sendLen); - //SHOULDDO can data be const? /** - * - * - * @param cookie Expects an RMAPCookie or derived from RMAPCookie Class - * @param data Data to be send - * @param len Length of the data to be send - * @return - Return codes of RMAP::sendWriteCommand() + * Called by DHB in the GET_WRITE doGetWrite(). + * Get send confirmation that the data in sendMessage() was sent successfully. + * @param cookie + * @return -@c RETURN_OK if data was sent successfull + * - Everything else triggers falure event with returnvalue as parameter 1 */ - virtual ReturnValue_t sendMessage(CookieIF *cookie, uint8_t *data, - uint32_t len); - virtual ReturnValue_t getSendSuccess(CookieIF *cookie); - virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie); + /** + * Called by DHB in the SEND_WRITE doSendRead(). + * It is assumed that it is always possible to request a reply + * from a device. + * + * @param cookie + * @return -@c RETURN_OK to confirm the request for data has been sent. + * -@c NO_READ_REQUEST if no request shall be made. readReceivedMessage() + * will not be called in the respective communication cycle. + * - Everything else triggers failure event with returnvalue as parameter 1 + */ + virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen); + /** + * Called by DHB in the GET_WRITE doGetRead(). + * This function is used to receive data from the physical device + * by implementing and calling related drivers or wrapper functions. + * @param cookie + * @param data + * @param len + * @return @c RETURN_OK for successfull receive + * - Everything else triggers failure event with returnvalue as parameter 1 + */ virtual ReturnValue_t readReceivedMessage(CookieIF *cookie, uint8_t **buffer, - uint32_t *size); + size_t *size); - virtual ReturnValue_t setAddress(CookieIF *cookie, uint32_t address); - - virtual uint32_t getAddress(CookieIF *cookie); - - virtual ReturnValue_t setParameter(CookieIF *cookie, uint32_t parameter); - - virtual uint32_t getParameter(CookieIF *cookie); + ReturnValue_t setAddress(CookieIF* cookie, + uint32_t address); + uint32_t getAddress(CookieIF* cookie); + ReturnValue_t setParameter(CookieIF* cookie, + uint32_t parameter); + uint32_t getParameter(CookieIF* cookie); }; -#endif /* MISSION_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ */ +#endif /* FSFW_RMAP_RMAPDEVICECOMMUNICATIONINTERFACE_H_ */ diff --git a/rmap/rmapStructs.h b/rmap/rmapStructs.h index bf0fb2606..11d8bb85b 100644 --- a/rmap/rmapStructs.h +++ b/rmap/rmapStructs.h @@ -1,7 +1,7 @@ -#ifndef RMAPSTRUCTS_H_ -#define RMAPSTRUCTS_H_ +#ifndef FSFW_RMAP_RMAPSTRUCTS_H_ +#define FSFW_RMAP_RMAPSTRUCTS_H_ -#include +#include //SHOULDDO: having the defines within a namespace would be nice. Problem are the defines referencing the previous define, eg RMAP_COMMAND_WRITE @@ -95,4 +95,4 @@ struct rmap_write_reply_header { } -#endif /* RMAPSTRUCTS_H_ */ +#endif /* FSFW_RMAP_RMAPSTRUCTS_H_ */ diff --git a/serialize/CMakeLists.txt b/serialize/CMakeLists.txt new file mode 100644 index 000000000..fc2387e80 --- /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 000000000..d84adbeb4 --- /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 000000000..b8138cae7 --- /dev/null +++ b/storagemanager/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ConstStorageAccessor.cpp + StorageAccessor.cpp + LocalPool.cpp + PoolManager.cpp +) \ No newline at end of file diff --git a/storagemanager/ConstStorageAccessor.h b/storagemanager/ConstStorageAccessor.h index 96d2dca2c..570c20ce5 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 000000000..74e362d49 --- /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 3a94c03db..db7711520 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/LocalPool.tpp b/storagemanager/LocalPool.tpp deleted file mode 100644 index 5e61efe45..000000000 --- a/storagemanager/LocalPool.tpp +++ /dev/null @@ -1,305 +0,0 @@ -#ifndef FSFW_STORAGEMANAGER_LOCALPOOL_TPP_ -#define FSFW_STORAGEMANAGER_LOCALPOOL_TPP_ - -#ifndef FSFW_STORAGEMANAGER_LOCALPOOL_H_ -#error Include LocalPool.h before LocalPool.tpp! -#endif - -template -inline LocalPool::LocalPool(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS], bool registered, - bool spillsToHigherPools) : - SystemObject(setObjectId, registered), internalErrorReporter(nullptr), - spillsToHigherPools(spillsToHigherPools) -{ - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - this->element_sizes[n] = element_sizes[n]; - this->n_elements[n] = n_elements[n]; - store[n] = new uint8_t[n_elements[n] * element_sizes[n]]; - size_list[n] = new uint32_t[n_elements[n]]; - memset(store[n], 0x00, (n_elements[n] * element_sizes[n])); - //TODO checkme - memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list))); - } -} - - -template -inline ReturnValue_t LocalPool::findEmpty(uint16_t pool_index, - uint16_t* element) { - ReturnValue_t status = DATA_STORAGE_FULL; - for (uint16_t foundElement = 0; foundElement < n_elements[pool_index]; - foundElement++) { - if (size_list[pool_index][foundElement] == STORAGE_FREE) { - *element = foundElement; - status = RETURN_OK; - break; - } - } - return status; -} - -template -inline void LocalPool::write(store_address_t packet_id, - const uint8_t* data, size_t size) { - uint8_t* ptr; - uint32_t packet_position = getRawPosition(packet_id); - - //check size? -> Not necessary, because size is checked before calling this function. - ptr = &store[packet_id.pool_index][packet_position]; - memcpy(ptr, data, size); - size_list[packet_id.pool_index][packet_id.packet_index] = size; -} - -//Returns page size of 0 in case store_index is illegal -template -inline uint32_t LocalPool::getPageSize(uint16_t pool_index) { - if (pool_index < NUMBER_OF_POOLS) { - return element_sizes[pool_index]; - } else { - return 0; - } -} - -template -inline ReturnValue_t LocalPool::getPoolIndex( - size_t packet_size, uint16_t* poolIndex, uint16_t startAtIndex) { - for (uint16_t n = startAtIndex; n < NUMBER_OF_POOLS; n++) { - //debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " << - // n << ", Element Size: " << element_sizes[n] << std::endl; - if (element_sizes[n] >= packet_size) { - *poolIndex = n; - return RETURN_OK; - } - } - return DATA_TOO_LARGE; -} - -template -inline uint32_t LocalPool::getRawPosition( - store_address_t packet_id) { - return packet_id.packet_index * element_sizes[packet_id.pool_index]; -} - -template -inline ReturnValue_t LocalPool::reserveSpace( - const uint32_t size, store_address_t* address, bool ignoreFault) { - ReturnValue_t status = getPoolIndex(size, &address->pool_index); - if (status != RETURN_OK) { - sif::error << "LocalPool( " << std::hex << getObjectId() << std::dec - << " )::reserveSpace: Packet too large." << std::endl; - return status; - } - status = findEmpty(address->pool_index, &address->packet_index); - while (status != RETURN_OK && spillsToHigherPools) { - status = getPoolIndex(size, &address->pool_index, address->pool_index + 1); - if (status != RETURN_OK) { - //We don't find any fitting pool anymore. - break; - } - status = findEmpty(address->pool_index, &address->packet_index); - } - if (status == RETURN_OK) { - // if (getObjectId() == objects::IPC_STORE && address->pool_index >= 3) { - // debug << "Reserve: Pool: " << std::dec << address->pool_index << - // " Index: " << address->packet_index << std::endl; - // } - - size_list[address->pool_index][address->packet_index] = size; - } else { - if (!ignoreFault and internalErrorReporter != nullptr) { - internalErrorReporter->storeFull(); - } - // error << "LocalPool( " << std::hex << getObjectId() << std::dec - // << " )::reserveSpace: Packet store is full." << std::endl; - } - return status; -} - -template -inline LocalPool::~LocalPool(void) { - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - delete[] store[n]; - delete[] size_list[n]; - } -} - -template -inline 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; -} - -template -inline ReturnValue_t LocalPool::getFreeElement( - store_address_t* storageId, const size_t size, - uint8_t** p_data, bool ignoreFault) { - ReturnValue_t status = reserveSpace(size, storageId, ignoreFault); - if (status == RETURN_OK) { - *p_data = &store[storageId->pool_index][getRawPosition(*storageId)]; - } else { - *p_data = NULL; - } - return status; -} - -template -inline 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)); -} - -template -inline 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; -} - -template -inline ReturnValue_t LocalPool::getData( - store_address_t packet_id, const uint8_t** packet_ptr, size_t* size) { - uint8_t* tempData = nullptr; - ReturnValue_t status = modifyData(packet_id, &tempData, size); - *packet_ptr = tempData; - return status; -} - -template -inline 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)); -} - -template -inline 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; -} - -template -inline ReturnValue_t LocalPool::modifyData( - store_address_t packet_id, uint8_t** packet_ptr, size_t* size) { - ReturnValue_t status = RETURN_FAILED; - if (packet_id.pool_index >= NUMBER_OF_POOLS) { - return ILLEGAL_STORAGE_ID; - } - if ((packet_id.packet_index >= n_elements[packet_id.pool_index])) { - return ILLEGAL_STORAGE_ID; - } - if (size_list[packet_id.pool_index][packet_id.packet_index] - != STORAGE_FREE) { - uint32_t packet_position = getRawPosition(packet_id); - *packet_ptr = &store[packet_id.pool_index][packet_position]; - *size = size_list[packet_id.pool_index][packet_id.packet_index]; - status = RETURN_OK; - } else { - status = DATA_DOES_NOT_EXIST; - } - return status; -} - -template -inline ReturnValue_t LocalPool::deleteData( - store_address_t packet_id) { - //if (getObjectId() == objects::IPC_STORE && packet_id.pool_index >= 3) { - // debug << "Delete: Pool: " << std::dec << packet_id.pool_index << " Index: " - // << packet_id.packet_index << std::endl; - //} - ReturnValue_t status = RETURN_OK; - uint32_t page_size = getPageSize(packet_id.pool_index); - if ((page_size != 0) - && (packet_id.packet_index < n_elements[packet_id.pool_index])) { - uint16_t packet_position = getRawPosition(packet_id); - uint8_t* ptr = &store[packet_id.pool_index][packet_position]; - memset(ptr, 0, page_size); - //Set free list - size_list[packet_id.pool_index][packet_id.packet_index] = STORAGE_FREE; - } else { - //pool_index or packet_index is too large - sif::error << "LocalPool:deleteData failed." << std::endl; - status = ILLEGAL_STORAGE_ID; - } - return status; -} - -template -inline void LocalPool::clearStore() { - for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) { - //TODO checkme - memset(size_list[n], STORAGE_FREE, (n_elements[n] * sizeof(**size_list))); - } -} - -template -inline 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] <= ptr) && (&store[n][n_elements[n]*element_sizes[n]]) > ptr) { - localId.pool_index = n; - uint32_t deltaAddress = ptr - store[n]; - // 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.packet_index = deltaAddress / element_sizes[n]; - result = deleteData(localId); - //if (deltaAddress % element_sizes[n] != 0) { - // error << "Pool::deleteData: address not aligned!" << std::endl; - //} - break; - } - } - if (storeId != NULL) { - *storeId = localId; - } - return result; -} - -template -inline 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 (element_sizes[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 RETURN_OK; -} - -#endif /* FSFW_STORAGEMANAGER_LOCALPOOL_TPP_ */ diff --git a/storagemanager/PoolManager.cpp b/storagemanager/PoolManager.cpp new file mode 100644 index 000000000..3b7b549bd --- /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 8cc6c0654..5786a2252 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/PoolManager.tpp b/storagemanager/PoolManager.tpp deleted file mode 100644 index 2be44ece2..000000000 --- a/storagemanager/PoolManager.tpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ -#define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ - -#ifndef FSFW_STORAGEMANAGER_POOLMANAGER_H_ -#error Include PoolManager.h before PoolManager.tpp! -#endif - -template -inline PoolManager::PoolManager(object_id_t setObjectId, - const uint16_t element_sizes[NUMBER_OF_POOLS], - const uint16_t n_elements[NUMBER_OF_POOLS]) : - LocalPool(setObjectId, element_sizes, n_elements, true) { - mutex = MutexFactory::instance()->createMutex(); -} - -template -inline PoolManager::~PoolManager(void) { - MutexFactory::instance()->deleteMutex(mutex); -} - -template -inline ReturnValue_t PoolManager::reserveSpace( - const uint32_t size, store_address_t* address, bool ignoreFault) { - MutexHelper mutexHelper(mutex,MutexIF::WAITING, mutexTimeoutMs); - ReturnValue_t status = LocalPool::reserveSpace(size, - address,ignoreFault); - return status; -} - -template -inline ReturnValue_t PoolManager::deleteData( - store_address_t packet_id) { - // debug << "PoolManager( " << translateObject(getObjectId()) << - // " )::deleteData from store " << packet_id.pool_index << - // ". id is "<< packet_id.packet_index << std::endl; - MutexHelper mutexHelper(mutex,MutexIF::WAITING, mutexTimeoutMs); - ReturnValue_t status = LocalPool::deleteData(packet_id); - return status; -} - -template -inline ReturnValue_t PoolManager::deleteData(uint8_t* buffer, - size_t size, store_address_t* storeId) { - MutexHelper mutexHelper(mutex,MutexIF::WAITING, mutexTimeoutMs); - ReturnValue_t status = LocalPool::deleteData(buffer, - size, storeId); - return status; -} - -template -inline void PoolManager::setMutexTimeout( - uint32_t mutexTimeoutMs) { - this->mutexTimeout = mutexTimeoutMs; -} - -#endif /* FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ */ diff --git a/storagemanager/StorageAccessor.h b/storagemanager/StorageAccessor.h index 5cf15d509..d5b383eb6 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 ab1998bf9..622519336 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. @@ -40,7 +43,9 @@ public: static const Event GET_DATA_FAILED = MAKE_EVENT(0, severity::LOW); static const Event STORE_DATA_FAILED = MAKE_EVENT(1, severity::LOW); - static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; //!< Indicates an invalid (i.e unused) storage address. + //!< Indicates an invalid (i.e unused) storage address. + static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; + /** * @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 044c07908..ea72f6f89 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 000000000..5c98ee707 --- /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/Subsystem.cpp b/subsystem/Subsystem.cpp index 56d47da23..4de6906c1 100644 --- a/subsystem/Subsystem.cpp +++ b/subsystem/Subsystem.cpp @@ -1,29 +1,21 @@ +#include "Subsystem.h" #include "../health/HealthMessage.h" #include "../objectmanager/ObjectManagerIF.h" #include "../serialize/SerialArrayListAdapter.h" #include "../serialize/SerialFixedArrayListAdapter.h" #include "../serialize/SerializeElement.h" #include "../serialize/SerialLinkedListAdapter.h" -#include "Subsystem.h" + #include Subsystem::Subsystem(object_id_t setObjectId, object_id_t parent, uint32_t maxNumberOfSequences, uint32_t maxNumberOfTables) : - SubsystemBase(setObjectId, parent, 0), isInTransition(false), childrenChangedHealth( - false), uptimeStartTable(0), currentTargetTable(), targetMode( - 0), targetSubmode(SUBMODE_NONE), initialMode(0), currentSequenceIterator(), modeTables( - maxNumberOfTables), modeSequences(maxNumberOfSequences), IPCStore( - NULL) -#ifdef USE_MODESTORE -,modeStore(NULL) -#endif -{ + SubsystemBase(setObjectId, parent, 0), isInTransition(false), + childrenChangedHealth(false), currentTargetTable(), + targetSubmode(SUBMODE_NONE), currentSequenceIterator(), + modeTables(maxNumberOfTables), modeSequences(maxNumberOfSequences) {} -} - -Subsystem::~Subsystem() { - //Auto-generated destructor stub -} +Subsystem::~Subsystem() {} ReturnValue_t Subsystem::checkSequence(HybridIterator iter, Mode_t fallbackSequence) { @@ -349,7 +341,8 @@ ReturnValue_t Subsystem::addSequence(ArrayList *sequence, ReturnValue_t result; - //Before initialize() is called, tables must not be checked as the children are not added yet. + //Before initialize() is called, tables must not be checked as the + //children are not added yet. //Sequences added before are checked by initialize() if (!preInit) { result = checkSequence( @@ -374,7 +367,7 @@ ReturnValue_t Subsystem::addSequence(ArrayList *sequence, } if (inStore) { -#ifdef USE_MODESTORE +#if FSFW_USE_MODESTORE == 1 result = modeStore->storeArray(sequence, &(modeSequences.find(id)->entries.firstLinkedElement)); if (result != RETURN_OK) { @@ -395,8 +388,8 @@ ReturnValue_t Subsystem::addTable(ArrayList *table, Mode_t id, ReturnValue_t result; - //Before initialize() is called, tables must not be checked as the children are not added yet. - //Tables added before are checked by initialize() + //Before initialize() is called, tables must not be checked as the children + //are not added yet. Tables added before are checked by initialize() if (!preInit) { result = checkTable( HybridIterator(table->front(), table->back())); @@ -417,7 +410,7 @@ ReturnValue_t Subsystem::addTable(ArrayList *table, Mode_t id, } if (inStore) { -#ifdef USE_MODESTORE +#if FSFW_USE_MODESTORE == 1 result = modeStore->storeArray(table, &(modeTables.find(id)->firstLinkedElement)); if (result != RETURN_OK) { @@ -447,7 +440,7 @@ ReturnValue_t Subsystem::deleteSequence(Mode_t id) { return ACCESS_DENIED; } -#ifdef USE_MODESTORE +#if FSFW_USE_MODESTORE == 1 modeStore->deleteList(sequenceInfo->entries.firstLinkedElement); #endif modeSequences.erase(id); @@ -470,7 +463,7 @@ ReturnValue_t Subsystem::deleteTable(Mode_t id) { return ACCESS_DENIED; } -#ifdef USE_MODESTORE +#if FSFW_USE_MODESTORE == 1 modeStore->deleteList(pointer->firstLinkedElement); #endif modeSequences.erase(id); @@ -489,10 +482,10 @@ ReturnValue_t Subsystem::initialize() { return RETURN_FAILED; } -#ifdef USE_MODESTORE +#if FSFW_USE_MODESTORE == 1 modeStore = objectManager->get(objects::MODE_STORE); - if (modeStore == NULL) { + if (modeStore == nullptr) { return RETURN_FAILED; } #endif @@ -587,12 +580,14 @@ void Subsystem::transitionFailed(ReturnValue_t failureCode, triggerEvent(MODE_TRANSITION_FAILED, failureCode, parameter); if (mode == targetMode) { //already tried going back to the current mode - //go into fallback mode, also set current mode to fallback mode, so we come here at the next fail + //go into fallback mode, also set current mode to fallback mode, + //so we come here at the next fail modeHelper.setForced(true); ReturnValue_t result; if ((result = checkSequence(getFallbackSequence(mode))) != RETURN_OK) { triggerEvent(FALLBACK_FAILED, result, getFallbackSequence(mode)); - isInTransition = false; //keep still and allow arbitrary mode commands to recover + //keep still and allow arbitrary mode commands to recover + isInTransition = false; return; } mode = getFallbackSequence(mode); @@ -656,8 +651,10 @@ void Subsystem::cantKeepMode() { modeHelper.setForced(true); - //already set the mode, so that we do not try to go back in our old mode when the transition fails + //already set the mode, so that we do not try to go back in our old mode + //when the transition fails mode = getFallbackSequence(mode); - //SHOULDDO: We should store submodes for fallback sequence as well, otherwise we should get rid of submodes completely. + //SHOULDDO: We should store submodes for fallback sequence as well, + //otherwise we should get rid of submodes completely. startTransition(mode, SUBMODE_NONE); } diff --git a/subsystem/Subsystem.h b/subsystem/Subsystem.h index a40b8028d..69563643e 100644 --- a/subsystem/Subsystem.h +++ b/subsystem/Subsystem.h @@ -1,14 +1,21 @@ -#ifndef SUBSYSTEM_H_ -#define SUBSYSTEM_H_ +#ifndef FSFW_SUBSYSTEM_SUBSYSTEM_H_ +#define FSFW_SUBSYSTEM_SUBSYSTEM_H_ + +#include "SubsystemBase.h" +#include "modes/ModeDefinitions.h" #include "../container/FixedArrayList.h" #include "../container/FixedMap.h" #include "../container/HybridIterator.h" #include "../container/SinglyLinkedList.h" #include "../serialize/SerialArrayListAdapter.h" -#include "modes/ModeDefinitions.h" -#include "SubsystemBase.h" +#include + +/** + * @brief TODO: documentation missing + * @details + */ class Subsystem: public SubsystemBase, public HasModeSequenceIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SUBSYSTEM; @@ -30,8 +37,13 @@ public: static const ReturnValue_t TARGET_TABLE_NOT_REACHED = MAKE_RETURN_CODE(0xA1); static const ReturnValue_t TABLE_CHECK_FAILED = MAKE_RETURN_CODE(0xA2); - - + /** + * TODO: Doc for constructor + * @param setObjectId + * @param parent + * @param maxNumberOfSequences + * @param maxNumberOfTables + */ Subsystem(object_id_t setObjectId, object_id_t parent, uint32_t maxNumberOfSequences, uint32_t maxNumberOfTables); virtual ~Subsystem(); @@ -44,31 +56,12 @@ public: void setInitialMode(Mode_t mode); - virtual ReturnValue_t initialize(); + virtual ReturnValue_t initialize() override; - virtual ReturnValue_t checkObjectConnections(); + virtual ReturnValue_t checkObjectConnections() override; - virtual MessageQueueId_t getSequenceCommandQueue() const; + virtual MessageQueueId_t getSequenceCommandQueue() const override; - /** - * - * - * IMPORTANT: Do not call on non existing sequence! Use existsSequence() first - * - * @param sequence - * @return - */ - ReturnValue_t checkSequence(Mode_t sequence); - - /** - * - * - * IMPORTANT: Do not call on non existing sequence! Use existsSequence() first - * - * @param iter - * @return - */ - ReturnValue_t checkSequence(HybridIterator iter, Mode_t fallbackSequence); protected: struct EntryPointer { @@ -92,15 +85,15 @@ protected: bool childrenChangedHealth; - uint32_t uptimeStartTable; + uint32_t uptimeStartTable = 0; HybridIterator currentTargetTable; - Mode_t targetMode; + Mode_t targetMode = 0; Submode_t targetSubmode; - Mode_t initialMode; + Mode_t initialMode = 0; HybridIterator currentSequenceIterator; @@ -108,10 +101,10 @@ protected: FixedMap modeSequences; - StorageManagerIF *IPCStore; + StorageManagerIF *IPCStore = nullptr; -#ifdef USE_MODESTORE - ModeStoreIF *modeStore; +#if FSFW_USE_MODESTORE == 1 + ModeStoreIF *modeStore = nullptr; #endif bool existsModeSequence(Mode_t id); @@ -124,8 +117,6 @@ protected: HybridIterator getCurrentTable(); -// void startSequence(Mode_t sequence); - /** * DO NOT USE ON NON EXISTING SEQUENCE * @@ -153,12 +144,29 @@ protected: virtual void startTransition(Mode_t mode, Submode_t submode); - void sendSerializablesAsCommandMessage(Command_t command, SerializeIF **elements, uint8_t count); + void sendSerializablesAsCommandMessage(Command_t command, + SerializeIF **elements, uint8_t count); void transitionFailed(ReturnValue_t failureCode, uint32_t parameter); void cantKeepMode(); + /** + * @brief Checks whether a sequence, identified by a mode. + * @param sequence + * @return + */ + ReturnValue_t checkSequence(Mode_t sequence); + + /** + * @brief Checks whether a sequence, identified by a mode list iterator + * and a fallback sequence. Iterator needs to point to a valid + * sequence. + * @param iter + * @return + */ + ReturnValue_t checkSequence(HybridIterator iter, + Mode_t fallbackSequence); }; -#endif /* SUBSYSTEM_H_ */ +#endif /* FSFW_SUBSYSTEM_SUBSYSTEM_H_ */ diff --git a/subsystem/SubsystemBase.cpp b/subsystem/SubsystemBase.cpp index 56ae10628..f60c88478 100644 --- a/subsystem/SubsystemBase.cpp +++ b/subsystem/SubsystemBase.cpp @@ -1,15 +1,15 @@ #include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h" -#include "SubsystemBase.h" +#include "../subsystem/SubsystemBase.h" #include "../ipc/QueueFactory.h" SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t initialMode, uint16_t commandQueueDepth) : - SystemObject(setObjectId), mode(initialMode), submode(SUBMODE_NONE), childrenChangedMode( - false), commandsOutstanding(0), commandQueue(NULL), healthHelper(this, - setObjectId), modeHelper(this), parentId(parent) { - commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth, - CommandMessage::MAX_MESSAGE_SIZE); + SystemObject(setObjectId), mode(initialMode), submode(SUBMODE_NONE), + childrenChangedMode(false), + commandQueue(QueueFactory::instance()->createMessageQueue( + commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE)), + healthHelper(this, setObjectId), modeHelper(this), parentId(parent) { } SubsystemBase::~SubsystemBase() { @@ -21,10 +21,11 @@ ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) { ChildInfo info; HasModesIF *child = objectManager->get(objectId); - //This is a rather ugly hack to have the changedHealth info for all children available. (needed for FOGs). + // This is a rather ugly hack to have the changedHealth info for all + // children available. HasHealthIF* healthChild = objectManager->get(objectId); - if (child == NULL) { - if (healthChild == NULL) { + if (child == nullptr) { + if (healthChild == nullptr) { return CHILD_DOESNT_HAVE_MODES; } else { info.commandQueue = healthChild->getCommandQueue(); @@ -38,14 +39,11 @@ ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) { info.submode = SUBMODE_NONE; info.healthChanged = false; - std::pair::iterator, bool> returnValue = - childrenMap.insert( - std::pair(objectId, info)); - if (!(returnValue.second)) { + auto resultPair = childrenMap.emplace(objectId, info); + if (not resultPair.second) { return COULD_NOT_INSERT_CHILD; - } else { - return RETURN_OK; } + return RETURN_OK; } ReturnValue_t SubsystemBase::checkStateAgainstTable( @@ -76,15 +74,15 @@ ReturnValue_t SubsystemBase::checkStateAgainstTable( return RETURN_OK; } -void SubsystemBase::executeTable(HybridIterator tableIter, Submode_t targetSubmode) { - - CommandMessage message; +void SubsystemBase::executeTable(HybridIterator tableIter, + Submode_t targetSubmode) { + CommandMessage command; std::map::iterator iter; commandsOutstanding = 0; - for (; tableIter.value != NULL; ++tableIter) { + for (; tableIter.value != nullptr; ++tableIter) { object_id_t object = tableIter.value->getObject(); if ((iter = childrenMap.find(object)) == childrenMap.end()) { //illegal table entry, should only happen due to misconfigured mode table @@ -100,17 +98,17 @@ void SubsystemBase::executeTable(HybridIterator tableIter, Submod if (healthHelper.healthTable->hasHealth(object)) { if (healthHelper.healthTable->isFaulty(object)) { - ModeMessage::setModeMessage(&message, + ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND, HasModesIF::MODE_OFF, SUBMODE_NONE); } else { if (modeHelper.isForced()) { - ModeMessage::setModeMessage(&message, + ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND_FORCED, tableIter.value->getMode(), submodeToCommand); } else { if (healthHelper.healthTable->isCommandable(object)) { - ModeMessage::setModeMessage(&message, + ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND, tableIter.value->getMode(), submodeToCommand); } else { @@ -119,17 +117,17 @@ void SubsystemBase::executeTable(HybridIterator tableIter, Submod } } } else { - ModeMessage::setModeMessage(&message, ModeMessage::CMD_MODE_COMMAND, + ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND, tableIter.value->getMode(), submodeToCommand); } - if ((iter->second.mode == ModeMessage::getMode(&message)) - && (iter->second.submode == ModeMessage::getSubmode(&message)) + if ((iter->second.mode == ModeMessage::getMode(&command)) + && (iter->second.submode == ModeMessage::getSubmode(&command)) && !modeHelper.isForced()) { continue; //don't send redundant mode commands (produces event spam), but still command if mode is forced to reach lower levels } ReturnValue_t result = commandQueue->sendMessage( - iter->second.commandQueue, &message); + iter->second.commandQueue, &command); if (result == RETURN_OK) { ++commandsOutstanding; } @@ -306,31 +304,31 @@ void SubsystemBase::announceMode(bool recursive) { void SubsystemBase::checkCommandQueue() { ReturnValue_t result; - CommandMessage message; + CommandMessage command; - for (result = commandQueue->receiveMessage(&message); result == RETURN_OK; - result = commandQueue->receiveMessage(&message)) { + for (result = commandQueue->receiveMessage(&command); result == RETURN_OK; + result = commandQueue->receiveMessage(&command)) { - result = healthHelper.handleHealthCommand(&message); + result = healthHelper.handleHealthCommand(&command); if (result == RETURN_OK) { continue; } - result = modeHelper.handleModeCommand(&message); + result = modeHelper.handleModeCommand(&command); if (result == RETURN_OK) { continue; } - result = handleModeReply(&message); + result = handleModeReply(&command); if (result == RETURN_OK) { continue; } - result = handleCommandMessage(&message); + result = handleCommandMessage(&command); if (result != RETURN_OK) { CommandMessage reply; reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, - message.getCommand()); + command.getCommand()); replyToCommand(&reply); } } diff --git a/subsystem/SubsystemBase.h b/subsystem/SubsystemBase.h index 61a7eaef1..b8e4f9029 100644 --- a/subsystem/SubsystemBase.h +++ b/subsystem/SubsystemBase.h @@ -1,5 +1,7 @@ -#ifndef SUBSYSTEMBASE_H_ -#define SUBSYSTEMBASE_H_ +#ifndef FSFW_SUBSYSTEM_SUBSYSTEMBASE_H_ +#define FSFW_SUBSYSTEM_SUBSYSTEMBASE_H_ + +#include "modes/HasModeSequenceIF.h" #include "../container/HybridIterator.h" #include "../health/HasHealthIF.h" @@ -7,11 +9,14 @@ #include "../modes/HasModesIF.h" #include "../objectmanager/SystemObject.h" #include "../returnvalues/HasReturnvaluesIF.h" -#include "modes/HasModeSequenceIF.h" #include "../tasks/ExecutableObjectIF.h" #include "../ipc/MessageQueueIF.h" #include +/** + * @defgroup subsystems Subsystem Objects + * Contains all Subsystem and Assemblies + */ class SubsystemBase: public SystemObject, public HasModesIF, public HasHealthIF, @@ -30,17 +35,17 @@ public: Mode_t initialMode = 0, uint16_t commandQueueDepth = 8); virtual ~SubsystemBase(); - virtual MessageQueueId_t getCommandQueue() const; + virtual MessageQueueId_t getCommandQueue() const override; ReturnValue_t registerChild(object_id_t objectId); - virtual ReturnValue_t initialize(); + virtual ReturnValue_t initialize() override; - virtual ReturnValue_t performOperation(uint8_t opCode); + virtual ReturnValue_t performOperation(uint8_t opCode) override; - virtual ReturnValue_t setHealth(HealthState health); + virtual ReturnValue_t setHealth(HealthState health) override; - virtual HasHealthIF::HealthState getHealth(); + virtual HasHealthIF::HealthState getHealth() override; protected: struct ChildInfo { @@ -58,9 +63,9 @@ protected: /** * Always check this against <=0, so you are robust against too many replies */ - int32_t commandsOutstanding; + int32_t commandsOutstanding = 0; - MessageQueueIF* commandQueue; + MessageQueueIF* commandQueue = nullptr; HealthHelper healthHelper; @@ -122,4 +127,4 @@ protected: virtual void modeChanged(); }; -#endif /* SUBSYSTEMBASE_H_ */ +#endif /* FSFW_SUBSYSTEM_SUBSYSTEMBASE_H_ */ diff --git a/subsystem/modes/CMakeLists.txt b/subsystem/modes/CMakeLists.txt new file mode 100644 index 000000000..6ac6a293a --- /dev/null +++ b/subsystem/modes/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + ModeSequenceMessage.cpp + ModeStore.cpp +) diff --git a/subsystem/modes/ModeDefinitions.h b/subsystem/modes/ModeDefinitions.h index a865ab0cf..13a780ee0 100644 --- a/subsystem/modes/ModeDefinitions.h +++ b/subsystem/modes/ModeDefinitions.h @@ -1,22 +1,19 @@ -#ifndef MODEDEFINITIONS_H_ -#define MODEDEFINITIONS_H_ +#ifndef FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_ +#define FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_ #include "../../modes/HasModesIF.h" #include "../../objectmanager/SystemObjectIF.h" #include "../../serialize/SerializeIF.h" #include "../../serialize/SerialLinkedListAdapter.h" + class ModeListEntry: public SerializeIF, public LinkedElement { public: - ModeListEntry() : - LinkedElement(this), value1(0), value2(0), value3(0), value4( - 0) { + ModeListEntry(): LinkedElement(this) {} - } - - uint32_t value1; - uint32_t value2; - uint8_t value3; - uint8_t value4; + uint32_t value1 = 0; + uint32_t value2 = 0; + uint8_t value3 = 0; + uint8_t value4 = 0; virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const { @@ -149,4 +146,4 @@ public: } }; -#endif //MODEDEFINITIONS_H_ +#endif /* FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_ */ diff --git a/subsystem/modes/ModeSequenceMessage.cpp b/subsystem/modes/ModeSequenceMessage.cpp index 33019f58f..7733098e3 100644 --- a/subsystem/modes/ModeSequenceMessage.cpp +++ b/subsystem/modes/ModeSequenceMessage.cpp @@ -1,8 +1,7 @@ -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../objectmanager/ObjectManagerIF.h" +#include "ModeSequenceMessage.h" + #include "../../objectmanager/ObjectManagerIF.h" #include "../../storagemanager/StorageManagerIF.h" -#include "ModeSequenceMessage.h" void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, Command_t command, Mode_t sequence, store_address_t storeAddress) { @@ -11,25 +10,12 @@ void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, message->setParameter2(sequence); } -//void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, -// Command_t command, ModeTableId_t table, store_address_t storeAddress) { -// message->setCommand(command); -// message->setParameter(storeAddress.raw); -// message->setParameter2(table); -//} - void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, Command_t command, Mode_t sequence) { message->setCommand(command); message->setParameter2(sequence); } -//void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, -// Command_t command, ModeTableId_t table) { -// message->setCommand(command); -// message->setParameter2(table); -//} - void ModeSequenceMessage::setModeSequenceMessage(CommandMessage* message, Command_t command, store_address_t storeAddress) { message->setCommand(command); @@ -63,9 +49,10 @@ void ModeSequenceMessage::clear(CommandMessage *message) { case SEQUENCE_LIST: case TABLE_LIST: case TABLE: - case SEQUENCE:{ - StorageManagerIF *ipcStore = objectManager->get(objects::IPC_STORE); - if (ipcStore != NULL){ + case SEQUENCE: { + StorageManagerIF *ipcStore = objectManager->get( + objects::IPC_STORE); + if (ipcStore != nullptr){ ipcStore->deleteData(ModeSequenceMessage::getStoreAddress(message)); } } diff --git a/subsystem/modes/ModeSequenceMessage.h b/subsystem/modes/ModeSequenceMessage.h index bbf747f14..7852c9848 100644 --- a/subsystem/modes/ModeSequenceMessage.h +++ b/subsystem/modes/ModeSequenceMessage.h @@ -1,9 +1,11 @@ -#ifndef MODESEQUENCEMESSAGE_H_ -#define MODESEQUENCEMESSAGE_H_ +#ifndef FSFW_SUBSYSTEM_MODES_MODESEQUENCEMESSAGE_H_ +#define FSFW_SUBSYSTEM_MODES_MODESEQUENCEMESSAGE_H_ + +#include "ModeDefinitions.h" #include "../../ipc/CommandMessage.h" #include "../../storagemanager/StorageManagerIF.h" -#include "ModeDefinitions.h" + class ModeSequenceMessage { public: @@ -45,4 +47,4 @@ private: ModeSequenceMessage(); }; -#endif /* MODESEQUENCEMESSAGE_H_ */ +#endif /* FSFW_SUBSYSTEM_MODES_MODESEQUENCEMESSAGE_H_ */ diff --git a/subsystem/modes/ModeStore.cpp b/subsystem/modes/ModeStore.cpp index 217e177c8..e216a167a 100644 --- a/subsystem/modes/ModeStore.cpp +++ b/subsystem/modes/ModeStore.cpp @@ -1,6 +1,8 @@ #include "ModeStore.h" -#ifdef USE_MODESTORE +// todo: I think some parts are deprecated. If this is used, the define +// USE_MODESTORE could be part of the new FSFWConfig.h file. +#if FSFW_USE_MODESTORE == 1 ModeStore::ModeStore(object_id_t objectId, uint32_t slots) : SystemObject(objectId), store(slots), emptySlot(store.front()) { diff --git a/subsystem/modes/ModeStore.h b/subsystem/modes/ModeStore.h index 0bf856a3e..a5cb4059c 100644 --- a/subsystem/modes/ModeStore.h +++ b/subsystem/modes/ModeStore.h @@ -1,12 +1,15 @@ -#ifndef MODESTORE_H_ -#define MODESTORE_H_ +#ifndef FSFW_SUBSYSTEM_MODES_MODESTORE_H_ +#define FSFW_SUBSYSTEM_MODES_MODESTORE_H_ -#ifdef USE_MODESTORE +#include + +#if FSFW_USE_MODESTORE == 1 + +#include "ModeStoreIF.h" #include "../../container/ArrayList.h" #include "../../container/SinglyLinkedList.h" #include "../../objectmanager/SystemObject.h" -#include "ModeStoreIF.h" class ModeStore: public ModeStoreIF, public SystemObject { public: @@ -41,5 +44,5 @@ private: #endif -#endif /* MODESTORE_H_ */ +#endif /* FSFW_SUBSYSTEM_MODES_MODESTORE_H_ */ diff --git a/subsystem/modes/ModeStoreIF.h b/subsystem/modes/ModeStoreIF.h index e5cac3b2e..9682501d6 100644 --- a/subsystem/modes/ModeStoreIF.h +++ b/subsystem/modes/ModeStoreIF.h @@ -1,12 +1,15 @@ #ifndef MODESTOREIF_H_ #define MODESTOREIF_H_ -#ifdef USE_MODESTORE +#include + +#if FSFW_USE_MODESTORE == 1 + +#include "ModeDefinitions.h" #include "../../container/ArrayList.h" #include "../../container/SinglyLinkedList.h" #include "../../returnvalues/HasReturnvaluesIF.h" -#include "ModeDefinitions.h" class ModeStoreIF { public: diff --git a/tasks/CMakeLists.txt b/tasks/CMakeLists.txt new file mode 100644 index 000000000..1964bb4e6 --- /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/tasks/FixedTimeslotTaskIF.h b/tasks/FixedTimeslotTaskIF.h index 421978f0d..2fc7e0922 100644 --- a/tasks/FixedTimeslotTaskIF.h +++ b/tasks/FixedTimeslotTaskIF.h @@ -1,16 +1,32 @@ #ifndef FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ #define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ -#include "../objectmanager/ObjectManagerIF.h" #include "PeriodicTaskIF.h" +#include "../objectmanager/ObjectManagerIF.h" /** - * Following the same principle as the base class IF. This is the interface for a Fixed timeslot task + * @brief Following the same principle as the base class IF. + * This is the interface for a Fixed timeslot task */ class FixedTimeslotTaskIF : public PeriodicTaskIF { public: virtual ~FixedTimeslotTaskIF() {} - virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) = 0; + + /** + * Add an object with a slot time and the execution step to the task. + * The execution step will be passed to the object (e.g. as an operation + * code in #performOperation) + * @param componentId + * @param slotTimeMs + * @param executionStep + * @return + */ + virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, + int8_t executionStep) = 0; + /** + * Check whether the sequence is valid and perform all other required + * initialization steps which are needed after task creation + */ virtual ReturnValue_t checkSequence() const = 0; }; diff --git a/tasks/TaskFactory.h b/tasks/TaskFactory.h index cbf2272c3..85cdda900 100644 --- a/tasks/TaskFactory.h +++ b/tasks/TaskFactory.h @@ -1,10 +1,11 @@ -#ifndef FRAMEWORK_TASKS_TASKFACTORY_H_ -#define FRAMEWORK_TASKS_TASKFACTORY_H_ +#ifndef FSFW_TASKS_TASKFACTORY_H_ +#define FSFW_TASKS_TASKFACTORY_H_ -#include #include "FixedTimeslotTaskIF.h" #include "Typedef.h" +#include + /** * Singleton Class that produces Tasks. */ @@ -48,10 +49,11 @@ public: /** * Function to be called to delete a task - * @param task The pointer to the task that shall be deleted, NULL specifies current Task + * @param task The pointer to the task that shall be deleted, + * nullptr specifies current Task * @return Success of deletion */ - static ReturnValue_t deleteTask(PeriodicTaskIF* task = NULL); + static ReturnValue_t deleteTask(PeriodicTaskIF* task = nullptr); /** * Function to be called to delay current task @@ -69,4 +71,4 @@ private: }; -#endif /* FRAMEWORK_TASKS_TASKFACTORY_H_ */ +#endif /* FSFW_TASKS_TASKFACTORY_H_ */ diff --git a/tcdistribution/CMakeLists.txt b/tcdistribution/CMakeLists.txt new file mode 100644 index 000000000..17dc186c3 --- /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 45ebe4a2a..40b305af9 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 eaca48fba..a1153314e 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, diff --git a/thermal/AcceptsThermalMessagesIF.h b/thermal/AcceptsThermalMessagesIF.h new file mode 100644 index 000000000..5fbd6bb38 --- /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 000000000..ad5327214 --- /dev/null +++ b/thermal/CMakeLists.txt @@ -0,0 +1,10 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + AbstractTemperatureSensor.cpp + Heater.cpp + RedundantHeater.cpp + ThermalComponentCore.cpp + ThermalComponent.cpp + ThermalModule.cpp + ThermalMonitorReporter.cpp +) diff --git a/thermal/CoreComponent.h b/thermal/CoreComponent.h deleted file mode 100644 index 8093711d6..000000000 --- a/thermal/CoreComponent.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ -#define MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ - -#include "../datapoolglob/GlobalDataSet.h" -#include "../datapoolglob/GlobalPoolVariable.h" -#include "../thermal/ThermalComponentIF.h" -#include "../thermal/AbstractTemperatureSensor.h" -#include "../thermal/ThermalModule.h" -#include "../thermal/ThermalMonitor.h" - -// TODO: Documentaiton, how to use this? only use Thermal Component, which inherits core component? -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, GlobDataSet *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; - - gp_float_t temperature; - gp_int8_t targetState; - gp_int8_t currentState; - gp_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 1301e2e01..ce965d5ea 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/RedundantHeater.h b/thermal/RedundantHeater.h index ab745a698..765375420 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 356ca7220..f41b3761b 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 50786654b..084201dd4 100644 --- a/thermal/ThermalComponent.cpp +++ b/thermal/ThermalComponent.cpp @@ -1,20 +1,20 @@ #include "ThermalComponent.h" ThermalComponent::ThermalComponent(object_id_t reportingObjectId, - uint8_t domainId, uint32_t temperaturePoolId, - uint32_t targetStatePoolId, uint32_t currentStatePoolId, - uint32_t requestPoolId, GlobDataSet* 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), + { parameters.lowerOpLimit, parameters.upperOpLimit, + parameters.heaterOn, parameters.hysteresis, + parameters.heaterSwitchoff }, + ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL), nopParameters({ parameters.lowerNopLimit, parameters.upperNopLimit }) { } @@ -22,22 +22,22 @@ ThermalComponent::~ThermalComponent() { } ReturnValue_t ThermalComponent::setTargetState(int8_t newState) { - GlobDataSet mySet; - gp_int8_t 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, size_t size) { @@ -57,11 +57,11 @@ ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, size_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) { @@ -78,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; @@ -142,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) { @@ -162,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 195f03b10..0785a9141 100644 --- a/thermal/ThermalComponent.h +++ b/thermal/ThermalComponent.h @@ -1,12 +1,14 @@ -#ifndef THERMALCOMPONENT_H_ -#define THERMALCOMPONENT_H_ +#ifndef FSFW_THERMAL_THERMALCOMPONENT_H_ +#define FSFW_THERMAL_THERMALCOMPONENT_H_ -#include "CoreComponent.h" +#include "ThermalComponentCore.h" /** - * What is it. How to use + * @brief + * @details + * Some more documentation. */ -class ThermalComponent: public CoreComponent { +class ThermalComponent: public ThermalComponentCore { public: struct Parameters { float lowerNopLimit; @@ -42,9 +44,10 @@ public: * @param parameters * @param priority */ - ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, - uint32_t targetStatePoolId, uint32_t currentStatePoolId, uint32_t requestPoolId, - GlobDataSet *dataSet, AbstractTemperatureSensor *sensor, + 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, @@ -63,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 50% rename from thermal/CoreComponent.cpp rename to thermal/ThermalComponentCore.cpp index 657e79cb0..ba8750532 100644 --- a/thermal/CoreComponent.cpp +++ b/thermal/ThermalComponentCore.cpp @@ -1,50 +1,74 @@ -#include "CoreComponent.h" +#include "ThermalComponentCore.h" +#include "tcsDefinitions.h" -CoreComponent::CoreComponent(object_id_t reportingObjectId, uint8_t domainId, - uint32_t temperaturePoolId, uint32_t targetStatePoolId, - uint32_t currentStatePoolId, uint32_t requestPoolId, GlobDataSet* 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, - GlobalDataPool::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. - GlobDataSet mySet; - gp_uint8_t 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 != thermal::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,43 +81,46 @@ 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) { - GlobDataSet mySet; - gp_uint8_t 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() { - temperature = INVALID_TEMPERATURE; +void ThermalComponentCore::setOutputInvalid() { + temperature = thermal::INVALID_TEMPERATURE; temperature.setValid(PoolVariableIF::INVALID); currentState.setValid(PoolVariableIF::INVALID); heaterRequest = HEATER_DONT_CARE; @@ -101,32 +128,34 @@ 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) { + if (temperature != thermal::INVALID_TEMPERATURE) { return temperature; } else { - return INVALID_TEMPERATURE; + return thermal::INVALID_TEMPERATURE; } } else { - return INVALID_TEMPERATURE; + return thermal::INVALID_TEMPERATURE; } } -ThermalComponentIF::State CoreComponent::getState(float temperature, +ThermalComponentIF::State ThermalComponentCore::getState(float temperature, Parameters parameters, int8_t targetState) { ThermalComponentIF::State state; @@ -144,14 +173,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 +206,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 +226,27 @@ ThermalComponentIF::State CoreComponent::getIgnoredState(int8_t state) { } } -void CoreComponent::updateMinMaxTemp() { - if (temperature == INVALID_TEMPERATURE) { +void ThermalComponentCore::updateMinMaxTemp() { + if (temperature == thermal::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 +280,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 000000000..da9424e68 --- /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 e542c8420..89c2b2d0e 100644 --- a/thermal/ThermalComponentIF.h +++ b/thermal/ThermalComponentIF.h @@ -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 fbd6939e7..de3475429 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, - GlobDataSet *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, GlobDataSet* 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,15 +98,16 @@ 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; + moduleTemperature.value = thermal::INVALID_TEMPERATURE; moduleTemperature.setValid(PoolVariableIF::INVALID); } } @@ -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; @@ -213,7 +219,7 @@ void ThermalModule::initialize(PowerSwitchIF* powerSwitch) { bool ThermalModule::calculateModuleHeaterRequestAndSetModuleStatus( Strategy strategy) { currentState.setValid(PoolVariableIF::VALID); - if (moduleTemperature == INVALID_TEMPERATURE) { + if (moduleTemperature == thermal::INVALID_TEMPERATURE) { currentState = UNKNOWN; return false; } @@ -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) { - GlobDataSet mySet; - gp_int8_t 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, @@ -275,7 +282,7 @@ void ThermalModule::updateTargetTemperatures(ThermalComponentIF* component, } void ThermalModule::setOutputInvalid() { - moduleTemperature = INVALID_TEMPERATURE; + moduleTemperature = thermal::INVALID_TEMPERATURE; moduleTemperature.setValid(PoolVariableIF::INVALID); currentState.setValid(PoolVariableIF::INVALID); std::list::iterator iter = components.begin(); diff --git a/thermal/ThermalModule.h b/thermal/ThermalModule.h index 41be6baae..0abe51c7e 100644 --- a/thermal/ThermalModule.h +++ b/thermal/ThermalModule.h @@ -1,14 +1,18 @@ -#ifndef THERMALMODULE_H_ -#define THERMALMODULE_H_ +#ifndef FSFW_THERMAL_THERMALMODULE_H_ +#define FSFW_THERMAL_THERMALMODULE_H_ -#include "../datapoolglob/GlobalDataSet.h" -#include "../datapoolglob/GlobalPoolVariable.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; /** @@ -22,11 +26,12 @@ public: float hysteresis; }; - ThermalModule(uint32_t moduleTemperaturePoolId, uint32_t currentStatePoolId, - uint32_t targetStatePoolId, GlobDataSet *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, GlobDataSet *dataSet); + ThermalModule(gp_id_t moduleTemperaturePoolId, + LocalPoolDataSetBase *dataSet); virtual ~ThermalModule(); @@ -62,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; - gp_float_t moduleTemperature; + lp_var_t moduleTemperature; - RedundantHeater *heater; + RedundantHeater *heater = nullptr; - gp_int8_t currentState; - gp_int8_t targetState; + lp_var_t currentState; + lp_var_t targetState; std::list sensors; std::list components; @@ -92,4 +97,4 @@ protected: void updateTargetTemperatures(ThermalComponentIF *component, bool isSafe); }; -#endif /* THERMALMODULE_H_ */ +#endif /* FSFW_THERMAL_THERMALMODULE_H_ */ diff --git a/thermal/ThermalModuleIF.h b/thermal/ThermalModuleIF.h index 2d11a6f25..89cf93d69 100644 --- a/thermal/ThermalModuleIF.h +++ b/thermal/ThermalModuleIF.h @@ -2,6 +2,7 @@ #define THERMALMODULEIF_H_ #include "ThermalComponentIF.h" + class AbstractTemperatureSensor; class ThermalModuleIF{ @@ -18,8 +19,6 @@ public: NON_OPERATIONAL = 0, OPERATIONAL = 1, UNKNOWN = 2 }; - static constexpr float INVALID_TEMPERATURE = 999; - virtual ~ThermalModuleIF() { } diff --git a/thermal/ThermalMonitor.h b/thermal/ThermalMonitor.h deleted file mode 100644 index 5c6806c1d..000000000 --- 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 11abfbe54..cefc61107 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 000000000..4fb68a991 --- /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 ad258ced7..3225be5c3 100644 --- a/thermal/tcsDefinitions.h +++ b/thermal/tcsDefinitions.h @@ -1,8 +1,8 @@ #ifndef TCSDEFINITIONS_H_ #define TCSDEFINITIONS_H_ - -static const uint32_t INVALID_TEMPERATURE = 999; - +namespace thermal { +static constexpr float INVALID_TEMPERATURE = 999; +} #endif /* TCSDEFINITIONS_H_ */ diff --git a/timemanager/CMakeLists.txt b/timemanager/CMakeLists.txt new file mode 100644 index 000000000..3367775f4 --- /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 bc1123880..fcc602a2d 100644 --- a/timemanager/Clock.h +++ b/timemanager/Clock.h @@ -1,12 +1,17 @@ -#ifndef FRAMEWORK_TIMEMANAGER_CLOCK_H_ -#define FRAMEWORK_TIMEMANAGER_CLOCK_H_ +#ifndef FSFW_TIMEMANAGER_CLOCK_H_ +#define FSFW_TIMEMANAGER_CLOCK_H_ #include "../returnvalues/HasReturnvaluesIF.h" #include "../ipc/MutexHelper.h" #include "../globalfunctions/timevalOperations.h" #include + +#ifdef WIN32 +#include +#else #include +#endif //! Don't use these for time points, type is not large enough for UNIX epoch. using dur_millis_t = uint32_t; @@ -151,4 +156,4 @@ private: }; -#endif /* FRAMEWORK_TIMEMANAGER_CLOCK_H_ */ +#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */ diff --git a/tmstorage/CMakeLists.txt b/tmstorage/CMakeLists.txt new file mode 100644 index 000000000..7990d85a1 --- /dev/null +++ b/tmstorage/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + TmStoreMessage.cpp +) diff --git a/tmtcpacket/CMakeLists.txt b/tmtcpacket/CMakeLists.txt new file mode 100644 index 000000000..fe3d2a4d2 --- /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 000000000..e9a8d03bb --- /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 a45796576..ac72b3e77 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 86fb087ed..54fc856c7 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 000000000..fcfc82d2c --- /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 000000000..c30af214f --- /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/CatchFactory.cpp b/unittest/core/CatchFactory.cpp new file mode 100644 index 000000000..3177212f4 --- /dev/null +++ b/unittest/core/CatchFactory.cpp @@ -0,0 +1,56 @@ +#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); + + { + PoolManager::LocalPoolConfig poolCfg = { + {100, 16}, {50, 32}, {25, 64} , {15, 128}, {5, 1024} + }; + new PoolManager(objects::TC_STORE, poolCfg); + } + + { + PoolManager::LocalPoolConfig poolCfg = { + {100, 16}, {50, 32}, {25, 64} , {15, 128}, {5, 1024} + }; + new PoolManager(objects::TM_STORE, poolCfg); + } + + { + PoolManager::LocalPoolConfig poolCfg = { + {100, 16}, {50, 32}, {25, 64} , {15, 128}, {5, 1024} + }; + new PoolManager(objects::IPC_STORE, poolCfg); + } + +} + +void Factory::setStaticFrameworkObjectIds() { + +} + + diff --git a/unittest/testcfg/CatchFactory.h b/unittest/core/CatchFactory.h similarity index 71% rename from unittest/testcfg/CatchFactory.h rename to unittest/core/CatchFactory.h index 84f9207e2..f06e7ae55 100644 --- a/unittest/testcfg/CatchFactory.h +++ b/unittest/core/CatchFactory.h @@ -1,5 +1,5 @@ -#ifndef FACTORY_H_ -#define FACTORY_H_ +#ifndef FSFW_CATCHFACTORY_H_ +#define FSFW_CATCHFACTORY_H_ #include @@ -13,4 +13,4 @@ namespace Factory { } -#endif /* FACTORY_H_ */ +#endif /* FSFW_CATCHFACTORY_H_ */ diff --git a/unittest/core/CatchSetup.cpp b/unittest/core/CatchSetup.cpp index cb5bd33ed..c93cf0323 100644 --- a/unittest/core/CatchSetup.cpp +++ b/unittest/core/CatchSetup.cpp @@ -1,6 +1,5 @@ +#include #include "CatchDefinitions.h" -#include "CatchFactory.h" - #include #ifdef GCOV @@ -10,15 +9,11 @@ #include "../../objectmanager/ObjectManager.h" #include "../../objectmanager/ObjectManagerIF.h" #include "../../storagemanager/StorageManagerIF.h" -#include "../../datapool/DataPool.h" #include "../../serviceinterface/ServiceInterfaceStream.h" /* Global instantiations normally done in main.cpp */ /* Initialize Data Pool */ -//namespace glob { -DataPool dataPool(datapool::dataPoolInit); -//} namespace sif { diff --git a/unittest/internal/osal/IntTestMq.cpp b/unittest/internal/osal/IntTestMq.cpp index 8d95f51ed..9917285f5 100644 --- a/unittest/internal/osal/IntTestMq.cpp +++ b/unittest/internal/osal/IntTestMq.cpp @@ -1,8 +1,8 @@ #include "IntTestMq.h" #include "../UnittDefinitions.h" -#include "../../ipc/MessageQueueIF.h" -#include "../../ipc/QueueFactory.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 015813470..d2f8b9628 100644 --- a/unittest/internal/osal/IntTestMutex.cpp +++ b/unittest/internal/osal/IntTestMutex.cpp @@ -1,6 +1,6 @@ #include "IntTestMutex.h" -#include "../../ipc/MutexFactory.h" +#include "../../../ipc/MutexFactory.h" #include "../UnittDefinitions.h" #if defined(hosted) diff --git a/unittest/internal/osal/IntTestSemaphore.cpp b/unittest/internal/osal/IntTestSemaphore.cpp index f260b6a51..6d2719d57 100644 --- a/unittest/internal/osal/IntTestSemaphore.cpp +++ b/unittest/internal/osal/IntTestSemaphore.cpp @@ -1,9 +1,9 @@ #include "IntTestSemaphore.h" #include "../UnittDefinitions.h" -#include "../../tasks/SemaphoreFactory.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" -#include "../../timemanager/Stopwatch.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 1e33ff335..793661c5b 100644 --- a/unittest/internal/serialize/IntTestSerialization.cpp +++ b/unittest/internal/serialize/IntTestSerialization.cpp @@ -1,8 +1,9 @@ #include "IntTestSerialization.h" #include "../UnittDefinitions.h" -#include "../../serialize/SerializeElement.h" -#include "../../serialize/SerialBufferAdapter.h" -#include "../../serialize/SerializeIF.h" + +#include "../../../serialize/SerializeElement.h" +#include "../../../serialize/SerialBufferAdapter.h" +#include "../../../serialize/SerializeIF.h" #include diff --git a/unittest/internal/serialize/IntTestSerialization.h b/unittest/internal/serialize/IntTestSerialization.h index e8dbd35a0..8706e0572 100644 --- a/unittest/internal/serialize/IntTestSerialization.h +++ b/unittest/internal/serialize/IntTestSerialization.h @@ -1,7 +1,7 @@ #ifndef FSFW_UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ #define FSFW_UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ -#include "../../returnvalues/HasReturnvaluesIF.h" +#include "../../../returnvalues/HasReturnvaluesIF.h" #include namespace testserialize { diff --git a/unittest/testcfg/CatchFactory.cpp b/unittest/testcfg/CatchFactory.cpp deleted file mode 100644 index c74a8126d..000000000 --- a/unittest/testcfg/CatchFactory.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#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/FSFWConfig.h b/unittest/testcfg/FSFWConfig.h index 4fb224c15..6b0def902 100644 --- a/unittest/testcfg/FSFWConfig.h +++ b/unittest/testcfg/FSFWConfig.h @@ -1,46 +1,55 @@ #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 - -//! Defines the FIFO depth of each commanding service base which -//! also determines how many commands a CSB service can handle in one cycle -//! simulataneously. This will increase the required RAM for -//! each CSB service ! -#define FSFW_CSB_FIFO_DEPTH 6 +//! Can be used to enable additional debugging printouts for developing the FSFW +#define FSFW_PRINT_VERBOSITY_LEVEL 0 //! If FSFW_OBJ_EVENT_TRANSLATION is set to one, //! additional output which requires the translation files translateObjects //! and translateEvents (and their compiled source files) #define FSFW_OBJ_EVENT_TRANSLATION 0 -//! If -DDEBUG is supplied in the build defines, there will be -//! additional output which requires the translation files translateObjects -//! and translateEvents (and their compiles source files) #if FSFW_OBJ_EVENT_TRANSLATION == 1 -#define FSFW_DEBUG_OUTPUT 1 //! Specify whether info events are printed too. #define FSFW_DEBUG_INFO 1 -#include -#include +#include "objects/translateObjects.h" +#include "events/translateEvents.h" #else -#define FSFW_DEBUG_OUTPUT 0 #endif //! 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 +//! short timestamp. +static constexpr uint8_t FSFW_MISSION_TIMESTAMP_SIZE = 8; + +//! 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; + +//! Defines the FIFO depth of each commanding service base which +//! also determines how many commands a CSB service can handle in one cycle +//! simulataneously. This will increase the required RAM for +//! each CSB service ! +static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 3; +} #endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/unittest/testcfg/Makefile-FSFW-Tests b/unittest/testcfg/Makefile-FSFW-Tests index 2017d2bd8..550fd1dee 100644 --- a/unittest/testcfg/Makefile-FSFW-Tests +++ b/unittest/testcfg/Makefile-FSFW-Tests @@ -15,7 +15,7 @@ SHELL = /bin/sh # (can be overriden by adding CHIP=chip and BOARD=board to the command-line) # Unit Test can only be run on host machine for now (Linux) FRAMEWORK_PATH = fsfw -FILE_ROOT = $(FRAMEWORK_PATH)/unittest +TEST_FILE_ROOT = $(FRAMEWORK_PATH)/unittest BOARD = unittest LINUX = 1 OS_FSFW = linux @@ -58,9 +58,10 @@ endif UNIT_TEST = 1 # General folder paths -CONFIG_PATH = $(FILE_ROOT)/config -UNIT_TEST_PATH = $(FILE_ROOT)/tests -CORE_PATH = $(FILE_ROOT)/core +CONFIG_PATH = testcfg +# Core copy has to be copied as well. +CORE_PATH = core +UNIT_TEST_PATH = $(TEST_FILE_ROOT)/tests # Output file basename BASENAME = fsfw @@ -154,8 +155,8 @@ include $(S)/$(notdir $S).mk endef $(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE))) -INCLUDES += $(FILE_ROOT) -INCLUDES += $(FILE_ROOT)/catch2/ +INCLUDES += $(TEST_FILE_ROOT) +INCLUDES += $(TEST_FILE_ROOT)/catch2/ #------------------------------------------------------------------------------- # Source Files diff --git a/unittest/testcfg/testcfg.mk b/unittest/testcfg/testcfg.mk index 31d3b60a5..fca2f7327 100644 --- a/unittest/testcfg/testcfg.mk +++ b/unittest/testcfg/testcfg.mk @@ -6,11 +6,3 @@ CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp) CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp) INCLUDES += $(CURRENTPATH) -INCLUDES += $(CURRENTPATH)/objects -INCLUDES += $(CURRENTPATH)/ipc -INCLUDES += $(CURRENTPATH)/pollingsequence -INCLUDES += $(CURRENTPATH)/returnvalues -INCLUDES += $(CURRENTPATH)/tmtc -INCLUDES += $(CURRENTPATH)/events -INCLUDES += $(CURRENTPATH)/devices -INCLUDES += $(CURRENTPATH)/cdatapool diff --git a/unittest/tests/storagemanager/TestPool.cpp b/unittest/tests/storagemanager/TestPool.cpp index f278c40c7..daeb6bb52 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); +}