diff --git a/datapool/ControllerSet.h b/datapool/ControllerSet.h deleted file mode 100644 index e27debff..00000000 --- a/datapool/ControllerSet.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef CONTROLLERSET_H_ -#define CONTROLLERSET_H_ - -#include "DataSet.h" - -class ControllerSet :public DataSet { -public: - ControllerSet(); - virtual ~ControllerSet(); - - virtual void setToDefault() = 0; - void setInvalid(); -}; - -#endif /* CONTROLLERSET_H_ */ diff --git a/datapool/DataPool.cpp b/datapool/DataPool.cpp deleted file mode 100644 index 1b6cb7a1..00000000 --- a/datapool/DataPool.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "DataPool.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../ipc/MutexFactory.h" - -DataPool::DataPool( void ( *initFunction )( std::map* pool_map ) ) { - mutex = MutexFactory::instance()->createMutex(); - if (initFunction != NULL ) { - initFunction( &this->data_pool ); - } -} - -DataPool::~DataPool() { - MutexFactory::instance()->deleteMutex(mutex); - for ( std::map::iterator it = this->data_pool.begin(); it != this->data_pool.end(); ++it ) { - delete it->second; - } -} - -//The function checks PID, type and array length before returning a copy of the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr. -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t sizeOrPosition ) { - std::map::iterator it = this->data_pool.find( data_pool_id ); - if ( it != this->data_pool.end() ) { - PoolEntry* entry = dynamic_cast< PoolEntry* >( it->second ); - if (entry != NULL ) { - if ( sizeOrPosition <= entry->length ) { - return entry; - } - } - } - return NULL; -} - -PoolEntryIF* DataPool::getRawData( uint32_t data_pool_id ) { - std::map::iterator it = this->data_pool.find( data_pool_id ); - if ( it != this->data_pool.end() ) { - return it->second; - } else { - return NULL; - } -} - -//uint8_t DataPool::getRawData( uint32_t data_pool_id, uint8_t* address, uint16_t* size, uint32_t maxSize ) { -// std::map::iterator it = this->data_pool.find( data_pool_id ); -// if ( it != this->data_pool.end() ) { -// if ( it->second->getByteSize() <= maxSize ) { -// *size = it->second->getByteSize(); -// memcpy( address, it->second->getRawData(), *size ); -// return DP_SUCCESSFUL; -// } -// } -// *size = 0; -// return DP_FAILURE; -//} - -ReturnValue_t DataPool::freeDataPoolLock() { - ReturnValue_t status = mutex->unlockMutex(); - if ( status != RETURN_OK ) { - sif::error << "DataPool::DataPool: unlock of mutex failed with error code: " << status << std::endl; - } - return status; -} - -ReturnValue_t DataPool::lockDataPool() { - ReturnValue_t status = mutex->lockMutex(MutexIF::BLOCKING); - if ( status != RETURN_OK ) { - sif::error << "DataPool::DataPool: lock of mutex failed with error code: " << status << std::endl; - } - return status; -} - -void DataPool::print() { - sif::debug << "DataPool contains: " << std::endl; - std::map::iterator dataPoolIt; - dataPoolIt = this->data_pool.begin(); - while( dataPoolIt != this->data_pool.end() ) { - sif::debug << std::hex << dataPoolIt->first << std::dec << " |"; - dataPoolIt->second->print(); - dataPoolIt++; - } -} - -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData(uint32_t data_pool_id, - uint8_t size); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData( uint32_t data_pool_id, uint8_t size ); -template PoolEntry* DataPool::getData(uint32_t data_pool_id, - uint8_t size); - - -uint32_t DataPool::PIDToDataPoolId(uint32_t parameter_id) { - return (parameter_id >> 8) & 0x00FFFFFF; -} - -uint8_t DataPool::PIDToArrayIndex(uint32_t parameter_id) { - return (parameter_id & 0x000000FF); -} - -uint32_t DataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) { - return (poolId << 8) + index; -} - - -//SHOULDDO: Do we need a mutex lock here... I don't think so, as we only check static const values of elements in a list that do not change. -//there is no guarantee in the standard, but it seems to me that the implementation is safe -UM -ReturnValue_t DataPool::getType(uint32_t parameter_id, Type* type) { - std::map::iterator it = this->data_pool.find( PIDToDataPoolId(parameter_id)); - if ( it != this->data_pool.end() ) { - *type = it->second->getType(); - return RETURN_OK; - } else { - *type = Type::UNKNOWN_TYPE; - return RETURN_FAILED; - } -} - -bool DataPool::exists(uint32_t parameterId) { - uint32_t poolId = PIDToDataPoolId(parameterId); - uint32_t index = PIDToArrayIndex(parameterId); - std::map::iterator it = this->data_pool.find( poolId ); - if (it != data_pool.end()) { - if (it->second->getSize() >= index) { - return true; - } - } - return false; -} diff --git a/datapool/DataPool.h b/datapool/DataPool.h deleted file mode 100644 index 7abf2898..00000000 --- a/datapool/DataPool.h +++ /dev/null @@ -1,135 +0,0 @@ -/** - * \file DataPool.h - * - * \date 10/17/2012 - * \author Bastian Baetz - * - * \brief This file contains the definition of the DataPool class and (temporarily) - * the "extern" definition of the global dataPool instance. - */ - -#ifndef DATAPOOL_H_ -#define DATAPOOL_H_ - -#include "PoolEntry.h" -#include "../globalfunctions/Type.h" -#include "../ipc/MutexIF.h" -#include - -/** - * \defgroup data_pool Data Pool - * This is the group, where all classes associated with Data Pool Handling belong to. - * This includes classes to access Data Pool variables. - */ - -#define DP_SUCCESSFUL 0 -#define DP_FAILURE 1 - -/** - * \brief This class represents the OBSW global data-pool. - * - * \details All variables are registered and space is allocated in an initialization - * function, which is passed do the constructor. - * Space for the variables is allocated on the heap (with a new call). - * The data is found by a data pool id, which uniquely represents a variable. - * Data pool variables should be used with a blackboard logic in mind, - * which means read data is valid (if flagged so), but not necessarily up-to-date. - * Variables are either single values or arrays. - * \ingroup data_pool - */ -class DataPool : public HasReturnvaluesIF { -private: - /** - * \brief This is the actual data pool itself. - * \details It is represented by a map - * with the data pool id as index and a pointer to a single PoolEntry as value. - */ - std::map data_pool; -public: - /** - * \brief The mutex is created in the constructor and makes access mutual exclusive. - * \details Locking and unlocking the pool is only done by the DataSet class. - */ - MutexIF* mutex; - /** - * \brief In the classes constructor, the passed initialization function is called. - * \details To enable filling the pool, - * a pointer to the map is passed, allowing direct access to the pool's content. - * On runtime, adding or removing variables is forbidden. - */ - DataPool( void ( *initFunction )( std::map* pool_map ) ); - /** - * \brief The destructor iterates through the data_pool map and calls all Entries destructors to clean up the heap. - */ - ~DataPool(); - /** - * \brief This is the default call to access the pool. - * \details A pointer to the PoolEntry object is returned. - * The call checks data pool id, type and array size. Returns NULL in case of failure. - * \param data_pool_id The data pool id to search. - * \param sizeOrPosition The array size (not byte size!) of the pool entry, or the position the user wants to read. - * If smaller than the entry size, everything's ok. - */ - template PoolEntry* getData( uint32_t data_pool_id, uint8_t sizeOrPosition ); - /** - * \brief An alternative call to get a data pool entry in case the type is not implicitly known - * (i.e. in Housekeeping Telemetry). - * \details It returns a basic interface and does NOT perform - * a size check. The caller has to assure he does not copy too much data. - * Returns NULL in case the entry is not found. - * \param data_pool_id The data pool id to search. - */ - PoolEntryIF* getRawData( uint32_t data_pool_id ); - /** - * \brief This is a small helper function to facilitate locking the global data pool. - * \details It fetches the pool's mutex id and tries to acquire the mutex. - */ - ReturnValue_t lockDataPool(); - /** - * \brief This is a small helper function to facilitate unlocking the global data pool. - * \details It fetches the pool's mutex id and tries to free the mutex. - */ - ReturnValue_t freeDataPoolLock(); - /** - * \brief The print call is a simple debug method. - * \details It prints the current content of the data pool. - * It iterates through the data_pool map and calls each entry's print() method. - */ - void print(); - /** - * Extracts the data pool id from a SCOS 2000 PID. - * @param parameter_id The passed Parameter ID. - * @return The data pool id as used within the OBSW. - */ - static uint32_t PIDToDataPoolId( uint32_t parameter_id ); - /** - * Extracts an array index out of a SCOS 2000 PID. - * @param parameter_id The passed Parameter ID. - * @return The index of the corresponding data pool entry. - */ - static uint8_t PIDToArrayIndex( uint32_t parameter_id ); - /** - * Retransforms a data pool id and an array index to a SCOS 2000 PID. - */ - static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index ); - - /** - * Method to return the type of a pool variable. - * @param parameter_id A parameterID (not pool id) of a DP member. - * @param type Returns the type or TYPE::UNKNOWN_TYPE - * @return RETURN_OK if parameter exists, RETURN_FAILED else. - */ - ReturnValue_t getType( uint32_t parameter_id, Type* type ); - - /** - * Method to check if a PID exists. - * Does not lock, as there's no possibility to alter the list that is checked during run-time. - * @param parameterId The PID (not pool id!) of a parameter. - * @return true if exists, false else. - */ - bool exists(uint32_t parameterId); -}; - -//We assume someone globally instantiates a DataPool. -extern DataPool dataPool; -#endif /* DATAPOOL_H_ */ diff --git a/datapool/DataSet.cpp b/datapool/DataSet.cpp deleted file mode 100644 index e41489bd..00000000 --- a/datapool/DataSet.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include "DataSet.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -DataSet::DataSet() : - fill_count(0), state(DATA_SET_UNINITIALISED) { - for (unsigned count = 0; count < DATA_SET_MAX_SIZE; count++) { - registeredVariables[count] = NULL; - } -} - -DataSet::~DataSet() { - //Don't do anything with your variables, they are dead already! (Destructor is already called) -} - -ReturnValue_t DataSet::read() { - ReturnValue_t result = RETURN_OK; - if (state == DATA_SET_UNINITIALISED) { - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_WRITE - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - ReturnValue_t status = registeredVariables[count]->read(); - if (status != RETURN_OK) { - result = INVALID_PARAMETER_DEFINITION; - break; - } - } - } - state = DATA_SET_WAS_READ; - freeDataPoolLock(); - } else { - sif::error << "DataSet::read(): Call made in wrong position." << std::endl; - result = SET_WAS_ALREADY_READ; - } - return result; -} - -ReturnValue_t DataSet::commit(uint8_t valid) { - setValid(valid); - return commit(); -} - -ReturnValue_t DataSet::commit() { - if (state == DATA_SET_WAS_READ) { - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_READ - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commit(); - } - } - state = DATA_SET_UNINITIALISED; - freeDataPoolLock(); - return RETURN_OK; - } else { - ReturnValue_t result = RETURN_OK; - lockDataPool(); - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - == PoolVariableIF::VAR_WRITE - && registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - registeredVariables[count]->commit(); - } else if (registeredVariables[count]->getDataPoolId() - != PoolVariableIF::NO_PARAMETER) { - if (result != COMMITING_WITHOUT_READING) { - sif::error << - "DataSet::commit(): commit-without-read " - "call made with non write-only variable." << std::endl; - result = COMMITING_WITHOUT_READING; - } - } - } - state = DATA_SET_UNINITIALISED; - freeDataPoolLock(); - return result; - } - -} - -void DataSet::registerVariable(PoolVariableIF* variable) { - if (state == DATA_SET_UNINITIALISED) { - if (variable != NULL) { - if (fill_count < DATA_SET_MAX_SIZE) { - registeredVariables[fill_count] = variable; - fill_count++; - return; - } - } - } - sif::error - << "DataSet::registerVariable: failed. Either NULL, or set is full, or call made in wrong position." - << std::endl; - return; -} - -uint8_t DataSet::freeDataPoolLock() { - return ::dataPool.freeDataPoolLock(); -} - -uint8_t DataSet::lockDataPool() { - return ::dataPool.lockDataPool(); -} - -ReturnValue_t DataSet::serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - ReturnValue_t result = RETURN_FAILED; - for (uint16_t count = 0; count < fill_count; count++) { - result = registeredVariables[count]->serialize(buffer, size, maxSize, - streamEndianness); - if (result != RETURN_OK) { - return result; - } - } - return result; -} - -size_t DataSet::getSerializedSize() const { - size_t size = 0; - for (uint16_t count = 0; count < fill_count; count++) { - size += registeredVariables[count]->getSerializedSize(); - } - return size; -} - -void DataSet::setValid(uint8_t valid) { - for (uint16_t count = 0; count < fill_count; count++) { - if (registeredVariables[count]->getReadWriteMode() - != PoolVariableIF::VAR_READ) { - registeredVariables[count]->setValid(valid); - } - } -} - -ReturnValue_t DataSet::deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result = RETURN_FAILED; - for (uint16_t count = 0; count < fill_count; count++) { - result = registeredVariables[count]->deSerialize(buffer, size, - streamEndianness); - if (result != RETURN_OK) { - return result; - } - } - return result; -} diff --git a/datapool/DataSet.h b/datapool/DataSet.h deleted file mode 100644 index 04044bfe..00000000 --- a/datapool/DataSet.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * \file DataSet.h - * - * \brief This file contains the DataSet class and a small structure called DataSetContent. - * - * \date 10/17/2012 - * - * \author Bastian Baetz - * - */ - -#ifndef DATASET_H_ -#define DATASET_H_ - -#include "DataPool.h" -#include "DataSetIF.h" -#include "PoolRawAccess.h" -#include "PoolVariable.h" -#include "PoolVarList.h" -#include "PoolVector.h" -#include "../serialize/SerializeAdapter.h" -/** - * \brief The DataSet class manages a set of locally checked out variables. - * - * \details This class manages a list, where a set of local variables (or pool variables) are - * registered. They are checked-out (i.e. their values are looked up and copied) - * with the read call. After the user finishes working with the pool variables, - * he can write back all variable values to the pool with the commit call. - * The data set manages locking and freeing the data pool, to ensure that all values - * are read and written back at once. - * An internal state manages usage of this class. Variables may only be registered before - * the read call is made, and the commit call only after the read call. - * If pool variables are writable and not committed until destruction of the set, the - * DataSet class automatically sets the valid flag in the data pool to invalid (without) - * changing the variable's value. - * - * \ingroup data_pool - */ -class DataSet: public DataSetIF, public HasReturnvaluesIF, public SerializeIF { -private: - //SHOULDDO we could use a linked list of datapool variables - static const uint8_t DATA_SET_MAX_SIZE = 63; //!< This definition sets the maximum number of variables to register in one DataSet. - - /** - * \brief This array represents all pool variables registered in this set. - * \details It has a maximum size of DATA_SET_MAX_SIZE. - */ - PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; - /** - * \brief The fill_count attribute ensures that the variables register in the correct array - * position and that the maximum number of variables is not exceeded. - */ - uint16_t fill_count; - /** - * States of the seet. - */ - enum States { - DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED - DATA_SET_WAS_READ //!< DATA_SET_WAS_READ - }; - /** - * \brief state manages the internal state of the data set, which is important e.g. for the - * behavior on destruction. - */ - States state; - /** - * \brief This is a small helper function to facilitate locking the global data pool. - * \details It makes use of the lockDataPool method offered by the DataPool class. - */ - uint8_t lockDataPool(); - /** - * \brief This is a small helper function to facilitate unlocking the global data pool. - * \details It makes use of the freeDataPoolLock method offered by the DataPool class. - */ - uint8_t freeDataPoolLock(); - -public: - static const uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; - static const ReturnValue_t INVALID_PARAMETER_DEFINITION = - MAKE_RETURN_CODE( 0x01 ); - static const ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); - static const ReturnValue_t COMMITING_WITHOUT_READING = - MAKE_RETURN_CODE(0x03); - - /** - * \brief The constructor simply sets the fill_count to zero and sets the state to "uninitialized". - */ - DataSet(); - /** - * \brief The destructor automatically manages writing the valid information of variables. - * \details In case the data set was read out, but not committed (indicated by state), - * the destructor parses all variables that are still registered to the set. - * For each, the valid flag in the data pool is set to "invalid". - */ - ~DataSet(); - /** - * \brief The read call initializes reading out all registered variables. - * \details It iterates through the list of registered variables and calls all read() - * functions of the registered pool variables (which read out their values from the - * data pool) which are not write-only. In case of an error (e.g. a wrong data type, - * or an invalid data pool id), the operation is aborted and - * \c INVALID_PARAMETER_DEFINITION returned. - * The data pool is locked during the whole read operation and freed afterwards. - * The state changes to "was written" after this operation. - * \return - \c RETURN_OK if all variables were read successfully. - * - \c INVALID_PARAMETER_DEFINITION if PID, size or type of the - * requested variable is invalid. - * - \c SET_WAS_ALREADY_READ if read() is called twice without calling - * commit() in between - */ - ReturnValue_t read(); - /** - * \brief The commit call initializes writing back the registered variables. - * \details It iterates through the list of registered variables and calls - * the commit() method of the remaining registered variables (which write back - * their values to the pool). - * The data pool is locked during the whole commit operation and freed afterwards. - * The state changes to "was committed" after this operation. - * If the set does contain at least one variable which is not write-only commit() - * can only be called after read(). If the set only contains variables which are - * write only, commit() can be called without a preceding read() call. - * \return - \c RETURN_OK if all variables were read successfully. - * - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only - * variables - */ - ReturnValue_t commit(void); - /** - * Variant of method above which sets validity of all elements of the set. - * @param valid Validity information from PoolVariableIF. - * \return - \c RETURN_OK if all variables were read successfully. - * - \c COMMITING_WITHOUT_READING if set was not read yet and contains non write-only - * variables - */ - ReturnValue_t commit(uint8_t valid); - /** - * \brief This operation is used to register the local variables in the set. - * \details It copies all required information to the currently - * free space in the registeredVariables list. - */ - void registerVariable(PoolVariableIF* variable); - - /** - * Set the valid information of all variables contained in the set which are not readonly - * - * @param valid Validity information from PoolVariableIF. - */ - void setValid(uint8_t valid); - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const override; - - size_t getSerializedSize() const override; - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) override; - -}; - -#endif /* DATASET_H_ */ diff --git a/datapool/DataSetIF.h b/datapool/DataSetIF.h index 7741477d..a6634a5c 100644 --- a/datapool/DataSetIF.h +++ b/datapool/DataSetIF.h @@ -1,39 +1,47 @@ -/** - * \file DataSetIF.h - * - * \brief This file contains the small interface to access the DataSet class. - * - * \date 10/23/2012 - * - * \author Bastian Baetz - * - */ - -#ifndef DATASETIF_H_ -#define DATASETIF_H_ +#ifndef FSFW_DATAPOOL_DATASETIF_H_ +#define FSFW_DATAPOOL_DATASETIF_H_ +#include "../returnvalues/HasReturnvaluesIF.h" +#include "../timemanager/Clock.h" class PoolVariableIF; /** - * \brief This class defines a small interface to register on a DataSet. + * @brief This class defines a small interface to register on a DataSet. * - * \details Currently, the only purpose of this interface is to provide a method for locally - * checked-out variables to register on a data set. Still, it may become useful for - * other purposes as well. - * - * \ingroup data_pool + * @details + * Currently, the only purpose of this interface is to provide a + * method for locally checked-out variables to register on a data set. + * Still, it may become useful for other purposes as well. + * @author Bastian Baetz + * @ingroup data_pool */ class DataSetIF { public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; + static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = + MAKE_RETURN_CODE( 0x01 ); + static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); + static constexpr ReturnValue_t COMMITING_WITHOUT_READING = + MAKE_RETURN_CODE(0x03); + + static constexpr ReturnValue_t DATA_SET_UNINITIALISED = MAKE_RETURN_CODE( 0x04 ); + static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE( 0x05 ); + static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE( 0x06 ); + /** - * \brief This is an empty virtual destructor, as it is proposed for C++ interfaces. + * @brief This is an empty virtual destructor, + * as it is proposed for C++ interfaces. */ virtual ~DataSetIF() {} + /** - * \brief This operation provides a method to register local data pool variables - * to register in a data set by passing itself to this DataSet operation. + * @brief This operation provides a method to register local data pool + * variables to register in a data set by passing itself + * to this DataSet operation. */ - virtual void registerVariable( PoolVariableIF* variable ) = 0; + virtual ReturnValue_t registerVariable(PoolVariableIF* variable) = 0; + + virtual uint16_t getFillCount() const = 0; }; -#endif /* DATASETIF_H_ */ +#endif /* FSFW_DATAPOOL_DATASETIF_H_ */ diff --git a/datapool/HkSwitchHelper.cpp b/datapool/HkSwitchHelper.cpp index 04096aca..1a2a25eb 100644 --- a/datapool/HkSwitchHelper.cpp +++ b/datapool/HkSwitchHelper.cpp @@ -1,5 +1,4 @@ -#include "HkSwitchHelper.h" -//#include +#include "../datapool/HkSwitchHelper.h" #include "../ipc/QueueFactory.h" HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy) : @@ -22,14 +21,14 @@ ReturnValue_t HkSwitchHelper::initialize() { } ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) { - CommandMessage message; - while (actionQueue->receiveMessage(&message) == HasReturnvaluesIF::RETURN_OK) { - ReturnValue_t result = commandActionHelper.handleReply(&message); + CommandMessage command; + while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) { + ReturnValue_t result = commandActionHelper.handleReply(&command); if (result == HasReturnvaluesIF::RETURN_OK) { continue; } - message.setToUnknownCommand(); - actionQueue->reply(&message); + command.setToUnknownCommand(); + actionQueue->reply(&command); } return HasReturnvaluesIF::RETURN_OK; diff --git a/datapool/PoolDataSetBase.cpp b/datapool/PoolDataSetBase.cpp new file mode 100644 index 00000000..1acd3fd3 --- /dev/null +++ b/datapool/PoolDataSetBase.cpp @@ -0,0 +1,169 @@ +#include "PoolDataSetBase.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray, + const size_t maxFillCount): + registeredVariables(registeredVariablesArray), + maxFillCount(maxFillCount) { +} + +PoolDataSetBase::~PoolDataSetBase() {} + +ReturnValue_t PoolDataSetBase::registerVariable( + PoolVariableIF *variable) { + if (state != States::DATA_SET_UNINITIALISED) { + sif::error << "DataSet::registerVariable: " + "Call made in wrong position." << std::endl; + return DataSetIF::DATA_SET_UNINITIALISED; + } + if (variable == nullptr) { + sif::error << "DataSet::registerVariable: " + "Pool variable is nullptr." << std::endl; + return DataSetIF::POOL_VAR_NULL; + } + if (fillCount >= maxFillCount) { + sif::error << "DataSet::registerVariable: " + "DataSet is full." << std::endl; + return DataSetIF::DATA_SET_FULL; + } + registeredVariables[fillCount] = variable; + fillCount++; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PoolDataSetBase::read(uint32_t lockTimeout) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + if (state == States::DATA_SET_UNINITIALISED) { + lockDataPool(lockTimeout); + for (uint16_t count = 0; count < fillCount; count++) { + result = readVariable(count); + if(result != RETURN_OK) { + break; + } + } + state = States::DATA_SET_WAS_READ; + unlockDataPool(); + } + else { + sif::error << "DataSet::read(): " + "Call made in wrong position. Don't forget to commit" + " member datasets!" << std::endl; + result = SET_WAS_ALREADY_READ; + } + return result; +} + +uint16_t PoolDataSetBase::getFillCount() const { + return fillCount; +} + +ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + // These checks are often performed by the respective + // variable implementation too, but I guess a double check does not hurt. + if (registeredVariables[count]->getReadWriteMode() != + PoolVariableIF::VAR_WRITE and + registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) + { + result = registeredVariables[count]->readWithoutLock(); + if(result != HasReturnvaluesIF::RETURN_OK) { + result = INVALID_PARAMETER_DEFINITION; + } + } + return result; +} + +ReturnValue_t PoolDataSetBase::commit(uint32_t lockTimeout) { + if (state == States::DATA_SET_WAS_READ) { + handleAlreadyReadDatasetCommit(lockTimeout); + return HasReturnvaluesIF::RETURN_OK; + } + else { + return handleUnreadDatasetCommit(lockTimeout); + } +} + +void PoolDataSetBase::handleAlreadyReadDatasetCommit(uint32_t lockTimeout) { + lockDataPool(lockTimeout); + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_READ + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + registeredVariables[count]->commitWithoutLock(); + } + } + state = States::DATA_SET_UNINITIALISED; + unlockDataPool(); +} + +ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(uint32_t lockTimeout) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + lockDataPool(lockTimeout); + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + == PoolVariableIF::VAR_WRITE + && registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + registeredVariables[count]->commitWithoutLock(); + } else if (registeredVariables[count]->getDataPoolId() + != PoolVariableIF::NO_PARAMETER) { + if (result != COMMITING_WITHOUT_READING) { + sif::error << "DataSet::commit(): commit-without-read call made " + "with non write-only variable." << std::endl; + result = COMMITING_WITHOUT_READING; + } + } + } + state = States::DATA_SET_UNINITIALISED; + unlockDataPool(); + return result; +} + + +ReturnValue_t PoolDataSetBase::lockDataPool(uint32_t timeoutMs) { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PoolDataSetBase::unlockDataPool() { + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, SerializeIF::Endianness streamEndianness) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->serialize(buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +ReturnValue_t PoolDataSetBase::deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->deSerialize(buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +size_t PoolDataSetBase::getSerializedSize() const { + uint32_t size = 0; + for (uint16_t count = 0; count < fillCount; count++) { + size += registeredVariables[count]->getSerializedSize(); + } + return size; +} + +void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) { + this->registeredVariables = variablesContainer; +} diff --git a/datapool/PoolDataSetBase.h b/datapool/PoolDataSetBase.h new file mode 100644 index 00000000..a8931d62 --- /dev/null +++ b/datapool/PoolDataSetBase.h @@ -0,0 +1,152 @@ +#ifndef FSFW_DATAPOOL_POOLDATASETBASE_H_ +#define FSFW_DATAPOOL_POOLDATASETBASE_H_ + +#include "PoolDataSetIF.h" +#include "PoolVariableIF.h" +#include "../ipc/MutexIF.h" + +/** + * @brief The DataSetBase class manages a set of locally checked out variables. + * @details + * This class manages a list, where a set of local variables (or pool variables) + * are registered. They are checked-out (i.e. their values are looked + * up and copied) with the read call. After the user finishes working with the + * pool variables, he can write back all variable values to the pool with + * the commit call. The data set manages locking and freeing the data pool, + * to ensure that all values are read and written back at once. + * + * An internal state manages usage of this class. Variables may only be + * registered before the read call is made, and the commit call only + * after the read call. + * + * If pool variables are writable and not committed until destruction + * of the set, the DataSet class automatically sets the valid flag in the + * data pool to invalid (without) changing the variable's value. + * + * The base class lockDataPool und unlockDataPool implementation are empty + * and should be implemented to protect the underlying pool type. + * @author Bastian Baetz + * @ingroup data_pool + */ +class PoolDataSetBase: public PoolDataSetIF, + public SerializeIF, + public HasReturnvaluesIF { +public: + + /** + * @brief Creates an empty dataset. Use registerVariable or + * supply a pointer to this dataset to PoolVariable + * initializations to register pool variables. + */ + PoolDataSetBase(PoolVariableIF** registeredVariablesArray, + const size_t maxFillCount); + virtual~ PoolDataSetBase(); + + /** + * @brief The read call initializes reading out all registered variables. + * @details + * It iterates through the list of registered variables and calls all read() + * functions of the registered pool variables (which read out their values + * from the data pool) which are not write-only. + * In case of an error (e.g. a wrong data type, or an invalid data pool id), + * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. + * + * The data pool is locked during the whole read operation and + * freed afterwards.The state changes to "was written" after this operation. + * @return + * - @c RETURN_OK if all variables were read successfully. + * - @c INVALID_PARAMETER_DEFINITION if PID, size or type of the + * requested variable is invalid. + * - @c SET_WAS_ALREADY_READ if read() is called twice without calling + * commit() in between + */ + virtual ReturnValue_t read(uint32_t lockTimeout = + MutexIF::BLOCKING) override; + /** + * @brief The commit call initializes writing back the registered variables. + * @details + * It iterates through the list of registered variables and calls the + * commit() method of the remaining registered variables (which write back + * their values to the pool). + * + * The data pool is locked during the whole commit operation and + * freed afterwards. The state changes to "was committed" after this operation. + * + * If the set does contain at least one variable which is not write-only + * commit() can only be called after read(). If the set only contains + * variables which are write only, commit() can be called without a + * preceding read() call. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + virtual ReturnValue_t commit(uint32_t lockTimeout = + MutexIF::BLOCKING) override; + + /** + * Register the passed pool variable instance into the data set. + * @param variable + * @return + */ + virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override; + /** + * Provides the means to lock the underlying data structure to ensure + * thread-safety. Default implementation is empty + * @return Always returns -@c RETURN_OK + */ + virtual ReturnValue_t lockDataPool(uint32_t timeoutMs = + MutexIF::BLOCKING) override; + /** + * Provides the means to unlock the underlying data structure to ensure + * thread-safety. Default implementation is empty + * @return Always returns -@c RETURN_OK + */ + virtual ReturnValue_t unlockDataPool() override; + + virtual uint16_t getFillCount() const; + + /* SerializeIF implementations */ + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; + +protected: + /** + * @brief The fill_count attribute ensures that the variables + * register in the correct array position and that the maximum + * number of variables is not exceeded. + */ + uint16_t fillCount = 0; + /** + * States of the seet. + */ + enum class States { + DATA_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED + DATA_SET_WAS_READ //!< DATA_SET_WAS_READ + }; + /** + * @brief state manages the internal state of the data set, + * which is important e.g. for the behavior on destruction. + */ + States state = States::DATA_SET_UNINITIALISED; + + /** + * @brief This array represents all pool variables registered in this set. + * Child classes can use a static or dynamic container to create + * an array of registered variables and assign the first entry here. + */ + PoolVariableIF** registeredVariables = nullptr; + const size_t maxFillCount = 0; + + void setContainer(PoolVariableIF** variablesContainer); + +private: + ReturnValue_t readVariable(uint16_t count); + void handleAlreadyReadDatasetCommit(uint32_t lockTimeout); + ReturnValue_t handleUnreadDatasetCommit(uint32_t lockTimeout); +}; + +#endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */ diff --git a/datapool/PoolDataSetIF.h b/datapool/PoolDataSetIF.h new file mode 100644 index 00000000..aa45fa54 --- /dev/null +++ b/datapool/PoolDataSetIF.h @@ -0,0 +1,33 @@ +#ifndef FSFW_DATAPOOL_POOLDATASETIF_H_ +#define FSFW_DATAPOOL_POOLDATASETIF_H_ + +#include "DataSetIF.h" + +/** + * @brief Extendes the DataSetIF by adding abstract functions to lock + * and unlock a data pool and read/commit semantics. + */ +class PoolDataSetIF: public DataSetIF { +public: + virtual~ PoolDataSetIF() {}; + + virtual ReturnValue_t read(dur_millis_t lockTimeout) = 0; + virtual ReturnValue_t commit(dur_millis_t lockTimeout) = 0; + + /** + * @brief Most underlying data structures will have a pool like structure + * and will require a lock and unlock mechanism to ensure + * thread-safety + * @return Lock operation result + */ + virtual ReturnValue_t lockDataPool(dur_millis_t timeoutMs) = 0; + /** + * @brief Unlock call corresponding to the lock call. + * @return Unlock operation result + */ + virtual ReturnValue_t unlockDataPool() = 0; + + virtual bool isValid() const = 0; +}; + +#endif /* FSFW_DATAPOOL_POOLDATASETIF_H_ */ diff --git a/datapool/PoolEntry.cpp b/datapool/PoolEntry.cpp index 56e489a5..fb73328c 100644 --- a/datapool/PoolEntry.cpp +++ b/datapool/PoolEntry.cpp @@ -1,4 +1,5 @@ #include "PoolEntry.h" + #include "../serviceinterface/ServiceInterfaceStream.h" #include "../globalfunctions/arrayprinter.h" #include diff --git a/datapool/PoolEntry.h b/datapool/PoolEntry.h index 7b47c673..033db40d 100644 --- a/datapool/PoolEntry.h +++ b/datapool/PoolEntry.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_DATAPOOL_POOLENTRY_H_ -#define FRAMEWORK_DATAPOOL_POOLENTRY_H_ +#ifndef FSFW_DATAPOOL_POOLENTRY_H_ +#define FSFW_DATAPOOL_POOLENTRY_H_ #include "PoolEntryIF.h" @@ -127,4 +127,4 @@ public: Type getType(); }; -#endif /* POOLENTRY_H_ */ +#endif /* FSFW_DATAPOOL_POOLENTRY_H_ */ diff --git a/datapool/PoolEntryIF.h b/datapool/PoolEntryIF.h index 462de18b..d9db5237 100644 --- a/datapool/PoolEntryIF.h +++ b/datapool/PoolEntryIF.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_DATAPOOL_POOLENTRYIF_H_ -#define FRAMEWORK_DATAPOOL_POOLENTRYIF_H_ +#ifndef FSFW_DATAPOOL_POOLENTRYIF_H_ +#define FSFW_DATAPOOL_POOLENTRYIF_H_ #include "../globalfunctions/Type.h" #include @@ -60,4 +60,4 @@ public: virtual Type getType() = 0; }; -#endif /* POOLENTRYIF_H_ */ +#endif /* FSFW_DATAPOOL_POOLENTRYIF_H_ */ diff --git a/datapool/PoolRawAccess.cpp b/datapool/PoolRawAccess.cpp deleted file mode 100644 index f9264081..00000000 --- a/datapool/PoolRawAccess.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "DataPool.h" -#include "PoolEntryIF.h" -#include "PoolRawAccess.h" -#include "../serviceinterface/ServiceInterfaceStream.h" -#include "../serialize/EndianConverter.h" - -#include - -PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry, - DataSetIF *data_set, ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), type( - Type::UNKNOWN_TYPE), typeSize(0), arraySize(0), sizeTillEnd(0), readWriteMode( - setReadWriteMode) { - memset(value, 0, sizeof(value)); - if (data_set != NULL) { - data_set->registerVariable(this); - } -} - -PoolRawAccess::~PoolRawAccess() { - -} - -ReturnValue_t PoolRawAccess::read() { - PoolEntryIF *read_out = ::dataPool.getRawData(dataPoolId); - if (read_out != NULL) { - valid = read_out->getValid(); - if (read_out->getSize() > arrayEntry) { - arraySize = read_out->getSize(); - typeSize = read_out->getByteSize() / read_out->getSize(); - type = read_out->getType(); - if (typeSize <= sizeof(value)) { - uint16_t arrayPosition = arrayEntry * typeSize; - sizeTillEnd = read_out->getByteSize() - arrayPosition; - uint8_t *ptr = - &((uint8_t*) read_out->getRawData())[arrayPosition]; - memcpy(value, ptr, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - //Error value type too large. - } - } else { - //Error index requested too large - } - } else { - //Error entry does not exist. - } - sif::error << "PoolRawAccess: read of DP Variable 0x" << std::hex - << dataPoolId << std::dec << " failed." << std::endl; - valid = INVALID; - typeSize = 0; - sizeTillEnd = 0; - memset(value, 0, sizeof(value)); - return HasReturnvaluesIF::RETURN_FAILED; -} - -ReturnValue_t PoolRawAccess::commit() { - PoolEntryIF *write_back = ::dataPool.getRawData(dataPoolId); - if ((write_back != NULL) && (readWriteMode != VAR_READ)) { - write_back->setValid(valid); - uint8_t array_position = arrayEntry * typeSize; - uint8_t *ptr = &((uint8_t*) write_back->getRawData())[array_position]; - memcpy(ptr, value, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } -} - -uint8_t* PoolRawAccess::getEntry() { - return value; -} - -ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t *buffer, - size_t *writtenBytes, size_t maxSize) { - uint8_t *data_ptr = getEntry(); -// debug << "PoolRawAccess::getEntry: Array position: " << index * size_of_type << " Size of T: " << (int)size_of_type << " ByteSize: " << byte_size << " Position: " << *size << std::endl; - if (typeSize == 0) { - return DATA_POOL_ACCESS_FAILED; - } - if (typeSize > maxSize) { - return INCORRECT_SIZE; - } - EndianConverter::convertBigEndian(buffer, data_ptr, typeSize); - *writtenBytes = typeSize; - return HasReturnvaluesIF::RETURN_OK; -} - -Type PoolRawAccess::getType() { - return type; -} - -size_t PoolRawAccess::getSizeOfType() { - return typeSize; -} - -size_t PoolRawAccess::getArraySize() { - return arraySize; -} - -uint32_t PoolRawAccess::getDataPoolId() const { - return dataPoolId; -} - -PoolVariableIF::ReadWriteMode_t PoolRawAccess::getReadWriteMode() const { - return readWriteMode; -} - -ReturnValue_t PoolRawAccess::setEntryFromBigEndian(const uint8_t *buffer, - size_t setSize) { - if (typeSize == setSize) { - EndianConverter::convertBigEndian(value, buffer, typeSize); - return HasReturnvaluesIF::RETURN_OK; - } else { - sif::error - << "PoolRawAccess::setEntryFromBigEndian: Illegal sizes: Internal" - << (uint32_t) typeSize << ", Requested: " << setSize - << std::endl; - return INCORRECT_SIZE; - } -} - -bool PoolRawAccess::isValid() const { - if (valid != INVALID) - return true; - else - return false; -} - -void PoolRawAccess::setValid(uint8_t valid) { - this->valid = valid; -} - -size_t PoolRawAccess::getSizeTillEnd() const { - return sizeTillEnd; -} - -ReturnValue_t PoolRawAccess::serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const { - if (typeSize + *size <= maxSize) { - switch (streamEndianness) { - case (Endianness::BIG): - EndianConverter::convertBigEndian(*buffer, value, typeSize); - break; - case (Endianness::LITTLE): - EndianConverter::convertLittleEndian(*buffer, value, typeSize); - break; - default: - case (Endianness::MACHINE): - memcpy(*buffer, value, typeSize); - break; - } - *size += typeSize; - (*buffer) += typeSize; - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } -} - -size_t PoolRawAccess::getSerializedSize() const { - return typeSize; -} - -ReturnValue_t PoolRawAccess::deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) { - - if (*size >= typeSize) { - switch (streamEndianness) { - case (Endianness::BIG): - EndianConverter::convertBigEndian(value, *buffer, typeSize); - break; - case (Endianness::LITTLE): - EndianConverter::convertLittleEndian(value, *buffer, typeSize); - break; - default: - case (Endianness::MACHINE): - memcpy(value, *buffer, typeSize); - break; - } - *size -= typeSize; - *buffer += typeSize; - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::STREAM_TOO_SHORT; - } -} diff --git a/datapool/PoolRawAccess.h b/datapool/PoolRawAccess.h deleted file mode 100644 index 0c7a06bf..00000000 --- a/datapool/PoolRawAccess.h +++ /dev/null @@ -1,152 +0,0 @@ -#ifndef POOLRAWACCESS_H_ -#define POOLRAWACCESS_H_ - -#include "DataSetIF.h" -#include "PoolVariableIF.h" - -/** - * This class allows accessing Data Pool variables as raw bytes. - * This is necessary to have an access method for HK data, as the PID's alone do not - * provide a type information. - * \ingroup data_pool - */ -class PoolRawAccess: public PoolVariableIF { -private: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The array entry that is fetched from the data pool. - */ - uint8_t arrayEntry; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief This value contains the type of the data pool entry. - */ - Type type; - /** - * \brief This value contains the size of the data pool entry in bytes. - */ - size_t typeSize; - /** - * The size of the DP array (single values return 1) - */ - size_t arraySize; - /** - * The size (in bytes) from the selected entry till the end of this DataPool variable. - */ - size_t sizeTillEnd; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - static const uint8_t RAW_MAX_SIZE = sizeof(double); -protected: - /** - * \brief This is a call to read the value from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read(); - /** - * \brief The commit call writes back the variable's value to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit(); -public: - static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; - static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); - static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); - uint8_t value[RAW_MAX_SIZE]; - PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, - DataSetIF *data_set, ReadWriteMode_t setReadWriteMode = - PoolVariableIF::VAR_READ); - /** - * \brief The classes destructor is empty. If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolRawAccess(); - /** - * \brief This operation returns a pointer to the entry fetched. - * \details This means, it does not return a pointer to byte "index", but to the start byte of - * array entry "index". Example: If the original data pool array consists of an double - * array of size four, getEntry(1) returns &(this->value[8]). - */ - uint8_t* getEntry(); - /** - * \brief This operation returns the fetched entry from the data pool and - * flips the bytes, if necessary. - * \details It makes use of the getEntry call of this function, but additionally flips the - * bytes to big endian, which is the default for external communication (as House- - * keeping telemetry). To achieve this, the data is copied directly to the passed - * buffer, if it fits in the given maxSize. - * \param buffer A pointer to a buffer to write to - * \param writtenBytes The number of bytes written is returned with this value. - * \param maxSize The maximum size that the function may write to buffer. - * \return - \c RETURN_OK if entry could be acquired - * - \c RETURN_FAILED else. - */ - ReturnValue_t getEntryEndianSafe(uint8_t *buffer, size_t *size, - size_t maxSize); - /** - * With this method, the content can be set from a big endian buffer safely. - * @param buffer Pointer to the data to set - * @param size Size of the data to write. Must fit this->size. - * @return - \c RETURN_OK on success - * - \c RETURN_FAILED on failure - */ - ReturnValue_t setEntryFromBigEndian(const uint8_t *buffer, - size_t setSize); - /** - * \brief This operation returns the type of the entry currently stored. - */ - Type getType(); - /** - * \brief This operation returns the size of the entry currently stored. - */ - size_t getSizeOfType(); - /** - * - * @return the size of the datapool array - */ - size_t getArraySize(); - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const; - /** - * This method returns if the variable is read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const; - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const; - - void setValid(uint8_t valid); - /** - * Getter for the remaining size. - */ - size_t getSizeTillEnd() const; - - ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const override; - - size_t getSerializedSize() const override; - - ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override; -}; - -#endif /* POOLRAWACCESS_H_ */ diff --git a/datapool/PoolVarList.h b/datapool/PoolVarList.h index 035ff2ac..0b2b0f06 100644 --- a/datapool/PoolVarList.h +++ b/datapool/PoolVarList.h @@ -1,14 +1,15 @@ -#ifndef POOLVARLIST_H_ -#define POOLVARLIST_H_ +#ifndef FSFW_DATAPOOL_POOLVARLIST_H_ +#define FSFW_DATAPOOL_POOLVARLIST_H_ -#include "PoolVariable.h" -#include "PoolVariableIF.h" +#include "../datapool/PoolVariableIF.h" +#include "../datapoolglob/GlobalPoolVariable.h" template class PoolVarList { private: - PoolVariable variables[n_var]; + GlobPoolVar variables[n_var]; public: - PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, PoolVariableIF::ReadWriteMode_t setReadWriteMode ) { + PoolVarList( const uint32_t set_id[n_var], DataSetIF* dataSet, + PoolVariableIF::ReadWriteMode_t setReadWriteMode ) { //I really should have a look at the new init list c++ syntax. if (dataSet == NULL) { return; @@ -20,9 +21,9 @@ public: } } - PoolVariable &operator [](int i) { return variables[i]; } + GlobPoolVar &operator [](int i) { return variables[i]; } }; -#endif /* POOLVARLIST_H_ */ +#endif /* FSFW_DATAPOOL_POOLVARLIST_H_ */ diff --git a/datapool/PoolVariable.h b/datapool/PoolVariable.h deleted file mode 100644 index a9d3407d..00000000 --- a/datapool/PoolVariable.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * \file PoolVariable.h - * - * \brief This file contains the PoolVariable class, which locally represents a non-array data pool variable. - * - * \date 10/17/2012 - * - * \author Bastian Baetz - */ - -#ifndef POOLVARIABLE_H_ -#define POOLVARIABLE_H_ - -#include "DataSetIF.h" -#include "PoolEntry.h" -#include "PoolVariableIF.h" -#include "../serialize/SerializeAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -template class PoolVarList; - -/** - * \brief This is the access class for non-array data pool entries. - * - * \details To ensure safe usage of the data pool, operation is not done directly on the data pool - * entries, but on local copies. This class provides simple type-safe access to single - * data pool entries (i.e. entries with length = 1). - * The class can be instantiated as read-write and read only. - * It provides a commit-and-roll-back semantic, which means that the variable's value in - * the data pool is not changed until the commit call is executed. - * \tparam T The template parameter sets the type of the variable. Currently, all plain data types - * are supported, but in principle any type is possible. - * \ingroup data_pool - */ -template -class PoolVariable: public PoolVariableIF { - template friend class PoolVarList; -protected: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - /** - * \brief This is a call to read the value from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies the value and the valid - * information to its local attributes. In case of a failure (wrong type or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read() { - PoolEntry *read_out = ::dataPool.getData < T > (dataPoolId, 1); - if (read_out != NULL) { - valid = read_out->valid; - value = *(read_out->address); - return HasReturnvaluesIF::RETURN_OK; - } else { - value = 0; - valid = false; - sif::error << "PoolVariable: read of DP Variable 0x" << std::hex - << dataPoolId << std::dec << " failed." << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * \brief The commit call writes back the variable's value to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit() { - PoolEntry *write_back = ::dataPool.getData < T > (dataPoolId, 1); - if ((write_back != NULL) && (readWriteMode != VAR_READ)) { - write_back->valid = valid; - *(write_back->address) = value; - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * Empty ctor for List initialization - */ - PoolVariable() : - dataPoolId(PoolVariableIF::NO_PARAMETER), valid( - PoolVariableIF::INVALID), readWriteMode(VAR_READ), value(0) { - - } -public: - /** - * \brief This is the local copy of the data pool entry. - * \details The user can work on this attribute - * just like he would on a simple local variable. - */ - T value; - /** - * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is - * passed). - * \details It DOES NOT fetch the current value from the data pool, but sets the value - * attribute to default (0). The value is fetched within the read() operation. - * \param set_id This is the id in the global data pool this instance of the access class - * corresponds to. - * \param dataSet The data set in which the variable shall register itself. If NULL, - * the variable is not registered. - * \param setWritable If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. - */ - PoolVariable(uint32_t set_id, DataSetIF *dataSet, - ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), valid(PoolVariableIF::INVALID), readWriteMode( - setReadWriteMode), value(0) { - if (dataSet != NULL) { - dataSet->registerVariable(this); - } - } - /** - * Copy ctor to copy classes containing Pool Variables. - */ - PoolVariable(const PoolVariable &rhs) : - dataPoolId(rhs.dataPoolId), valid(rhs.valid), readWriteMode( - rhs.readWriteMode), value(rhs.value) { - } - - /** - * \brief The classes destructor is empty. - * \details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolVariable() { - - } - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const { - return dataPoolId; - } - /** - * This operation sets the data pool id of the variable. - * The method is necessary to set id's of data pool member variables with bad initialization. - */ - void setDataPoolId(uint32_t poolId) { - dataPoolId = poolId; - } - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const { - return readWriteMode; - } - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const { - if (valid) - return true; - else - return false; - } - - uint8_t getValid() { - return valid; - } - - void setValid(uint8_t valid) { - this->valid = valid; - } - - operator T() { - return value; - } - - operator T() const { - return value; - } - - PoolVariable& operator=(T newValue) { - value = newValue; - return *this; - } - - PoolVariable& operator=(PoolVariable newPoolVariable) { - value = newPoolVariable.value; - return *this; - } - - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, - size_t maxSize, Endianness streamEndianness) const override { - return SerializeAdapter::serialize(&value, buffer, size, maxSize, - streamEndianness); - } - - virtual size_t getSerializedSize() const override { - return SerializeAdapter::getSerializedSize(&value); - } - - virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, - Endianness streamEndianness) override { - return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); - } -}; - -typedef PoolVariable db_uint8_t; -typedef PoolVariable db_uint16_t; -typedef PoolVariable db_uint32_t; -typedef PoolVariable db_int8_t; -typedef PoolVariable db_int16_t; -typedef PoolVariable db_int32_t; -typedef PoolVariable db_bool_t; -typedef PoolVariable db_float_t; -typedef PoolVariable db_double_t; -//Alternative (but I thing this is not as useful: code duplication, differences too small): - -//template -//class PoolReader : public PoolVariableIF { -//private: -// uint32_t parameter_id; -// uint8_t valid; -//public: -// T value; -// PoolReader( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), valid(false), value(0) { -// set->registerVariable( this ); -// } -// -// ~PoolReader() {}; -// -// uint8_t commit() { -// return HasReturnvaluesIF::RETURN_OK; -// } -// -// uint8_t read() { -// PoolEntry* read_out = ::dataPool.getData( parameter_id, 1 ); -// if ( read_out != NULL ) { -// valid = read_out->valid; -// value = *(read_out->address); -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// value = 0; -// valid = false; -// return CHECKOUT_FAILED; -// } -// } -// uint32_t getParameterId() { return parameter_id; } -// bool isWritable() { return false; }; -// bool isValid() { if (valid) return true; else return false; } -//}; -// -//template -//class PoolWriter : public PoolVariableIF { -//private: -// uint32_t parameter_id; -//public: -// T value; -// PoolWriter( uint32_t set_id, DataSetIF* set ) : parameter_id(set_id), value(0) { -// set->registerVariable( this ); -// } -// -// ~PoolWriter() {}; -// -// uint8_t commit() { -// PoolEntry* write_back = ::dataPool.getData( parameter_id, 1 ); -// if ( write_back != NULL ) { -// write_back->valid = true; -// *(write_back->address) = value; -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// return CHECKOUT_FAILED; -// } -// } -// uint8_t read() { -// PoolEntry* read_out = ::dataPool.getData( parameter_id, 1 ); -// if ( read_out != NULL ) { -// value = *(read_out->address); -// return HasReturnvaluesIF::RETURN_OK; -// } else { -// value = 0; -// return CHECKOUT_FAILED; -// } -// } -// uint32_t getParameterId() { return parameter_id; } -// bool isWritable() { return true; }; -// bool isValid() { return false; } -//}; - -#endif /* POOLVARIABLE_H_ */ diff --git a/datapool/PoolVariableIF.h b/datapool/PoolVariableIF.h index f47173df..cd15f744 100644 --- a/datapool/PoolVariableIF.h +++ b/datapool/PoolVariableIF.h @@ -1,71 +1,99 @@ -/* - * \file PoolVariableIF.h - * - * \brief This file contains the interface definition for pool variables. - * - * \date 10/17/2012 - * - * \author Bastian Baetz - */ - -#ifndef POOLVARIABLEIF_H_ -#define POOLVARIABLEIF_H_ +#ifndef FSFW_DATAPOOL_POOLVARIABLEIF_H_ +#define FSFW_DATAPOOL_POOLVARIABLEIF_H_ #include "../returnvalues/HasReturnvaluesIF.h" #include "../serialize/SerializeIF.h" /** - * \brief This interface is used to control local data pool variable representations. - * - * \details To securely handle data pool variables, all pool entries are locally managed by - * data pool variable access classes, which are called pool variables. To ensure a - * common state of a set of variables needed in a function, these local pool variables - * again are managed by other classes, e.g. the DataSet. This interface provides unified - * access to local pool variables for such manager classes. - * \ingroup data_pool + * @brief This interface is used to control data pool + * variable representations. + * @details + * To securely handle data pool variables, all pool entries are locally + * managed by data pool variable access classes, which are called pool + * variables. To ensure a common state of a set of variables needed in a + * function, these local pool variables again are managed by other classes, + * like the DataSet classes. This interface provides unified access to + * local pool variables for such manager classes. + * @author Bastian Baetz + * @ingroup data_pool */ class PoolVariableIF : public SerializeIF { - friend class DataSet; -protected: - /** - * \brief The commit call shall write back a newly calculated local value to the data pool. - */ - virtual ReturnValue_t commit() = 0; - /** - * \brief The read call shall read the value of this parameter from the data pool and store - * the content locally. - */ - virtual ReturnValue_t read() = 0; + friend class PoolDataSetBase; + friend class GlobDataSet; + friend class LocalPoolDataSetBase; public: - static const uint8_t VALID = 1; - static const uint8_t INVALID = 0; - static const uint32_t NO_PARAMETER = 0; + static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF; + static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0); + + static constexpr bool VALID = 1; + static constexpr bool INVALID = 0; + static constexpr uint32_t NO_PARAMETER = 0xffffffff; + enum ReadWriteMode_t { VAR_READ, VAR_WRITE, VAR_READ_WRITE }; /** - * \brief This is an empty virtual destructor, as it is proposed for C++ interfaces. + * @brief This is an empty virtual destructor, + * as it is proposed for C++ interfaces. */ - virtual ~PoolVariableIF() { - } + virtual ~PoolVariableIF() {} /** - * \brief This method returns if the variable is write-only, read-write or read-only. + * @brief This method returns if the variable is write-only, + * read-write or read-only. */ virtual ReadWriteMode_t getReadWriteMode() const = 0; /** - * \brief This operation shall return the data pool id of the variable. + * @brief This operation shall return the data pool id of the variable. */ virtual uint32_t getDataPoolId() const = 0; /** - * \brief With this call, the valid information of the variable is returned. + * @brief With this call, the valid information of the + * variable is returned. */ virtual bool isValid() const = 0; /** - * \brief With this call, the valid information of the variable is set. + * @brief With this call, the valid information of the variable is set. */ - virtual void setValid(uint8_t validity) = 0; + virtual void setValid(bool validity) = 0; + /** + * @brief The commit call shall write back a newly calculated local + * value to the data pool. + * @details + * It is assumed that these calls are implemented in a thread-safe manner! + */ + virtual ReturnValue_t commit(uint32_t lockTimeout) = 0; + /** + * @brief The read call shall read the value of this parameter from + * the data pool and store the content locally. + * @details + * It is assumbed that these calls are implemented in a thread-safe manner! + */ + virtual ReturnValue_t read(uint32_t lockTimeout) = 0; + +protected: + + /** + * @brief Same as commit with the difference that comitting will be + * performed without a lock + * @return + * This can be used if the lock protection is handled externally + * to avoid the overhead of locking and unlocking consecutively. + * Declared protected to avoid free public usage. + */ + virtual ReturnValue_t readWithoutLock() = 0; + /** + * @brief Same as commit with the difference that comitting will be + * performed without a lock + * @return + * This can be used if the lock protection is handled externally + * to avoid the overhead of locking and unlocking consecutively. + * Declared protected to avoid free public usage. + */ + virtual ReturnValue_t commitWithoutLock() = 0; }; -#endif /* POOLVARIABLEIF_H_ */ +using pool_rwm_t = PoolVariableIF::ReadWriteMode_t; + +#endif /* FSFW_DATAPOOL_POOLVARIABLEIF_H_ */ diff --git a/datapool/PoolVector.h b/datapool/PoolVector.h deleted file mode 100644 index d4ca0842..00000000 --- a/datapool/PoolVector.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * \file PoolVector.h - * - * \brief This file contains the PoolVector class, the header only class to handle data pool vectors. - * - * \date 10/23/2012 - * - * \author Bastian Baetz - */ - -#ifndef POOLVECTOR_H_ -#define POOLVECTOR_H_ - -#include "DataSetIF.h" -#include "PoolEntry.h" -#include "PoolVariableIF.h" -#include "../serialize/SerializeAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" - -/** - * \brief This is the access class for array-type data pool entries. - * - * \details To ensure safe usage of the data pool, operation is not done directly on the data pool - * entries, but on local copies. This class provides simple type- and length-safe access - * to vector-style data pool entries (i.e. entries with length > 1). - * The class can be instantiated as read-write and read only. - * It provides a commit-and-roll-back semantic, which means that no array entry in - * the data pool is changed until the commit call is executed. - * There are two template parameters: - * \tparam T This template parameter specifies the data type of an array entry. Currently, all - * plain data types are supported, but in principle any type is possible. - * \tparam vector_size This template parameter specifies the vector size of this entry. - * Using a template parameter for this is not perfect, but avoids dynamic memory allocation. - * \ingroup data_pool - */ -template -class PoolVector: public PoolVariableIF { -private: - /** - * \brief To access the correct data pool entry on read and commit calls, the data pool id - * is stored. - */ - uint32_t dataPoolId; - /** - * \brief The valid information as it was stored in the data pool is copied to this attribute. - */ - uint8_t valid; - /** - * \brief The information whether the class is read-write or read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - -protected: - /** - * \brief This is a call to read the array's values from the global data pool. - * \details When executed, this operation tries to fetch the pool entry with matching - * data pool id from the global data pool and copies all array values and the valid - * information to its local attributes. In case of a failure (wrong type, size or - * pool id not found), the variable is set to zero and invalid. - * The operation does NOT provide any mutual exclusive protection by itself. - */ - ReturnValue_t read() { - PoolEntry* read_out = ::dataPool.getData(this->dataPoolId, - vector_size); - if (read_out != NULL) { - this->valid = read_out->valid; - memcpy(this->value, read_out->address, read_out->getByteSize()); - - return HasReturnvaluesIF::RETURN_OK; - - } else { - memset(this->value, 0, vector_size * sizeof(T)); - sif::error << "PoolVector: read of DP Variable 0x" << std::hex - << dataPoolId << std::dec << " failed." << std::endl; - this->valid = INVALID; - return HasReturnvaluesIF::RETURN_FAILED; - } - } - /** - * \brief The commit call copies the array values back to the data pool. - * \details It checks type and size, as well as if the variable is writable. If so, - * the value is copied and the valid flag is automatically set to "valid". - * The operation does NOT provide any mutual exclusive protection by itself. - * - */ - ReturnValue_t commit() { - PoolEntry* write_back = ::dataPool.getData(this->dataPoolId, - vector_size); - if ((write_back != NULL) && (this->readWriteMode != VAR_READ)) { - write_back->valid = valid; - memcpy(write_back->address, this->value, write_back->getByteSize()); - return HasReturnvaluesIF::RETURN_OK; - } else { - return HasReturnvaluesIF::RETURN_FAILED; - } - } -public: - /** - * \brief This is the local copy of the data pool entry. - * \detials The user can work on this attribute - * just like he would on a local array of this type. - */ - T value[vector_size]; - /** - * \brief In the constructor, the variable can register itself in a DataSet (if not NULL is - * passed). - * \details It DOES NOT fetch the current value from the data pool, but sets the value - * attribute to default (0). The value is fetched within the read() operation. - * \param set_id This is the id in the global data pool this instance of the access class - * corresponds to. - * \param dataSet The data set in which the variable shall register itself. If NULL, - * the variable is not registered. - * \param setWritable If this flag is set to true, changes in the value attribute can be - * written back to the data pool, otherwise not. - */ - PoolVector(uint32_t set_id, DataSetIF* set, - ReadWriteMode_t setReadWriteMode) : - dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) { - memset(this->value, 0, vector_size * sizeof(T)); - if (set != NULL) { - set->registerVariable(this); - } - } - /** - * Copy ctor to copy classes containing Pool Variables. - */ -// PoolVector(const PoolVector& rhs) { -// PoolVector temp(rhs.dataPoolId, rhs.) -// memcpy(value, rhs.value, sizeof(T)*vector_size); -// } - /** - * \brief The classes destructor is empty. - * \details If commit() was not called, the local value is - * discarded and not written back to the data pool. - */ - ~PoolVector() { - } - ; - /** - * \brief The operation returns the number of array entries in this variable. - */ - uint8_t getSize() { - return vector_size; - } - /** - * \brief This operation returns the data pool id of the variable. - */ - uint32_t getDataPoolId() const { - return dataPoolId; - } - /** - * This operation sets the data pool id of the variable. - * The method is necessary to set id's of data pool member variables with bad initialization. - */ - void setDataPoolId(uint32_t poolId) { - dataPoolId = poolId; - } - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - ReadWriteMode_t getReadWriteMode() const { - return readWriteMode; - } - ; - /** - * \brief With this call, the valid information of the variable is returned. - */ - bool isValid() const { - if (valid != INVALID) - return true; - else - return false; - } - - void setValid(uint8_t valid) { - this->valid = valid; - } - - uint8_t getValid() { - return valid; - } - - T &operator [](int i) { - return value[i]; - } - - const T &operator [](int i) const { - return value[i]; - } - - PoolVector &operator=( - PoolVector newPoolVector) { - - for (uint16_t i = 0; i < vector_size; i++) { - this->value[i] = newPoolVector.value[i]; - } - return *this; - } - - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, - size_t maxSize, Endianness streamEndianness) const { - uint16_t i; - ReturnValue_t result; - for (i = 0; i < vector_size; i++) { - result = SerializeAdapter::serialize(&(value[i]), buffer, size, - maxSize, streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; - } - - virtual size_t getSerializedSize() const { - return vector_size * SerializeAdapter::getSerializedSize(value); - } - - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - uint16_t i; - ReturnValue_t result; - for (i = 0; i < vector_size; i++) { - result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, - streamEndianness); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - } - return result; - } -}; - -#endif /* POOLVECTOR_H_ */ diff --git a/datapool/SharedDataSetIF.h b/datapool/SharedDataSetIF.h new file mode 100644 index 00000000..b8d98794 --- /dev/null +++ b/datapool/SharedDataSetIF.h @@ -0,0 +1,14 @@ +#ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ +#define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ +#include "PoolDataSetIF.h" + +class SharedDataSetIF: public PoolDataSetIF { +public: + virtual ~SharedDataSetIF() {}; + +private: + virtual ReturnValue_t lockDataset(dur_millis_t mutexTimeout) = 0; + virtual ReturnValue_t unlockDataset() = 0; +}; + +#endif /* FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ */ diff --git a/datapool/ControllerSet.cpp b/datapoolglob/ControllerSet.cpp similarity index 79% rename from datapool/ControllerSet.cpp rename to datapoolglob/ControllerSet.cpp index 6339034c..54fc6e8c 100644 --- a/datapool/ControllerSet.cpp +++ b/datapoolglob/ControllerSet.cpp @@ -1,4 +1,4 @@ -#include "ControllerSet.h" +#include ControllerSet::ControllerSet() { diff --git a/datapoolglob/ControllerSet.h b/datapoolglob/ControllerSet.h new file mode 100644 index 00000000..5da11397 --- /dev/null +++ b/datapoolglob/ControllerSet.h @@ -0,0 +1,15 @@ +#ifndef FSFW_DATAPOOLGLOB_CONTROLLERSET_H_ +#define FSFW_DATAPOOLGLOB_CONTROLLERSET_H_ + +#include "../datapoolglob/GlobalDataSet.h" + +class ControllerSet :public GlobDataSet { +public: + ControllerSet(); + virtual ~ControllerSet(); + + virtual void setToDefault() = 0; + void setInvalid(); +}; + +#endif /* FSFW_DATAPOOLGLOB_CONTROLLERSET_H_ */ diff --git a/datapool/DataPoolAdmin.cpp b/datapoolglob/DataPoolAdmin.cpp similarity index 94% rename from datapool/DataPoolAdmin.cpp rename to datapoolglob/DataPoolAdmin.cpp index f298d530..6ede0841 100644 --- a/datapool/DataPoolAdmin.cpp +++ b/datapoolglob/DataPoolAdmin.cpp @@ -1,7 +1,8 @@ -#include "DataPool.h" #include "DataPoolAdmin.h" -#include "DataSet.h" +#include "GlobalDataSet.h" +#include "GlobalDataPool.h" #include "PoolRawAccess.h" + #include "../ipc/CommandMessage.h" #include "../ipc/QueueFactory.h" #include "../parameters/ParameterMessage.h" @@ -40,9 +41,9 @@ ReturnValue_t DataPoolAdmin::executeAction(ActionId_t actionId, uint8_t valid = data[4]; - uint32_t poolId = ::dataPool.PIDToDataPoolId(address); + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); - DataSet mySet; + GlobDataSet mySet; PoolRawAccess variable(poolId, 0, &mySet, PoolVariableIF::VAR_READ_WRITE); ReturnValue_t status = mySet.read(); if (status != RETURN_OK) { @@ -92,9 +93,9 @@ void DataPoolAdmin::handleCommand() { ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, const uint8_t* data, size_t size, uint8_t** dataPointer) { - uint32_t poolId = ::dataPool.PIDToDataPoolId(address); - uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address); - DataSet testSet; + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); + uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); + GlobDataSet testSet; PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ); ReturnValue_t status = testSet.read(); @@ -113,7 +114,7 @@ ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, const uint8_t* readPosition = data; for (; size > 0; size -= typeSize) { - DataSet rawSet; + GlobDataSet rawSet; PoolRawAccess variable(poolId, arrayIndex, &rawSet, PoolVariableIF::VAR_READ_WRITE); status = rawSet.read(); @@ -131,9 +132,9 @@ ReturnValue_t DataPoolAdmin::handleMemoryLoad(uint32_t address, ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, size_t size, uint8_t** dataPointer, uint8_t* copyHere) { - uint32_t poolId = ::dataPool.PIDToDataPoolId(address); - uint8_t arrayIndex = ::dataPool.PIDToArrayIndex(address); - DataSet testSet; + uint32_t poolId = glob::dataPool.PIDToDataPoolId(address); + uint8_t arrayIndex = glob::dataPool.PIDToArrayIndex(address); + GlobDataSet testSet; PoolRawAccess varToGetSize(poolId, arrayIndex, &testSet, PoolVariableIF::VAR_READ); ReturnValue_t status = testSet.read(); @@ -146,7 +147,7 @@ ReturnValue_t DataPoolAdmin::handleMemoryDump(uint32_t address, size_t size, } uint8_t* ptrToCopy = copyHere; for (; size > 0; size -= typeSize) { - DataSet rawSet; + GlobDataSet rawSet; PoolRawAccess variable(poolId, arrayIndex, &rawSet, PoolVariableIF::VAR_READ); status = rawSet.read(); diff --git a/datapool/DataPoolAdmin.h b/datapoolglob/DataPoolAdmin.h similarity index 92% rename from datapool/DataPoolAdmin.h rename to datapoolglob/DataPoolAdmin.h index e2d1e9e1..d8871b65 100644 --- a/datapool/DataPoolAdmin.h +++ b/datapoolglob/DataPoolAdmin.h @@ -1,15 +1,17 @@ -#ifndef DATAPOOLADMIN_H_ -#define DATAPOOLADMIN_H_ +#ifndef FSFW_DATAPOOLGLOB_DATAPOOLADMIN_H_ +#define FSFW_DATAPOOLGLOB_DATAPOOLADMIN_H_ + +#include "DataPoolParameterWrapper.h" -#include "../memory/MemoryHelper.h" -#include "../action/HasActionsIF.h" -#include "../action/SimpleActionHelper.h" #include "../objectmanager/SystemObject.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../tasks/ExecutableObjectIF.h" -#include "../parameters/ReceivesParameterMessagesIF.h" -#include "DataPoolParameterWrapper.h" +#include "../action/HasActionsIF.h" #include "../ipc/MessageQueueIF.h" +#include "../parameters/ReceivesParameterMessagesIF.h" +#include "../action/SimpleActionHelper.h" +#include "../memory/MemoryHelper.h" + class DataPoolAdmin: public HasActionsIF, public ExecutableObjectIF, @@ -55,4 +57,4 @@ private: Command_t initialCommand); }; -#endif /* DATAPOOLADMIN_H_ */ +#endif /* FSFW_DATAPOOLGLOB_DATAPOOLADMIN_H_ */ diff --git a/datapool/DataPoolParameterWrapper.cpp b/datapoolglob/DataPoolParameterWrapper.cpp similarity index 95% rename from datapool/DataPoolParameterWrapper.cpp rename to datapoolglob/DataPoolParameterWrapper.cpp index 79367405..3a57d90d 100644 --- a/datapool/DataPoolParameterWrapper.cpp +++ b/datapoolglob/DataPoolParameterWrapper.cpp @@ -1,10 +1,8 @@ -#include "DataPoolParameterWrapper.h" - -//for returncodes +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/DataPoolParameterWrapper.h" +#include "../datapoolglob/PoolRawAccess.h" #include "../parameters/HasParametersIF.h" -#include "DataSet.h" -#include "PoolRawAccess.h" DataPoolParameterWrapper::DataPoolParameterWrapper() : type(Type::UNKNOWN_TYPE), rows(0), columns(0), poolId( @@ -20,7 +18,7 @@ ReturnValue_t DataPoolParameterWrapper::set(uint8_t domainId, uint16_t parameterId) { poolId = (domainId << 16) + parameterId; - DataSet mySet; + GlobDataSet mySet; PoolRawAccess raw(poolId, 0, &mySet, PoolVariableIF::VAR_READ); ReturnValue_t status = mySet.read(); if (status != HasReturnvaluesIF::RETURN_OK) { @@ -57,7 +55,7 @@ ReturnValue_t DataPoolParameterWrapper::serialize(uint8_t** buffer, } for (uint8_t index = 0; index < rows; index++){ - DataSet mySet; + GlobDataSet mySet; PoolRawAccess raw(poolId, index, &mySet,PoolVariableIF::VAR_READ); mySet.read(); result = raw.serialize(buffer,size,maxSize,streamEndianness); @@ -94,7 +92,7 @@ ReturnValue_t DataPoolParameterWrapper::deSerializeData(uint8_t startingRow, for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) { - DataSet mySet; + GlobDataSet mySet; PoolRawAccess raw(poolId, startingRow + fromRow, &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); diff --git a/datapool/DataPoolParameterWrapper.h b/datapoolglob/DataPoolParameterWrapper.h similarity index 100% rename from datapool/DataPoolParameterWrapper.h rename to datapoolglob/DataPoolParameterWrapper.h diff --git a/datapoolglob/GlobalDataPool.cpp b/datapoolglob/GlobalDataPool.cpp new file mode 100644 index 00000000..afb27b77 --- /dev/null +++ b/datapoolglob/GlobalDataPool.cpp @@ -0,0 +1,133 @@ +#include "../datapoolglob/GlobalDataPool.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../ipc/MutexFactory.h" + +GlobalDataPool::GlobalDataPool( + void(*initFunction)(GlobPoolMap* pool_map)) { + mutex = MutexFactory::instance()->createMutex(); + if (initFunction != NULL ) { + initFunction( &this->globDataPool ); + } +} + +GlobalDataPool::~GlobalDataPool() { + MutexFactory::instance()->deleteMutex(mutex); + for(GlobPoolMapIter it = this->globDataPool.begin(); + it != this->globDataPool.end(); ++it ) + { + delete it->second; + } +} + +// The function checks PID, type and array length before returning a copy of +// the PoolEntry. In failure case, it returns a temp-Entry with size 0 and NULL-ptr. +template PoolEntry* GlobalDataPool::getData( uint32_t data_pool_id, + uint8_t sizeOrPosition ) { + GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); + if ( it != this->globDataPool.end() ) { + PoolEntry* entry = dynamic_cast< PoolEntry* >( it->second ); + if (entry != nullptr ) { + if ( sizeOrPosition <= entry->length ) { + return entry; + } + } + } + return nullptr; +} + +PoolEntryIF* GlobalDataPool::getRawData( uint32_t data_pool_id ) { + GlobPoolMapIter it = this->globDataPool.find( data_pool_id ); + if ( it != this->globDataPool.end() ) { + return it->second; + } else { + return nullptr; + } +} + +ReturnValue_t GlobalDataPool::unlockDataPool() { + ReturnValue_t status = mutex->unlockMutex(); + if(status != RETURN_OK) { + sif::error << "DataPool::DataPool: unlock of mutex failed with" + " error code: " << status << std::endl; + } + return status; +} + +ReturnValue_t GlobalDataPool::lockDataPool(uint32_t timeoutMs) { + ReturnValue_t status = mutex->lockMutex(MutexIF::TimeoutType::WAITING, + timeoutMs); + if(status != RETURN_OK) { + sif::error << "DataPool::DataPool: lock of mutex failed " + "with error code: " << status << std::endl; + } + return status; +} + +void GlobalDataPool::print() { + sif::debug << "DataPool contains: " << std::endl; + std::map::iterator dataPoolIt; + dataPoolIt = this->globDataPool.begin(); + while( dataPoolIt != this->globDataPool.end() ) { + sif::debug << std::hex << dataPoolIt->first << std::dec << " |"; + dataPoolIt->second->print(); + dataPoolIt++; + } +} + +uint32_t GlobalDataPool::PIDToDataPoolId(uint32_t parameter_id) { + return (parameter_id >> 8) & 0x00FFFFFF; +} + +uint8_t GlobalDataPool::PIDToArrayIndex(uint32_t parameter_id) { + return (parameter_id & 0x000000FF); +} + +uint32_t GlobalDataPool::poolIdAndPositionToPid(uint32_t poolId, uint8_t index) { + return (poolId << 8) + index; +} + + +//SHOULDDO: Do we need a mutex lock here... I don't think so, +//as we only check static const values of elements in a list that do not change. +//there is no guarantee in the standard, but it seems to me that the implementation is safe -UM +ReturnValue_t GlobalDataPool::getType(uint32_t parameter_id, Type* type) { + GlobPoolMapIter it = this->globDataPool.find( PIDToDataPoolId(parameter_id)); + if ( it != this->globDataPool.end() ) { + *type = it->second->getType(); + return RETURN_OK; + } else { + *type = Type::UNKNOWN_TYPE; + return RETURN_FAILED; + } +} + +bool GlobalDataPool::exists(uint32_t parameterId) { + uint32_t poolId = PIDToDataPoolId(parameterId); + uint32_t index = PIDToArrayIndex(parameterId); + GlobPoolMapIter it = this->globDataPool.find( poolId ); + if (it != globDataPool.end()) { + if (it->second->getSize() >= index) { + return true; + } + } + return false; +} + +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size ); +template PoolEntry* GlobalDataPool::getData( + uint32_t data_pool_id, uint8_t size); diff --git a/datapoolglob/GlobalDataPool.h b/datapoolglob/GlobalDataPool.h new file mode 100644 index 00000000..ce5b132c --- /dev/null +++ b/datapoolglob/GlobalDataPool.h @@ -0,0 +1,149 @@ +#ifndef GLOBALDATAPOOL_H_ +#define GLOBALDATAPOOL_H_ + +#include "../datapool/PoolEntry.h" +#include "../globalfunctions/Type.h" +#include "../ipc/MutexIF.h" +#include + +/** + * @defgroup data_pool Global data pool + * This is the group, where all classes associated with global + * data pool handling belong to. + * This includes classes to access Data Pool variables. + */ + +/** + * Typedefs for the global pool representations + */ +using GlobPoolMap = std::map; +using GlobPoolMapIter = GlobPoolMap::iterator; + +/** + * @brief This class represents the OBSW global data-pool. + * + * @details + * All variables are registered and space is allocated in an initialization + * function, which is passed do the constructor. Space for the variables is + * allocated on the heap (with a new call). + * + * The data is found by a data pool id, which uniquely represents a variable. + * Data pool variables should be used with a blackboard logic in mind, + * which means read data is valid (if flagged so), + * but not necessarily up-to-date. + * + * Variables are either single values or arrays. + * @author Bastian Baetz + * @ingroup data_pool + */ +class GlobalDataPool : public HasReturnvaluesIF { +private: + /** + * @brief This is the actual data pool itself. + * @details It is represented by a map with the data pool id as index + * and a pointer to a single PoolEntry as value. + */ + GlobPoolMap globDataPool; + + /** + * @brief The mutex is created in the constructor and makes + * access mutual exclusive. + * @details Locking and unlocking the pool is only done by the DataSet class. + */ + MutexIF* mutex; +public: + /** + * @brief In the classes constructor, + * the passed initialization function is called. + * @details + * To enable filling the pool, a pointer to the map is passed, + * allowing direct access to the pool's content. + * On runtime, adding or removing variables is forbidden. + */ + GlobalDataPool( void ( *initFunction )( GlobPoolMap* pool_map ) ); + + /** + * @brief The destructor iterates through the data_pool map and + * calls all entries destructors to clean up the heap. + */ + ~GlobalDataPool(); + + /** + * @brief This is the default call to access the pool. + * @details + * A pointer to the PoolEntry object is returned. + * The call checks data pool id, type and array size. + * Returns NULL in case of failure. + * @param data_pool_id The data pool id to search. + * @param sizeOrPosition The array size (not byte size!) of the pool entry, + * or the position the user wants to read. + * If smaller than the entry size, everything's ok. + */ + template PoolEntry* getData( uint32_t data_pool_id, + uint8_t sizeOrPosition ); + + /** + * @brief An alternative call to get a data pool entry in case the type is not implicitly known + * (i.e. in Housekeeping Telemetry). + * @details It returns a basic interface and does NOT perform + * a size check. The caller has to assure he does not copy too much data. + * Returns NULL in case the entry is not found. + * @param data_pool_id The data pool id to search. + */ + PoolEntryIF* getRawData( uint32_t data_pool_id ); + /** + * @brief This is a small helper function to facilitate locking the global data pool. + * @details It fetches the pool's mutex id and tries to acquire the mutex. + */ + ReturnValue_t lockDataPool(uint32_t timeoutMs = MutexIF::BLOCKING); + /** + * @brief This is a small helper function to facilitate unlocking the global data pool. + * @details It fetches the pool's mutex id and tries to free the mutex. + */ + ReturnValue_t unlockDataPool(); + /** + * @brief The print call is a simple debug method. + * @details It prints the current content of the data pool. + * It iterates through the data_pool map and calls each entry's print() method. + */ + void print(); + /** + * Extracts the data pool id from a SCOS 2000 PID. + * @param parameter_id The passed Parameter ID. + * @return The data pool id as used within the OBSW. + */ + static uint32_t PIDToDataPoolId( uint32_t parameter_id ); + /** + * Extracts an array index out of a SCOS 2000 PID. + * @param parameter_id The passed Parameter ID. + * @return The index of the corresponding data pool entry. + */ + static uint8_t PIDToArrayIndex( uint32_t parameter_id ); + /** + * Retransforms a data pool id and an array index to a SCOS 2000 PID. + */ + static uint32_t poolIdAndPositionToPid( uint32_t poolId, uint8_t index ); + + /** + * Method to return the type of a pool variable. + * @param parameter_id A parameterID (not pool id) of a DP member. + * @param type Returns the type or TYPE::UNKNOWN_TYPE + * @return RETURN_OK if parameter exists, RETURN_FAILED else. + */ + ReturnValue_t getType( uint32_t parameter_id, Type* type ); + + /** + * Method to check if a PID exists. Does not lock, as there's no + * possibility to alter the list that is checked during run-time. + * @param parameterId The PID (not pool id!) of a parameter. + * @return true if exists, false else. + */ + bool exists(uint32_t parameterId); +}; + +//We assume someone globally instantiates a DataPool. +namespace glob { +extern GlobalDataPool dataPool; +} + +#endif /* DATAPOOL_H_ */ diff --git a/datapoolglob/GlobalDataSet.cpp b/datapoolglob/GlobalDataSet.cpp new file mode 100644 index 00000000..1e99f805 --- /dev/null +++ b/datapoolglob/GlobalDataSet.cpp @@ -0,0 +1,48 @@ +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +GlobDataSet::GlobDataSet(): PoolDataSetBase( + reinterpret_cast(®isteredVariables), + DATA_SET_MAX_SIZE) {} + +// Don't do anything with your variables, they are dead already! +// (Destructor is already called) +GlobDataSet::~GlobDataSet() {} + +ReturnValue_t GlobDataSet::commit(bool valid, uint32_t lockTimeout) { + setEntriesValid(valid); + setSetValid(valid); + return commit(lockTimeout); +} + +ReturnValue_t GlobDataSet::commit(uint32_t lockTimeout) { + return PoolDataSetBase::commit(lockTimeout); +} + +bool GlobDataSet::isValid() const { + return this->valid; +} + +ReturnValue_t GlobDataSet::unlockDataPool() { + return glob::dataPool.unlockDataPool(); +} + +ReturnValue_t GlobDataSet::lockDataPool(uint32_t timeoutMs) { + return glob::dataPool.lockDataPool(timeoutMs); +} + +void GlobDataSet::setEntriesValid(bool valid) { + for (uint16_t count = 0; count < fillCount; count++) { + if (registeredVariables[count]->getReadWriteMode() + != PoolVariableIF::VAR_READ) { + registeredVariables[count]->setValid(valid); + } + } +} + +void GlobDataSet::setSetValid(bool valid) { + this->valid = valid; +} + + diff --git a/datapoolglob/GlobalDataSet.h b/datapoolglob/GlobalDataSet.h new file mode 100644 index 00000000..2f0edbd5 --- /dev/null +++ b/datapoolglob/GlobalDataSet.h @@ -0,0 +1,98 @@ +#ifndef FRAMEWORK_DATAPOOLGLOB_DATASET_H_ +#define FRAMEWORK_DATAPOOLGLOB_DATASET_H_ + +#include "../datapool/PoolDataSetBase.h" + +/** + * @brief The DataSet class manages a set of locally checked out variables + * for the global data pool. + * @details + * This class uses the read-commit() semantic provided by the DataSetBase class. + * It extends the base class by using the global data pool, + * having a valid state and implementing lock und unlock calls for the global + * datapool. + * + * For more information on how this class works, see the DataSetBase + * documentation. + * @author Bastian Baetz + * @ingroup data_pool + */ +class GlobDataSet: public PoolDataSetBase { +public: + + /** + * @brief Creates an empty GlobDataSet. Use registerVariable or + * supply a pointer to this dataset to PoolVariable + * initializations to register pool variables. + */ + GlobDataSet(); + + /** + * @brief The destructor automatically manages writing the valid + * information of variables. + * @details + * In case the data set was read out, but not committed(indicated by state), + * the destructor parses all variables that are still registered to the set. + * For each, the valid flag in the data pool is set to "invalid". + */ + ~GlobDataSet(); + + /** + * Variant of method above which sets validity of all elements of the set. + * @param valid Validity information from PoolVariableIF. + * @return - @c RETURN_OK if all variables were read successfully. + * - @c COMMITING_WITHOUT_READING if set was not read yet and + * contains non write-only variables + */ + ReturnValue_t commit(bool valid, uint32_t lockTimeout = MutexIF::BLOCKING); + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + + /** + * Set all entries + * @param valid + */ + void setSetValid(bool valid); + + bool isValid() const override; + + /** + * Set the valid information of all variables contained in the set which + * are not read-only + * + * @param valid Validity information from PoolVariableIF. + */ + void setEntriesValid(bool valid); + + //!< This definition sets the maximum number of variables to + //! register in one DataSet. + static const uint8_t DATA_SET_MAX_SIZE = 63; + +private: + /** + * If the valid state of a dataset is always relevant to the whole + * data set we can use this flag. + */ + bool valid = false; + + /** + * @brief This is a small helper function to facilitate locking + * the global data pool. + * @details + * It makes use of the lockDataPool method offered by the DataPool class. + */ + ReturnValue_t lockDataPool(uint32_t timeoutMs) override; + /** + * @brief This is a small helper function to facilitate + * unlocking the global data pool + * @details + * It makes use of the freeDataPoolLock method offered by the DataPool class. + */ + ReturnValue_t unlockDataPool() override; + + void handleAlreadyReadDatasetCommit(); + ReturnValue_t handleUnreadDatasetCommit(); + + PoolVariableIF* registeredVariables[DATA_SET_MAX_SIZE]; +}; + +#endif /* FRAMEWORK_DATAPOOLGLOB_DATASET_H_ */ diff --git a/datapoolglob/GlobalPoolVariable.h b/datapoolglob/GlobalPoolVariable.h new file mode 100644 index 00000000..a995bfaf --- /dev/null +++ b/datapoolglob/GlobalPoolVariable.h @@ -0,0 +1,213 @@ +#ifndef GLOBALPOOLVARIABLE_H_ +#define GLOBALPOOLVARIABLE_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapool/PoolVariableIF.h" +#include "../datapool/PoolEntry.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +template class PoolVarList; + + +/** + * @brief This is the access class for non-array data pool entries. + * + * @details + * To ensure safe usage of the data pool, operation is not done directly + * on the data pool entries, but on local copies. This class provides simple + * type-safe access to single data pool entries (i.e. entries with length = 1). + * The class can be instantiated as read-write and read only. + * It provides a commit-and-roll-back semantic, which means that the + * variable's value in the data pool is not changed until the + * commit call is executed. + * @tparam T The template parameter sets the type of the variable. + * Currently, all plain data types are supported, but in principle + * any type is possible. + * @ingroup data_pool + */ +template +class GlobPoolVar: public PoolVariableIF { + template friend class PoolVarList; + static_assert(not std::is_same::value, + "Do not use boolean for the PoolEntry type, use uint8_t instead!" + "There is no boolean type in CCSDS."); +public: + /** + * @brief In the constructor, the variable can register itself in a + * DataSet (if nullptr is not passed). + * @details + * It DOES NOT fetch the current value from the data pool, but + * sets the value attribute to default (0). + * The value is fetched within the read() operation. + * @param set_id This is the id in the global data pool + * this instance of the access class corresponds to. + * @param dataSet The data set in which the variable shall register + * itself. If NULL, the variable is not registered. + * @param setWritable If this flag is set to true, changes in the value + * attribute can be written back to the data pool, otherwise not. + */ + GlobPoolVar(uint32_t set_id, DataSetIF* dataSet, + ReadWriteMode_t setReadWriteMode); + + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a simple local variable. + */ + T value = 0; + + /** + * @brief Copy ctor to copy classes containing Pool Variables. + * (Robin): This only copies member variables, which is done + * by the default copy ctor. maybe we can ommit this ctor? + */ + GlobPoolVar(const GlobPoolVar& rhs); + + /** + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~GlobPoolVar() {} + + /** + * @brief This is a call to read the value from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t read(uint32_t lockTimeout) override; + /** + * @brief The commit call writes back the variable's value to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The operation does NOT provide any mutual exclusive protection by itself. + * The commit call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(uint32_t lockTimeout) override; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool is stored. + */ + uint32_t dataPoolId; + + /** + * @brief The valid information as it was stored in the data pool is + * copied to this attribute. + */ + uint8_t valid; + + /** + * @brief The information whether the class is read-write or read-only + * is stored here. + */ + pool_rwm_t readWriteMode; + + /** + * Empty ctor for List initialization + */ + GlobPoolVar(); +public: + /** + * \brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const override; + + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const override; + /** + * This operation sets the data pool id of the variable. + * The method is necessary to set id's of data pool member variables with bad initialization. + */ + void setDataPoolId(uint32_t poolId); + + /** + * \brief With this call, the valid information of the variable is returned. + */ + bool isValid() const override; + + uint8_t getValid(); + + void setValid(bool valid) override; + + operator T() { + return value; + } + + operator T() const { + return value; + } + + GlobPoolVar &operator=(T newValue) { + value = newValue; + return *this; + } + + GlobPoolVar &operator=(GlobPoolVar newPoolVariable) { + value = newPoolVariable.value; + return *this; + } + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, + SerializeIF::Endianness streamEndianness) const override { + return SerializeAdapter::serialize(&value, buffer, size, max_size, + streamEndianness); + } + + virtual size_t getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&value); + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&value, buffer, size, + streamEndianness); + } +}; + +#include "../datapoolglob/GlobalPoolVariable.tpp" + +typedef GlobPoolVar gp_bool_t; +typedef GlobPoolVar gp_uint8_t; +typedef GlobPoolVar gp_uint16_t; +typedef GlobPoolVar gp_uint32_t; +typedef GlobPoolVar gp_int8_t; +typedef GlobPoolVar gp_int16_t; +typedef GlobPoolVar gp_int32_t; +typedef GlobPoolVar gp_float_t; +typedef GlobPoolVar gp_double_t; + +#endif /* POOLVARIABLE_H_ */ diff --git a/datapoolglob/GlobalPoolVariable.tpp b/datapoolglob/GlobalPoolVariable.tpp new file mode 100644 index 00000000..d61d605d --- /dev/null +++ b/datapoolglob/GlobalPoolVariable.tpp @@ -0,0 +1,117 @@ +#ifndef GLOBALPOOLVARIABLE_TPP_ +#define GLOBALPOOLVARIABLE_TPP_ + +template +inline GlobPoolVar::GlobPoolVar(uint32_t set_id, + DataSetIF* dataSet, ReadWriteMode_t setReadWriteMode): + dataPoolId(set_id), valid(PoolVariableIF::INVALID), + readWriteMode(setReadWriteMode) +{ + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +template +inline ReturnValue_t GlobPoolVar::read(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +template +inline ReturnValue_t GlobPoolVar::commit(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = commitWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +template +inline ReturnValue_t GlobPoolVar::readWithoutLock() { + PoolEntry* read_out = glob::dataPool.getData(dataPoolId, 1); + if (read_out != NULL) { + valid = read_out->valid; + value = *(read_out->address); + return HasReturnvaluesIF::RETURN_OK; + } else { + value = 0; + valid = false; + sif::error << "PoolVariable: read of DP Variable 0x" << std::hex + << dataPoolId << std::dec << " failed." << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline ReturnValue_t GlobPoolVar::commitWithoutLock() { + PoolEntry* write_back = glob::dataPool.getData(dataPoolId, 1); + if ((write_back != NULL) && (readWriteMode != VAR_READ)) { + write_back->valid = valid; + *(write_back->address) = value; + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline GlobPoolVar::GlobPoolVar(): + dataPoolId(PoolVariableIF::NO_PARAMETER), + valid(PoolVariableIF::INVALID), + readWriteMode(VAR_READ), value(0) {} + +template +inline GlobPoolVar::GlobPoolVar(const GlobPoolVar& rhs) : + dataPoolId(rhs.dataPoolId), valid(rhs.valid), readWriteMode( + rhs.readWriteMode), value(rhs.value) {} + +template +inline pool_rwm_t GlobPoolVar::getReadWriteMode() const { + return readWriteMode; +} + +template +inline uint32_t GlobPoolVar::getDataPoolId() const { + return dataPoolId; +} + +template +inline void GlobPoolVar::setDataPoolId(uint32_t poolId) { + dataPoolId = poolId; +} + +template +inline bool GlobPoolVar::isValid() const { + if (valid) + return true; + else + return false; +} + +template +inline uint8_t GlobPoolVar::getValid() { + return valid; +} + +template +inline void GlobPoolVar::setValid(bool valid) { + this->valid = valid; +} + +#endif diff --git a/datapoolglob/GlobalPoolVector.h b/datapoolglob/GlobalPoolVector.h new file mode 100644 index 00000000..0f5daacd --- /dev/null +++ b/datapoolglob/GlobalPoolVector.h @@ -0,0 +1,185 @@ +#ifndef FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_H_ +#define FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntry.h" +#include "../datapool/PoolVariableIF.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + +/** + * @brief This is the access class for array-type data pool entries. + * + * @details + * To ensure safe usage of the data pool, operation is not done directly on the + * data pool entries, but on local copies. This class provides simple type- + * and length-safe access to vector-style data pool entries (i.e. entries with + * length > 1). The class can be instantiated as read-write and read only. + * + * It provides a commit-and-roll-back semantic, which means that no array + * entry in the data pool is changed until the commit call is executed. + * There are two template parameters: + * @tparam T + * This template parameter specifies the data type of an array entry. Currently, + * all plain data types are supported, but in principle any type is possible. + * @tparam vector_size + * This template parameter specifies the vector size of this entry. Using a + * template parameter for this is not perfect, but avoids + * dynamic memory allocation. + * @ingroup data_pool + */ +template +class GlobPoolVector: public PoolVariableIF { +public: + /** + * @brief In the constructor, the variable can register itself in a + * DataSet (if no nullptr is passed). + * @details + * It DOES NOT fetch the current value from the data pool, but sets the + * value attribute to default (0). The value is fetched within the + * read() operation. + * @param set_id + * This is the id in the global data pool this instance of the access + * class corresponds to. + * @param dataSet + * The data set in which the variable shall register itself. If nullptr, + * the variable is not registered. + * @param setWritable + * If this flag is set to true, changes in the value attribute can be + * written back to the data pool, otherwise not. + */ + GlobPoolVector(uint32_t set_id, DataSetIF* set, + ReadWriteMode_t setReadWriteMode); + + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a local array of this type. + */ + T value[vectorSize]; + /** + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~GlobPoolVector() {}; + /** + * @brief The operation returns the number of array entries + * in this variable. + */ + uint8_t getSize() { + return vectorSize; + } + /** + * @brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const { + return dataPoolId; + } + /** + * @brief This operation sets the data pool id of the variable. + * @details + * The method is necessary to set id's of data pool member variables + * with bad initialization. + */ + void setDataPoolId(uint32_t poolId) { + dataPoolId = poolId; + } + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const { + return readWriteMode; + } + + + /** + * @brief With this call, the valid information of the variable is returned. + */ + bool isValid() const { + if (valid != INVALID) + return true; + else + return false; + } + void setValid(bool valid) {this->valid = valid;} + uint8_t getValid() {return valid;} + + T &operator [](int i) {return value[i];} + const T &operator [](int i) const {return value[i];} + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t max_size, Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override; + + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies all array values + * and the valid information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected by a lock of the global data pool. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief The commit call copies the array values back to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The commit call is protected by a lock of the global data pool. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + +private: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool id is stored. + */ + uint32_t dataPoolId; + /** + * @brief The valid information as it was stored in the data pool + * is copied to this attribute. + */ + uint8_t valid; + /** + * @brief The information whether the class is read-write or + * read-only is stored here. + */ + ReadWriteMode_t readWriteMode; +}; + +#include "../datapoolglob/GlobalPoolVector.tpp" + +template +using gp_vec_t = GlobPoolVector; + +#endif /* FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_H_ */ diff --git a/datapoolglob/GlobalPoolVector.tpp b/datapoolglob/GlobalPoolVector.tpp new file mode 100644 index 00000000..013a682a --- /dev/null +++ b/datapoolglob/GlobalPoolVector.tpp @@ -0,0 +1,117 @@ +#ifndef FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_TPP_ +#define FSFW_DATAPOOLGLOB_GLOBALPOOLVECTOR_TPP_ + + +template +inline GlobPoolVector::GlobPoolVector(uint32_t set_id, + DataSetIF* set, ReadWriteMode_t setReadWriteMode) : + dataPoolId(set_id), valid(false), readWriteMode(setReadWriteMode) { + memset(this->value, 0, vectorSize * sizeof(T)); + if (set != nullptr) { + set->registerVariable(this); + } +} + + +template +inline ReturnValue_t GlobPoolVector::read(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +template +inline ReturnValue_t GlobPoolVector::commit( + uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = commitWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +template +inline ReturnValue_t GlobPoolVector::readWithoutLock() { + PoolEntry* read_out = glob::dataPool.getData(this->dataPoolId, + vectorSize); + if (read_out != nullptr) { + this->valid = read_out->valid; + memcpy(this->value, read_out->address, read_out->getByteSize()); + + return HasReturnvaluesIF::RETURN_OK; + + } else { + memset(this->value, 0, vectorSize * sizeof(T)); + sif::error << "PoolVector: Read of DP Variable 0x" << std::hex + << std::setw(8) << std::setfill('0') << dataPoolId << + std::dec << " failed." << std::endl; + this->valid = INVALID; + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline ReturnValue_t GlobPoolVector::commitWithoutLock() { + PoolEntry* writeBack = glob::dataPool.getData(this->dataPoolId, + vectorSize); + if ((writeBack != nullptr) && (this->readWriteMode != VAR_READ)) { + writeBack->valid = valid; + memcpy(writeBack->address, this->value, writeBack->getByteSize()); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +template +inline ReturnValue_t GlobPoolVector::serialize(uint8_t** buffer, + size_t* size, size_t max_size, + SerializeIF::Endianness streamEndianness) const { + uint16_t i; + ReturnValue_t result; + for (i = 0; i < vectorSize; i++) { + result = SerializeAdapter::serialize(&(value[i]), buffer, size, + max_size, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +template +inline size_t GlobPoolVector::getSerializedSize() const { + return vectorSize * SerializeAdapter::getSerializedSize(value); +} + +template +inline ReturnValue_t GlobPoolVector::deSerialize( + const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + uint16_t i; + ReturnValue_t result; + for (i = 0; i < vectorSize; i++) { + result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; +} + +#endif diff --git a/datapool/PIDReader.h b/datapoolglob/PIDReader.h similarity index 77% rename from datapool/PIDReader.h rename to datapoolglob/PIDReader.h index 3b38b51d..9431e1d4 100644 --- a/datapool/PIDReader.h +++ b/datapoolglob/PIDReader.h @@ -1,9 +1,9 @@ #ifndef PIDREADER_H_ #define PIDREADER_H_ -#include "DataPool.h" -#include "DataSetIF.h" -#include "PoolEntry.h" -#include "PoolVariableIF.h" +#include "../datapool/DataSetIF.h" +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapool/PoolEntry.h" +#include "../datapool/PoolVariableIF.h" #include "../serialize/SerializeAdapter.h" #include "../serviceinterface/ServiceInterfaceStream.h" @@ -15,10 +15,10 @@ class PIDReader: public PoolVariableIF { protected: uint32_t parameterId; uint8_t valid; - ReturnValue_t read() { - uint8_t arrayIndex = DataPool::PIDToArrayIndex(parameterId); - PoolEntry *read_out = ::dataPool.getData( - DataPool::PIDToDataPoolId(parameterId), arrayIndex); + ReturnValue_t readWithoutLock() { + uint8_t arrayIndex = GlobalDataPool::PIDToArrayIndex(parameterId); + PoolEntry *read_out = glob::dataPool.getData( + GlobalDataPool::PIDToDataPoolId(parameterId), arrayIndex); if (read_out != NULL) { valid = read_out->valid; value = read_out->address[arrayIndex]; @@ -36,9 +36,13 @@ protected: * Reason is the possibility to access a single DP vector element, but if we commit, * we set validity of the whole vector. */ - ReturnValue_t commit() { + ReturnValue_t commit(uint32_t lockTimeout) override { return HasReturnvaluesIF::RETURN_FAILED; } + ReturnValue_t commitWithoutLock() override { + return HasReturnvaluesIF::RETURN_FAILED; + } + /** * Empty ctor for List initialization */ @@ -72,6 +76,19 @@ public: } } + ReturnValue_t read(uint32_t lockTimeout) override { + ReturnValue_t result = glob::dataPool.lockDataPool(); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "PIDReader::read: Could not unlock data pool!" + << std::endl; + } + return result; + } /** * Copy ctor to copy classes containing Pool Variables. */ @@ -89,7 +106,7 @@ public: * \brief This operation returns the data pool id of the variable. */ uint32_t getDataPoolId() const { - return DataPool::PIDToDataPoolId(parameterId); + return GlobalDataPool::PIDToDataPoolId(parameterId); } uint32_t getParameterId() const { return parameterId; @@ -114,7 +131,7 @@ public: return valid; } - void setValid(uint8_t valid) { + void setValid(bool valid) { this->valid = valid; } diff --git a/datapool/PIDReaderList.h b/datapoolglob/PIDReaderList.h similarity index 68% rename from datapool/PIDReaderList.h rename to datapoolglob/PIDReaderList.h index 1f6aa99c..ae99f3aa 100644 --- a/datapool/PIDReaderList.h +++ b/datapoolglob/PIDReaderList.h @@ -1,8 +1,8 @@ -#ifndef FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ -#define FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ +#ifndef FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ +#define FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ -#include "PIDReader.h" -#include "PoolVariableIF.h" +#include "../datapool/PoolVariableIF.h" +#include "../datapoolglob/PIDReader.h" template class PIDReaderList { private: @@ -24,4 +24,4 @@ public: -#endif /* FRAMEWORK_DATAPOOL_PIDREADERLIST_H_ */ +#endif /* FRAMEWORK_DATAPOOLGLOB_PIDREADERLIST_H_ */ diff --git a/datapoolglob/PoolRawAccess.cpp b/datapoolglob/PoolRawAccess.cpp new file mode 100644 index 00000000..53706c6d --- /dev/null +++ b/datapoolglob/PoolRawAccess.cpp @@ -0,0 +1,239 @@ +#include "../datapoolglob/GlobalDataPool.h" +#include "../datapoolglob/PoolRawAccess.h" +#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serialize/EndianConverter.h" + +#include + +PoolRawAccess::PoolRawAccess(uint32_t set_id, uint8_t setArrayEntry, + DataSetIF* dataSet, ReadWriteMode_t setReadWriteMode) : + dataPoolId(set_id), arrayEntry(setArrayEntry), valid(false), + type(Type::UNKNOWN_TYPE), typeSize(0), arraySize(0), sizeTillEnd(0), + readWriteMode(setReadWriteMode) { + memset(value, 0, sizeof(value)); + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +PoolRawAccess::~PoolRawAccess() {} + +ReturnValue_t PoolRawAccess::read(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = readWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +ReturnValue_t PoolRawAccess::readWithoutLock() { + ReturnValue_t result = RETURN_FAILED; + PoolEntryIF* readOut = glob::dataPool.getRawData(dataPoolId); + if (readOut != nullptr) { + result = handleReadOut(readOut); + if(result == RETURN_OK) { + return result; + } + } else { + result = READ_ENTRY_NON_EXISTENT; + } + handleReadError(result); + return result; +} + +ReturnValue_t PoolRawAccess::handleReadOut(PoolEntryIF* readOut) { + ReturnValue_t result = RETURN_FAILED; + valid = readOut->getValid(); + if (readOut->getSize() > arrayEntry) { + arraySize = readOut->getSize(); + typeSize = readOut->getByteSize() / readOut->getSize(); + type = readOut->getType(); + if (typeSize <= sizeof(value)) { + uint16_t arrayPosition = arrayEntry * typeSize; + sizeTillEnd = readOut->getByteSize() - arrayPosition; + uint8_t* ptr = &((uint8_t*) readOut->getRawData())[arrayPosition]; + memcpy(value, ptr, typeSize); + return RETURN_OK; + } else { + result = READ_TYPE_TOO_LARGE; + } + } else { + //debug << "PoolRawAccess: Size: " << (int)read_out->getSize() << std::endl; + result = READ_INDEX_TOO_LARGE; + } + return result; +} + +void PoolRawAccess::handleReadError(ReturnValue_t result) { + sif::error << "PoolRawAccess: read of DP Variable 0x" << std::hex << dataPoolId + << std::dec << " failed, "; + if(result == READ_TYPE_TOO_LARGE) { + sif::error << "type too large." << std::endl; + } + else if(result == READ_INDEX_TOO_LARGE) { + sif::error << "index too large." << std::endl; + } + else if(result == READ_ENTRY_NON_EXISTENT) { + sif::error << "entry does not exist." << std::endl; + } + + valid = INVALID; + typeSize = 0; + sizeTillEnd = 0; + memset(value, 0, sizeof(value)); +} + +ReturnValue_t PoolRawAccess::commit(uint32_t lockTimeout) { + ReturnValue_t result = glob::dataPool.lockDataPool(lockTimeout); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = commitWithoutLock(); + ReturnValue_t unlockResult = glob::dataPool.unlockDataPool(); + if(unlockResult != HasReturnvaluesIF::RETURN_OK) { + sif::error << "GlobPoolVar::read: Could not unlock global data pool" + << std::endl; + } + return result; +} + +ReturnValue_t PoolRawAccess::commitWithoutLock() { + PoolEntryIF* write_back = glob::dataPool.getRawData(dataPoolId); + if ((write_back != NULL) && (readWriteMode != VAR_READ)) { + write_back->setValid(valid); + uint8_t array_position = arrayEntry * typeSize; + uint8_t* ptr = &((uint8_t*) write_back->getRawData())[array_position]; + memcpy(ptr, value, typeSize); + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t* PoolRawAccess::getEntry() { + return value; +} + +ReturnValue_t PoolRawAccess::getEntryEndianSafe(uint8_t* buffer, + size_t* writtenBytes, size_t max_size) { + uint8_t* data_ptr = getEntry(); + // debug << "PoolRawAccess::getEntry: Array position: " << + // index * size_of_type << " Size of T: " << (int)size_of_type << + // " ByteSize: " << byte_size << " Position: " << *size << std::endl; + if (typeSize == 0) + return DATA_POOL_ACCESS_FAILED; + if (typeSize > max_size) + return INCORRECT_SIZE; + EndianConverter::convertBigEndian(buffer, data_ptr, typeSize); + *writtenBytes = typeSize; + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t PoolRawAccess::serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const { + if (typeSize + *size <= maxSize) { + switch(streamEndianness) { + case(Endianness::BIG): + EndianConverter::convertBigEndian(*buffer, value, typeSize); + break; + case(Endianness::LITTLE): + EndianConverter::convertLittleEndian(*buffer, value, typeSize); + break; + case(Endianness::MACHINE): + default: + memcpy(*buffer, value, typeSize); + break; + } + *size += typeSize; + (*buffer) += typeSize; + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } +} + + +Type PoolRawAccess::getType() { + return type; +} + +size_t PoolRawAccess::getSizeOfType() { + return typeSize; +} + +size_t PoolRawAccess::getArraySize(){ + return arraySize; +} + +uint32_t PoolRawAccess::getDataPoolId() const { + return dataPoolId; +} + +PoolVariableIF::ReadWriteMode_t PoolRawAccess::getReadWriteMode() const { + return readWriteMode; +} + +ReturnValue_t PoolRawAccess::setEntryFromBigEndian(const uint8_t *buffer, + size_t setSize) { + if (typeSize == setSize) { + EndianConverter::convertBigEndian(value, buffer, typeSize); + return HasReturnvaluesIF::RETURN_OK; + } else { + sif::error << "PoolRawAccess::setEntryFromBigEndian: Illegal sizes: " + "Internal" << (uint32_t) typeSize << ", Requested: " << setSize + << std::endl; + return INCORRECT_SIZE; + } +} + +bool PoolRawAccess::isValid() const { + if (valid != INVALID) + return true; + else + return false; +} + +void PoolRawAccess::setValid(bool valid) { + this->valid = valid; +} + +size_t PoolRawAccess::getSizeTillEnd() const { + return sizeTillEnd; +} + + +size_t PoolRawAccess::getSerializedSize() const { + return typeSize; +} + +ReturnValue_t PoolRawAccess::deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) { + + if (*size >= typeSize) { + switch(streamEndianness) { + case(Endianness::BIG): + EndianConverter::convertBigEndian(value, *buffer, typeSize); + break; + case(Endianness::LITTLE): + EndianConverter::convertLittleEndian(value, *buffer, typeSize); + break; + case(Endianness::MACHINE): + default: + memcpy(value, *buffer, typeSize); + break; + } + *size -= typeSize; + *buffer += typeSize; + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SerializeIF::STREAM_TOO_SHORT; + } +} diff --git a/datapoolglob/PoolRawAccess.h b/datapoolglob/PoolRawAccess.h new file mode 100644 index 00000000..15643a41 --- /dev/null +++ b/datapoolglob/PoolRawAccess.h @@ -0,0 +1,220 @@ +#ifndef POOLRAWACCESS_H_ +#define POOLRAWACCESS_H_ + +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntryIF.h" +#include "../datapool/PoolVariableIF.h" +#include "../globalfunctions/Type.h" + +/** + * @brief This class allows accessing Data Pool variables as raw bytes. + * @details + * This is necessary to have an access method for HK data, as the PID's alone + * do not provide type information. Please note that the the raw pool access + * read() and commit() calls are not thread-safe. + * + * Please supply a data set and use the data set read(), commit() calls for + * thread-safe data pool access. + * @ingroup data_pool + */ +class PoolRawAccess: public PoolVariableIF, HasReturnvaluesIF { +public: + /** + * This constructor is used to access a data pool entry with a + * given ID if the target type is not known. A DataSet object is supplied + * and the data pool entry with the given ID is registered to that data set. + * Please note that a pool raw access buffer only has a buffer + * with a size of double. As such, for vector entries which have + * @param data_pool_id Target data pool entry ID + * @param arrayEntry + * @param data_set Dataset to register data pool entry to + * @param setReadWriteMode + * @param registerVectors If set to true, the constructor checks if + * there are multiple vector entries to registers + * and registers all of them recursively into the data_set + * + */ + PoolRawAccess(uint32_t data_pool_id, uint8_t arrayEntry, + DataSetIF* data_set, ReadWriteMode_t setReadWriteMode = + PoolVariableIF::VAR_READ); + + /** + * @brief This operation returns a pointer to the entry fetched. + * @details Return pointer to the buffer containing the raw data + * Size and number of data can be retrieved by other means. + */ + uint8_t* getEntry(); + /** + * @brief This operation returns the fetched entry from the data pool and + * flips the bytes, if necessary. + * @details It makes use of the getEntry call of this function, but additionally flips the + * bytes to big endian, which is the default for external communication (as House- + * keeping telemetry). To achieve this, the data is copied directly to the passed + * buffer, if it fits in the given max_size. + * @param buffer A pointer to a buffer to write to + * @param writtenBytes The number of bytes written is returned with this value. + * @param max_size The maximum size that the function may write to buffer. + * @return - @c RETURN_OK if entry could be acquired + * - @c RETURN_FAILED else. + */ + ReturnValue_t getEntryEndianSafe(uint8_t *buffer, size_t *size, + size_t maxSize); + + /** + * @brief Serialize raw pool entry into provided buffer directly + * @param buffer Provided buffer. Raw pool data will be copied here + * @param size [out] Increment provided size value by serialized size + * @param max_size Maximum allowed serialization size + * @param bigEndian Specify endianess + * @return - @c RETURN_OK if serialization was successfull + * - @c SerializeIF::BUFFER_TOO_SHORT if range check failed + */ + ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const override; + + size_t getSerializedSize() const override; + + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override; + + /** + * With this method, the content can be set from a big endian buffer safely. + * @param buffer Pointer to the data to set + * @param size Size of the data to write. Must fit this->size. + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t setEntryFromBigEndian(const uint8_t* buffer, + size_t setSize); + /** + * @brief This operation returns the type of the entry currently stored. + */ + Type getType(); + /** + * @brief This operation returns the size of the entry currently stored. + */ + size_t getSizeOfType(); + /** + * + * @return the size of the datapool array + */ + size_t getArraySize(); + /** + * @brief This operation returns the data pool id of the variable. + */ + uint32_t getDataPoolId() const; + + static const uint8_t INTERFACE_ID = CLASS_ID::POOL_RAW_ACCESS_CLASS; + static const ReturnValue_t INCORRECT_SIZE = MAKE_RETURN_CODE(0x01); + static const ReturnValue_t DATA_POOL_ACCESS_FAILED = MAKE_RETURN_CODE(0x02); + static const ReturnValue_t READ_TYPE_TOO_LARGE = MAKE_RETURN_CODE(0x03); + static const ReturnValue_t READ_INDEX_TOO_LARGE = MAKE_RETURN_CODE(0x04); + static const ReturnValue_t READ_ENTRY_NON_EXISTENT = MAKE_RETURN_CODE(0x05); + static const uint8_t RAW_MAX_SIZE = sizeof(double); + uint8_t value[RAW_MAX_SIZE]; + + + /** + * @brief The classes destructor is empty. If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~PoolRawAccess(); + + /** + * This method returns if the variable is read-write or read-only. + */ + ReadWriteMode_t getReadWriteMode() const; + /** + * @brief With this call, the valid information of the variable is returned. + */ + bool isValid() const; + + void setValid(bool valid); + /** + * Getter for the remaining size. + */ + size_t getSizeTillEnd() const; + + /** + * @brief This is a call to read the value from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the global data pool and copies the value and the valid + * information to its local attributes. In case of a failure (wrong type or + * pool id not found), the variable is set to zero and invalid. + * The call is protected by a lock of the global data pool. + * @return -@c RETURN_OK Read successfull + * -@c READ_TYPE_TOO_LARGE + * -@c READ_INDEX_TOO_LARGE + * -@c READ_ENTRY_NON_EXISTENT + */ + ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief The commit call writes back the variable's value to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the valid flag is automatically set to "valid". + * The call is protected by a lock of the global data pool. + * + */ + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + + ReturnValue_t handleReadOut(PoolEntryIF* read_out); + void handleReadError(ReturnValue_t result); +private: + /** + * @brief To access the correct data pool entry on read and commit calls, the data pool id + * is stored. + */ + uint32_t dataPoolId; + /** + * @brief The array entry that is fetched from the data pool. + */ + uint8_t arrayEntry; + /** + * @brief The valid information as it was stored in the data pool is copied to this attribute. + */ + uint8_t valid; + /** + * @brief This value contains the type of the data pool entry. + */ + Type type; + /** + * @brief This value contains the size of the data pool entry type in bytes. + */ + size_t typeSize; + /** + * The size of the DP array (single values return 1) + */ + size_t arraySize; + /** + * The size (in bytes) from the selected entry till the end of this DataPool variable. + */ + size_t sizeTillEnd; + /** + * @brief The information whether the class is read-write or read-only is stored here. + */ + ReadWriteMode_t readWriteMode; +}; + +#endif /* POOLRAWACCESS_H_ */ diff --git a/datapoollocal/HasLocalDataPoolIF.h b/datapoollocal/HasLocalDataPoolIF.h new file mode 100644 index 00000000..7f1f202e --- /dev/null +++ b/datapoollocal/HasLocalDataPoolIF.h @@ -0,0 +1,136 @@ +#ifndef FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ +#define FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ + +#include "locPoolDefinitions.h" + +#include "../datapool/PoolEntryIF.h" +#include "../ipc/MessageQueueSenderIF.h" +#include "../housekeeping/HousekeepingMessage.h" + +#include + +class LocalDataPoolManager; +class LocalPoolDataSetBase; +class LocalPoolObjectBase; + +using LocalDataPool = std::map; +using LocalDataPoolMapIter = LocalDataPool::iterator; + +/** + * @brief This interface is implemented by classes which posses a local + * data pool (not the managing class). It defines the relationship + * between the local data pool owner and the LocalDataPoolManager. + * @details + * Any class implementing this interface shall also have a LocalDataPoolManager + * member class which contains the actual pool data structure + * and exposes the public interface for it. + * This is required because the pool entries are templates, which makes + * specifying an interface rather difficult. The local data pool can be + * accessed by using the LocalPoolVariable, LocalPoolVector or LocalDataSet + * classes. + * + * Architectural Note: + * This could be circumvented by using a wrapper/accessor function or + * implementing the templated function in this interface.. + * The first solution sounds better than the second but + * the LocalPoolVariable classes are templates as well, so this just shifts + * the problem somewhere else. Interfaces are nice, but the most + * pragmatic solution I found was to offer the client the full interface + * of the LocalDataPoolManager. + */ +class HasLocalDataPoolIF { +public: + virtual~ HasLocalDataPoolIF() {}; + + static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; + + static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID; + + virtual object_id_t getObjectId() const = 0; + + /** Command queue for housekeeping messages. */ + virtual MessageQueueId_t getCommandQueue() const = 0; + + /** + * Is used by pool owner to initialize the pool map once + * The manager instance shall also be passed to this function. + * It can be used to subscribe for periodic packets for for updates. + */ + virtual ReturnValue_t initializeLocalDataPool( + LocalDataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) = 0; + + /** Can be used to get a handle to the local data pool manager. */ + virtual LocalDataPoolManager* getHkManagerHandle() = 0; + + /** + * Returns the minimum sampling frequency in milliseconds, which will + * usually be the period the pool owner performs its periodic operation. + * @return + */ + virtual uint32_t getPeriodicOperationFrequency() const = 0; + + /** + * This function is used by the pool manager to get a valid dataset + * from a SID + * @param sid Corresponding structure ID + * @return + */ + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) = 0; + + /** + * Similar to the function above, but used to get a local pool variable + * handle. This is only needed for update notifications, so it is not + * defined as abstract. + * @param localPoolId + * @return + */ + virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) { + sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden" + << ". Returning nullptr!" << std::endl; + return nullptr; + } + + /** + * @brief This function will be called by the manager if an update + * notification is received. + * @details + * Can be overriden by the child class to handle changed datasets. + * @param sid + * @param storeId If a snapshot was requested, data will be located inside + * the IPC store with this store ID. + */ + virtual void handleChangedDataset(sid_t sid, + store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { + return; + } + + /** + * @brief This function will be called by the manager if an update + * notification is received. + * @details + * Can be overriden by the child class to handle changed pool IDs. + * @param sid + * @param storeId If a snapshot was requested, data will be located inside + * the IPC store with this store ID. + */ + virtual void handleChangedPoolVariable(lp_id_t poolId, + store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { + return; + } + + /* These function can be implemented by pool owner, as they are required + * by the housekeeping message interface */ + virtual ReturnValue_t addDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + virtual ReturnValue_t removeDataSet(sid_t sid) { + return HasReturnvaluesIF::RETURN_FAILED; + }; + virtual ReturnValue_t changeCollectionInterval(sid_t sid, + float newIntervalSeconds) { + return HasReturnvaluesIF::RETURN_FAILED; + }; +}; + +#endif /* FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ */ diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp new file mode 100644 index 00000000..f649a362 --- /dev/null +++ b/datapoollocal/LocalDataPoolManager.cpp @@ -0,0 +1,782 @@ +#include "LocalDataPoolManager.h" +#include "LocalPoolObjectBase.h" +#include "LocalPoolDataSetBase.h" + +#include "../housekeeping/HousekeepingPacketUpdate.h" +#include "../housekeeping/HousekeepingSetPacket.h" +#include "../housekeeping/AcceptsHkPacketsIF.h" + +#include "../timemanager/CCSDSTime.h" +#include "../ipc/MutexFactory.h" +#include "../ipc/MutexHelper.h" +#include "../ipc/QueueFactory.h" + +#include +#include + +object_id_t LocalDataPoolManager::defaultHkDestination = + objects::PUS_SERVICE_3_HOUSEKEEPING; + +LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, + MessageQueueIF* queueToUse, bool appendValidityBuffer): + appendValidityBuffer(appendValidityBuffer) { + if(owner == nullptr) { + sif::error << "LocalDataPoolManager::LocalDataPoolManager: " + << "Invalid supplied owner!" << std::endl; + return; + } + this->owner = owner; + mutex = MutexFactory::instance()->createMutex(); + if(mutex == nullptr) { + sif::error << "LocalDataPoolManager::LocalDataPoolManager: " + << "Could not create mutex." << std::endl; + } + + hkQueue = queueToUse; +} + +LocalDataPoolManager::~LocalDataPoolManager() {} + +ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { + if(queueToUse == nullptr) { + sif::error << "LocalDataPoolManager::initialize: " + << std::hex << "0x" << owner->getObjectId() << ". Supplied " + << "queue invalid!" << std::dec << std::endl; + } + hkQueue = queueToUse; + + ipcStore = objectManager->get(objects::IPC_STORE); + if(ipcStore == nullptr) { + sif::error << "LocalDataPoolManager::initialize: " + << std::hex << "0x" << owner->getObjectId() << ": Could not " + << "set IPC store." <get(defaultHkDestination); + if(hkPacketReceiver != nullptr) { + hkDestinationId = hkPacketReceiver->getHkQueue(); + } + else { + sif::error << "LocalDataPoolManager::LocalDataPoolManager: " + << "Default HK destination object is invalid!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + } + + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation( + uint8_t nonDiagInvlFactor) { + setNonDiagnosticIntervalFactor(nonDiagInvlFactor); + return initializeHousekeepingPoolEntriesOnce(); +} + +ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { + if(not mapInitialized) { + ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, + *this); + if(result == HasReturnvaluesIF::RETURN_OK) { + mapInitialized = true; + } + return result; + } + sif::warning << "HousekeepingManager: The map should only be initialized " + << "once!" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::performHkOperation() { + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + for(auto& receiver: hkReceiversMap) { + switch(receiver.reportingType) { + case(ReportingType::PERIODIC): { + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + // Periodic packets shall only be generated from datasets. + continue; + } + performPeriodicHkGeneration(receiver); + break; + } + case(ReportingType::UPDATE_HK): { + handleHkUpdate(receiver, status); + break; + } + case(ReportingType::UPDATE_NOTIFICATION): { + handleNotificationUpdate(receiver, status); + break; + } + case(ReportingType::UPDATE_SNAPSHOT): { + handleNotificationSnapshot(receiver, status); + break; + } + default: + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } + } + resetHkUpdateResetHelper(); + return status; +} + +ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver, + ReturnValue_t& status) { + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + // Update packets shall only be generated from datasets. + return HasReturnvaluesIF::RETURN_FAILED; + } + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( + receiver.dataId.sid); + if(dataSet->hasChanged()) { + // prepare and send update notification + ReturnValue_t result = generateHousekeepingPacket( + receiver.dataId.sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + } + handleChangeResetLogic(receiver.dataType, receiver.dataId, + dataSet); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::handleNotificationUpdate( + HkReceiver& receiver, ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle( + receiver.dataId.localPoolId); + if(poolObj == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(poolObj->hasChanged()) { + // prepare and send update notification. + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationVariableCommand( + ¬ification, receiver.dataId.localPoolId); + ReturnValue_t result = hkQueue->sendMessage( + receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } + + } + else { + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( + receiver.dataId.sid); + if(dataSet == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(dataSet->hasChanged()) { + // prepare and send update notification + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationSetCommand( + ¬ification, receiver.dataId.sid); + ReturnValue_t result = hkQueue->sendMessage( + receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; + } + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, + receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot( + HkReceiver& receiver, ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + // check whether data has changed and send messages in case it has. + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle( + receiver.dataId.localPoolId); + if(poolObj == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + if (not poolObj->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } + + // prepare and send update snapshot. + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + sizeof(cds), owner->getPoolObjectHandle( + receiver.dataId.localPoolId)); + + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotVariableCommand(¬ification, + receiver.dataId.localPoolId, storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, + ¬ification); + if (result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } + else { + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( + receiver.dataId.sid); + if(dataSet == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(not dataSet->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } + + // prepare and send update snapshot. + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + sizeof(cds), owner->getDataSetHandle(receiver.dataId.sid)); + + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotSetCommand( + ¬ification, receiver.dataId.sid, storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; + + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, + receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::addUpdateToStore( + HousekeepingPacketUpdate& updatePacket, store_address_t& storeId) { + size_t updatePacketSize = updatePacket.getSerializedSize(); + uint8_t *storePtr = nullptr; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + updatePacket.getSerializedSize(), &storePtr); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t serializedSize = 0; + result = updatePacket.serialize(&storePtr, &serializedSize, + updatePacketSize, SerializeIF::Endianness::MACHINE); + return result;; +} + +void LocalDataPoolManager::handleChangeResetLogic( + DataType type, DataId dataId, MarkChangedIF* toReset) { + if(hkUpdateResetList == nullptr) { + // config error! + return; + } + + for(auto& changeInfo: *hkUpdateResetList) { + if(changeInfo.dataType != type) { + continue; + } + if((changeInfo.dataType == DataType::DATA_SET) and + (changeInfo.dataId.sid != dataId.sid)) { + continue; + } + if((changeInfo.dataType == DataType::LOCAL_POOL_VARIABLE) and + (changeInfo.dataId.localPoolId != dataId.localPoolId)) { + continue; + } + + if(changeInfo.updateCounter <= 1) { + toReset->setChanged(false); + } + if(changeInfo.currentUpdateCounter == 0) { + toReset->setChanged(false); + } + else { + changeInfo.currentUpdateCounter--; + } + return; + } +} + +void LocalDataPoolManager::resetHkUpdateResetHelper() { + if(hkUpdateResetList == nullptr) { + return; + } + + for(auto& changeInfo: *hkUpdateResetList) { + changeInfo.currentUpdateCounter = changeInfo.updateCounter; + } +} + +ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid, + bool enableReporting, float collectionInterval, bool isDiagnostics, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + objectManager->get(packetDestination); + if(hkReceiverObject == nullptr) { + sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" + << " Invalid receiver!"<< std::endl; + return HasReturnvaluesIF::RETURN_OK; + } + + struct HkReceiver hkReceiver; + hkReceiver.dataId.sid = sid; + hkReceiver.reportingType = ReportingType::PERIODIC; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); + + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(dataSet != nullptr) { + dataSet->setReportingEnabled(enableReporting); + dataSet->setDiagnostic(isDiagnostics); + dataSet->initializePeriodicHelper(collectionInterval, + owner->getPeriodicOperationFrequency(), isDiagnostics); + } + + hkReceiversMap.push_back(hkReceiver); + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t LocalDataPoolManager::subscribeForUpdatePackets(sid_t sid, + bool isDiagnostics, bool reportingEnabled, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + objectManager->get(packetDestination); + if(hkReceiverObject == nullptr) { + sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" + << " Invalid receiver!"<< std::endl; + return HasReturnvaluesIF::RETURN_OK; + } + + struct HkReceiver hkReceiver; + hkReceiver.dataId.sid = sid; + hkReceiver.reportingType = ReportingType::UPDATE_HK; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); + + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(dataSet != nullptr) { + dataSet->setReportingEnabled(true); + dataSet->setDiagnostic(isDiagnostics); + } + + hkReceiversMap.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessages( + const uint32_t setId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.dataId.sid = sid_t(this->getOwner()->getObjectId(), setId); + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } + + hkReceiversMap.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessages( + const lp_id_t localPoolId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::LOCAL_POOL_VARIABLE; + hkReceiver.dataId.localPoolId = localPoolId; + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } + + hkReceiversMap.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +void LocalDataPoolManager::handleHkUpdateResetListInsertion(DataType dataType, + DataId dataId) { + if(hkUpdateResetList == nullptr) { + hkUpdateResetList = new std::vector(); + } + + for(auto& updateResetStruct: *hkUpdateResetList) { + if(dataType == DataType::DATA_SET) { + if(updateResetStruct.dataId.sid == dataId.sid) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + else { + if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + + } + HkUpdateResetHelper hkUpdateResetHelper; + hkUpdateResetHelper.currentUpdateCounter = 1; + hkUpdateResetHelper.updateCounter = 1; + hkUpdateResetHelper.dataType = dataType; + if(dataType == DataType::DATA_SET) { + hkUpdateResetHelper.dataId.sid = dataId.sid; + } + else { + hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId; + } + hkUpdateResetList->push_back(hkUpdateResetHelper); +} + +ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( + CommandMessage* message) { + Command_t command = message->getCommand(); + sid_t sid = HousekeepingMessage::getSid(message); + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(command) { + // Houskeeping interface handling. + case(HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, true, true); + break; + } + + case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, false, true); + break; + } + + case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, true, false); + break; + } + + case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, false, false); + break; + } + + case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): + return generateSetStructurePacket(sid, true); + case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): + return generateSetStructurePacket(sid, false); + case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL): + case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): { + float newCollIntvl = 0; + HousekeepingMessage::getCollectionIntervalModificationCommand(message, + &newCollIntvl); + if(command == HousekeepingMessage:: + MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) { + result = changeCollectionInterval(sid, newCollIntvl, true); + } + else { + result = changeCollectionInterval(sid, newCollIntvl, false); + } + break; + } + + case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): + case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT + and dataSet->isDiagnostics()) { + return WRONG_HK_PACKET_TYPE; + } + else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT + and not dataSet->isDiagnostics()) { + return WRONG_HK_PACKET_TYPE; + } + return generateHousekeepingPacket(HousekeepingMessage::getSid(message), + dataSet, true); + } + + // Notification handling. + case(HousekeepingMessage::UPDATE_NOTIFICATION_SET): { + owner->handleChangedDataset(sid); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE): { + lp_id_t locPoolId = HousekeepingMessage:: + getUpdateNotificationVariableCommand(message); + owner->handleChangedPoolVariable(locPoolId); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { + store_address_t storeId; + HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId); + owner->handleChangedDataset(sid, storeId); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { + store_address_t storeId; + lp_id_t localPoolId = HousekeepingMessage:: + getUpdateSnapshotVariableCommand(message, &storeId); + owner->handleChangedPoolVariable(localPoolId, storeId); + return HasReturnvaluesIF::RETURN_OK; + } + + default: + return CommandMessageIF::UNKNOWN_COMMAND; + } + + CommandMessage reply; + if(result != HasReturnvaluesIF::RETURN_OK) { + HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); + } + else { + HousekeepingMessage::setHkRequestSuccessReply(&reply, sid); + } + hkQueue->sendMessage(hkDestinationId, &reply); + return result; +} + +ReturnValue_t LocalDataPoolManager::printPoolEntry( + lp_id_t localPoolId) { + auto poolIter = localPoolMap.find(localPoolId); + if (poolIter == localPoolMap.end()) { + sif::debug << "HousekeepingManager::fechPoolEntry:" + << " Pool entry not found." << std::endl; + return POOL_ENTRY_NOT_FOUND; + } + poolIter->second->print(); + return HasReturnvaluesIF::RETURN_OK; +} + +MutexIF* LocalDataPoolManager::getMutexHandle() { + return mutex; +} + +HasLocalDataPoolIF* LocalDataPoolManager::getOwner() { + return owner; +} + +ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, + LocalPoolDataSetBase* dataSet, bool forDownlink, + MessageQueueId_t destination) { + if(dataSet == nullptr) { + // Configuration error. + sif::warning << "HousekeepingManager::generateHousekeepingPacket:" + << " Set ID not found or dataset not assigned!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + store_address_t storeId; + HousekeepingPacketDownlink hkPacket(sid, dataSet); + size_t serializedSize = 0; + ReturnValue_t result = serializeHkPacketIntoStore(hkPacket, storeId, + forDownlink, &serializedSize); + if(result != HasReturnvaluesIF::RETURN_OK or serializedSize == 0) { + return result; + } + + // and now we set a HK message and send it the HK packet destination. + CommandMessage hkMessage; + if(dataSet->isDiagnostics()) { + HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); + } + else { + HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId); + } + + if(hkQueue == nullptr) { + return QUEUE_OR_DESTINATION_NOT_SET; + } + if(destination == MessageQueueIF::NO_QUEUE) { + if(hkDestinationId == MessageQueueIF::NO_QUEUE) { + // error, all destinations invalid + return HasReturnvaluesIF::RETURN_FAILED; + } + destination = hkDestinationId; + } + + return hkQueue->sendMessage(destination, &hkMessage); +} + +ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( + HousekeepingPacketDownlink& hkPacket, + store_address_t& storeId, bool forDownlink, + size_t* serializedSize) { + uint8_t* dataPtr = nullptr; + const size_t maxSize = hkPacket.getSerializedSize(); + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + maxSize, &dataPtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + if(forDownlink) { + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::BIG); + } + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::MACHINE); +} + +void LocalDataPoolManager::setNonDiagnosticIntervalFactor( + uint8_t nonDiagInvlFactor) { + this->nonDiagnosticIntervalFactor = nonDiagInvlFactor; +} + +void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { + sid_t sid = receiver.dataId.sid; + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(not dataSet->getReportingEnabled()) { + return; + } + + if(dataSet->periodicHelper == nullptr) { + // Configuration error. + return; + } + + if(not dataSet->periodicHelper->checkOpNecessary()) { + return; + } + + ReturnValue_t result = generateHousekeepingPacket( + sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + // configuration error + sif::debug << "LocalDataPoolManager::performHkOperation:" + << "0x" << std::hex << std::setfill('0') << std::setw(8) + << owner->getObjectId() << " Error generating " + << "HK packet" << std::setfill(' ') << std::dec << std::endl; + } +} + + +ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, + bool enable, bool isDiagnostics) { + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if((dataSet->isDiagnostics() and not isDiagnostics) or + (not dataSet->isDiagnostics() and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } + + if((dataSet->getReportingEnabled() and enable) or + (not dataSet->getReportingEnabled() and not enable)) { + return REPORTING_STATUS_UNCHANGED; + } + + dataSet->setReportingEnabled(enable); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, + float newCollectionInterval, bool isDiagnostics) { + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + bool targetIsDiagnostics = dataSet->isDiagnostics(); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } + + if(dataSet->periodicHelper == nullptr) { + // config error + return PERIODIC_HELPER_INVALID; + } + + dataSet->periodicHelper->changeCollectionInterval(newCollectionInterval); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, + bool isDiagnostics) { + // Get and check dataset first. + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(dataSet == nullptr) { + sif::warning << "HousekeepingManager::generateHousekeepingPacket:" + << " Set ID not found" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + + bool targetIsDiagnostics = dataSet->isDiagnostics(); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } + + bool valid = dataSet->isValid(); + bool reportingEnabled = dataSet->getReportingEnabled(); + float collectionInterval = + dataSet->periodicHelper->getCollectionIntervalInSeconds(); + + // Generate set packet which can be serialized. + HousekeepingSetPacket setPacket(sid, + reportingEnabled, valid, collectionInterval, dataSet); + size_t expectedSize = setPacket.getSerializedSize(); + uint8_t* storePtr = nullptr; + store_address_t storeId; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + expectedSize,&storePtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "HousekeepingManager::generateHousekeepingPacket: " + << "Could not get free element from IPC store." << std::endl; + return result; + } + + // Serialize set packet into store. + size_t size = 0; + result = setPacket.serialize(&storePtr, &size, expectedSize, + SerializeIF::Endianness::BIG); + if(expectedSize != size) { + sif::error << "HousekeepingManager::generateSetStructurePacket: " + << "Expected size is not equal to serialized size" << std::endl; + } + + // Send structure reporting reply. + CommandMessage reply; + if(isDiagnostics) { + HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, + sid, storeId); + } + else { + HousekeepingMessage::setHkStuctureReportReply(&reply, + sid, storeId); + } + + hkQueue->reply(&reply); + return result; +} diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h new file mode 100644 index 00000000..95d48303 --- /dev/null +++ b/datapoollocal/LocalDataPoolManager.h @@ -0,0 +1,396 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ +#define FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ + +#include "HasLocalDataPoolIF.h" + +#include "../housekeeping/HousekeepingPacketDownlink.h" +#include "../housekeeping/HousekeepingMessage.h" +#include "../housekeeping/PeriodicHousekeepingHelper.h" +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntry.h" +#include "../objectmanager/SystemObjectIF.h" +#include "../ipc/MutexIF.h" +#include "../ipc/CommandMessage.h" +#include "../ipc/MessageQueueIF.h" +#include "../ipc/MutexHelper.h" + +#include + +namespace Factory { +void setStaticFrameworkObjectIds(); +} + +class LocalPoolDataSetBase; +class HousekeepingPacketUpdate; + +/** + * @brief This class is the managing instance for the local data pool. + * @details + * The actual data pool structure is a member of this class. Any class which + * has a local data pool shall have this manager class as a member and implement + * the HasLocalDataPoolIF. + * + * The manager offers some adaption points and functions which can be used + * by the owning class to simplify data handling significantly. + * + * Please ensure that both initialize and initializeAfterTaskCreation are + * called at some point by the owning class in the respective functions of the + * same name! + * + * Users of the data pool use the helper classes LocalDataSet, + * LocalPoolVariable and LocalPoolVector to access pool entries in + * a thread-safe and efficient way. + * + * The local data pools employ a blackboard logic: Only the most recent + * value is stored. The helper classes offer a read() and commit() interface + * through the PoolVariableIF which is used to read and update values. + * Each pool entry has a valid state too. + * @author R. Mueller + */ +class LocalDataPoolManager { + template friend class LocalPoolVar; + template friend class LocalPoolVector; + friend class LocalPoolDataSetBase; + friend void (Factory::setStaticFrameworkObjectIds)(); +public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER; + + static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x00); + static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x01); + + static constexpr ReturnValue_t QUEUE_OR_DESTINATION_NOT_SET = MAKE_RETURN_CODE(0x02); + + static constexpr ReturnValue_t WRONG_HK_PACKET_TYPE = MAKE_RETURN_CODE(0x03); + static constexpr ReturnValue_t REPORTING_STATUS_UNCHANGED = MAKE_RETURN_CODE(0x04); + static constexpr ReturnValue_t PERIODIC_HELPER_INVALID = MAKE_RETURN_CODE(0x05); + + /** + * This constructor is used by a class which wants to implement + * a personal local data pool. The queueToUse can be supplied if it + * is already known. + * + * initialize() has to be called in any case before using the object! + * @param owner + * @param queueToUse + * @param appendValidityBuffer Specify whether a buffer containing the + * validity state is generated when serializing or deserializing packets. + */ + LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, + bool appendValidityBuffer = true); + virtual~ LocalDataPoolManager(); + + /** + * Assigns the queue to use. Make sure to call this in the #initialize + * function of the owner. + * @param queueToUse + * @param nonDiagInvlFactor See #setNonDiagnosticIntervalFactor doc + * @return + */ + ReturnValue_t initialize(MessageQueueIF* queueToUse); + + /** + * Initializes the map by calling the map initialization function and + * setting the periodic factor for non-diagnostic packets. + * Don't forget to call this in the #initializeAfterTaskCreation call of + * the owner, otherwise the map will be invalid! + * @param nonDiagInvlFactor + * @return + */ + ReturnValue_t initializeAfterTaskCreation( + uint8_t nonDiagInvlFactor = 5); + + /** + * @brief This should be called in the periodic handler of the owner. + * @details + * This in generally called in the #performOperation function of the owner. + * It performs all the periodic functionalities of the data pool manager, + * for example generating periodic HK packets. + * Marked virtual as an adaption point for custom data pool managers. + * @return + */ + virtual ReturnValue_t performHkOperation(); + + /** + * @brief Subscribe for the generation of periodic packets. + * @details + * This subscription mechanism will generally be used by the data creator + * to generate housekeeping packets which are downlinked directly. + * @return + */ + ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting, + float collectionInterval, bool isDiagnostics, + object_id_t packetDestination = defaultHkDestination); + + /** + * @brief Subscribe for the generation of packets if the dataset + * is marked as changed. + * @details + * This subscription mechanism will generally be used by the data creator. + * @param sid + * @param isDiagnostics + * @param packetDestination + * @return + */ + ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled, + bool isDiagnostics, + object_id_t packetDestination = defaultHkDestination); + + /** + * @brief Subscribe for a notification message which will be sent + * if a dataset has changed. + * @details + * This subscription mechanism will generally be used internally by + * other software components. + * @param setId Set ID of the set to receive update messages from. + * @param destinationObject + * @param targetQueueId + * @param generateSnapshot If this is set to true, a copy of the current + * data with a timestamp will be generated and sent via message. + * Otherwise, only an notification message is sent. + * @return + */ + ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId, + object_id_t destinationObject, + MessageQueueId_t targetQueueId, + bool generateSnapshot); + + /** + * @brief Subscribe for an notification message which will be sent if a + * pool variable has changed. + * @details + * This subscription mechanism will generally be used internally by + * other software components. + * @param localPoolId Pool ID of the pool variable + * @param destinationObject + * @param targetQueueId + * @param generateSnapshot If this is set to true, a copy of the current + * data with a timestamp will be generated and sent via message. + * Otherwise, only an notification message is sent. + * @return + */ + ReturnValue_t subscribeForVariableUpdateMessages(const lp_id_t localPoolId, + object_id_t destinationObject, + MessageQueueId_t targetQueueId, + bool generateSnapshot); + + /** + * Non-Diagnostics packets usually have a lower minimum sampling frequency + * than diagnostic packets. + * A factor can be specified to determine the minimum sampling frequency + * for non-diagnostic packets. The minimum sampling frequency of the + * diagnostics packets,which is usually jusst the period of the + * performOperation calls, is multiplied with that factor. + * @param factor + */ + void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor); + + /** + * @brief The manager is also able to handle housekeeping messages. + * @details + * This most commonly is used to handle messages for the housekeeping + * interface, but the manager is also able to handle update notifications + * and calls a special function which can be overriden by a child class + * to handle data set or pool variable updates. This is relevant + * for classes like controllers which have their own local datapool + * but pull their data from other local datapools. + * @param message + * @return + */ + virtual ReturnValue_t handleHousekeepingMessage(CommandMessage* message); + + /** + * Generate a housekeeping packet with a given SID. + * @param sid + * @return + */ + ReturnValue_t generateHousekeepingPacket(sid_t sid, + LocalPoolDataSetBase* dataSet, bool forDownlink, + MessageQueueId_t destination = MessageQueueIF::NO_QUEUE); + + HasLocalDataPoolIF* getOwner(); + + ReturnValue_t printPoolEntry(lp_id_t localPoolId); + + /** + * Different types of housekeeping reporting are possible. + * 1. PERIODIC: + * HK packets are generated in fixed intervals and sent to + * destination. Fromat will be raw. + * 2. UPDATE_NOTIFICATION: + * Notification will be sent out if HK data has changed. + * 3. UPDATE_SNAPSHOT: + * HK packets are only generated if explicitely requested. + * Propably not necessary, just use multiple local data sets or + * shared datasets. + */ + enum class ReportingType: uint8_t { + //! Periodic generation of HK packets. + PERIODIC, + //! Housekeeping packet will be generated if values have changed. + UPDATE_HK, + //! Update notification will be sent out as message. + UPDATE_NOTIFICATION, + //! Notification will be sent out as message and a snapshot of the + //! current data will be generated. + UPDATE_SNAPSHOT, + }; + + /** + * Different data types are possible in the HK receiver map. + * For example, updates can be requested for full datasets or + * for single pool variables. Periodic reporting is only possible for + * data sets. + */ + enum class DataType: uint8_t { + LOCAL_POOL_VARIABLE, + DATA_SET + }; + + /* Copying forbidden */ + LocalDataPoolManager(const LocalDataPoolManager &) = delete; + LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete; + +private: + LocalDataPool localPoolMap; + //! Every housekeeping data manager has a mutex to protect access + //! to it's data pool. + MutexIF* mutex = nullptr; + + /** The class which actually owns the manager (and its datapool). */ + HasLocalDataPoolIF* owner = nullptr; + + uint8_t nonDiagnosticIntervalFactor = 0; + + /** Default receiver for periodic HK packets */ + static object_id_t defaultHkDestination; + MessageQueueId_t hkDestinationId = MessageQueueIF::NO_QUEUE; + + union DataId { + DataId(): sid() {}; + sid_t sid; + lp_id_t localPoolId; + }; + + /** The data pool manager will keep an internal map of HK receivers. */ + struct HkReceiver { + /** Object ID of receiver */ + object_id_t objectId = objects::NO_OBJECT; + + DataType dataType = DataType::DATA_SET; + DataId dataId; + + ReportingType reportingType = ReportingType::PERIODIC; + MessageQueueId_t destinationQueue = MessageQueueIF::NO_QUEUE; + }; + + /** This vector will contain the list of HK receivers. */ + using HkReceivers = std::vector; + + HkReceivers hkReceiversMap; + + struct HkUpdateResetHelper { + DataType dataType = DataType::DATA_SET; + DataId dataId; + uint8_t updateCounter; + uint8_t currentUpdateCounter; + }; + + using HkUpdateResetList = std::vector; + // Will only be created when needed. + HkUpdateResetList* hkUpdateResetList = nullptr; + + /** This is the map holding the actual data. Should only be initialized + * once ! */ + bool mapInitialized = false; + /** This specifies whether a validity buffer is appended at the end + * of generated housekeeping packets. */ + bool appendValidityBuffer = true; + + /** + * @brief Queue used for communication, for example commands. + * Is also used to send messages. Can be set either in the constructor + * or in the initialize() function. + */ + MessageQueueIF* hkQueue = nullptr; + + /** Global IPC store is used to store all packets. */ + StorageManagerIF* ipcStore = nullptr; + /** + * Get the pointer to the mutex. Can be used to lock the data pool + * externally. Use with care and don't forget to unlock locked mutexes! + * For now, only friend classes can accss this function. + * @return + */ + MutexIF* getMutexHandle(); + + /** + * Read a variable by supplying its local pool ID and assign the pool + * entry to the supplied PoolEntry pointer. The type of the pool entry + * is deduced automatically. This call is not thread-safe! + * For now, only friend classes like LocalPoolVar may access this + * function. + * @tparam T Type of the pool entry + * @param localPoolId Pool ID of the variable to read + * @param poolVar [out] Corresponding pool entry will be assigned to the + * supplied pointer. + * @return + */ + template ReturnValue_t fetchPoolEntry(lp_id_t localPoolId, + PoolEntry **poolEntry); + + /** + * This function is used to fill the local data pool map with pool + * entries. It should only be called once by the pool owner. + * @param localDataPoolMap + * @return + */ + ReturnValue_t initializeHousekeepingPoolEntriesOnce(); + + ReturnValue_t serializeHkPacketIntoStore( + HousekeepingPacketDownlink& hkPacket, + store_address_t& storeId, bool forDownlink, size_t* serializedSize); + + void performPeriodicHkGeneration(HkReceiver& hkReceiver); + ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, + bool isDiagnostics); + ReturnValue_t changeCollectionInterval(sid_t sid, + float newCollectionInterval, bool isDiagnostics); + ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics); + + void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId); + void handleChangeResetLogic(DataType type, + DataId dataId, MarkChangedIF* toReset); + void resetHkUpdateResetHelper(); + + ReturnValue_t handleHkUpdate(HkReceiver& hkReceiver, + ReturnValue_t& status); + ReturnValue_t handleNotificationUpdate(HkReceiver& hkReceiver, + ReturnValue_t& status); + ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver, + ReturnValue_t& status); + ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket, + store_address_t& storeId); +}; + + +template inline +ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, + PoolEntry **poolEntry) { + auto poolIter = localPoolMap.find(localPoolId); + if (poolIter == localPoolMap.end()) { + sif::warning << "HousekeepingManager::fechPoolEntry: Pool entry " + "not found." << std::endl; + return POOL_ENTRY_NOT_FOUND; + } + + *poolEntry = dynamic_cast< PoolEntry* >(poolIter->second); + if(*poolEntry == nullptr) { + sif::debug << "HousekeepingManager::fetchPoolEntry:" + " Pool entry not found." << std::endl; + return POOL_ENTRY_TYPE_CONFLICT; + } + return HasReturnvaluesIF::RETURN_OK; +} + + +#endif /* FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ */ diff --git a/datapoollocal/LocalDataSet.cpp b/datapoollocal/LocalDataSet.cpp new file mode 100644 index 00000000..394a9abe --- /dev/null +++ b/datapoollocal/LocalDataSet.cpp @@ -0,0 +1,22 @@ +#include "LocalDataSet.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../serialize/SerializeAdapter.h" + +#include +#include + +LocalDataSet::LocalDataSet(HasLocalDataPoolIF *hkOwner, uint32_t setId, + const size_t maxNumberOfVariables): + LocalPoolDataSetBase(hkOwner, setId, nullptr, maxNumberOfVariables), + poolVarList(maxNumberOfVariables) { + this->setContainer(poolVarList.data()); +} + +LocalDataSet::LocalDataSet(sid_t sid, const size_t maxNumberOfVariables): + LocalPoolDataSetBase(sid, nullptr, maxNumberOfVariables), + poolVarList(maxNumberOfVariables) { + this->setContainer(poolVarList.data()); +} + +LocalDataSet::~LocalDataSet() {} + diff --git a/datapoollocal/LocalDataSet.h b/datapoollocal/LocalDataSet.h new file mode 100644 index 00000000..0368f26d --- /dev/null +++ b/datapoollocal/LocalDataSet.h @@ -0,0 +1,21 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALDATASET_H_ +#define FSFW_DATAPOOLLOCAL_LOCALDATASET_H_ + +#include "LocalPoolDataSetBase.h" +#include + +class LocalDataSet: public LocalPoolDataSetBase { +public: + LocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId, + const size_t maxSize); + LocalDataSet(sid_t sid, const size_t maxSize); + virtual~ LocalDataSet(); + + //! Copying forbidden for now. + LocalDataSet(const LocalDataSet&) = delete; + LocalDataSet& operator=(const LocalDataSet&) = delete; +private: + std::vector poolVarList; +}; + +#endif /* FSFW_DATAPOOLLOCAL_LOCALDATASET_H_ */ diff --git a/datapoollocal/LocalPoolDataSetBase.cpp b/datapoollocal/LocalPoolDataSetBase.cpp new file mode 100644 index 00000000..640956db --- /dev/null +++ b/datapoollocal/LocalPoolDataSetBase.cpp @@ -0,0 +1,278 @@ +#include "LocalPoolDataSetBase.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../housekeeping/PeriodicHousekeepingHelper.h" +#include "../serialize/SerializeAdapter.h" + +#include +#include + +LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, + uint32_t setId, PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables, bool noPeriodicHandling): + PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { + if(hkOwner == nullptr) { + // Configuration error. + sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " + << "invalid!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + this->sid.objectId = hkOwner->getObjectId(); + this->sid.ownerSetId = setId; + + mutex = MutexFactory::instance()->createMutex(); + + // Data creators get a periodic helper for periodic HK data generation. + if(not noPeriodicHandling) { + periodicHelper = new PeriodicHousekeepingHelper(this); + } +} + +LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, + PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables): + PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { + HasLocalDataPoolIF* hkOwner = objectManager->get( + sid.objectId); + if(hkOwner == nullptr) { + // Configuration error. + sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " + << "invalid!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + this->sid = sid; + + mutex = MutexFactory::instance()->createMutex(); +} + +LocalPoolDataSetBase::~LocalPoolDataSetBase() { +} + +ReturnValue_t LocalPoolDataSetBase::lockDataPool(uint32_t timeoutMs) { + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->lockMutex(MutexIF::TimeoutType::WAITING, timeoutMs); +} + +ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer, + size_t *size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + uint8_t validityMaskSize = std::ceil(static_cast(fillCount)/8.0); + uint8_t validityMask[validityMaskSize]; + uint8_t validBufferIndex = 0; + uint8_t validBufferIndexBit = 0; + for (uint16_t count = 0; count < fillCount; count++) { + if(registeredVariables[count]->isValid()) { + // set validity buffer here. + this->bitSetter(validityMask + validBufferIndex, + validBufferIndexBit); + if(validBufferIndexBit == 7) { + validBufferIndex ++; + validBufferIndexBit = 0; + } + else { + validBufferIndexBit ++; + } + } + result = registeredVariables[count]->serialize(buffer, size, maxSize, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + if(*size + validityMaskSize > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + // copy validity buffer to end + std::memcpy(*buffer, validityMask, validityMaskSize); + *size += validityMaskSize; + return result; +} + +ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer( + const uint8_t **buffer, size_t *size, + SerializeIF::Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t count = 0; count < fillCount; count++) { + result = registeredVariables[count]->deSerialize(buffer, size, + streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + + if(*size < std::ceil(static_cast(fillCount) / 8.0)) { + return SerializeIF::STREAM_TOO_SHORT; + } + + uint8_t validBufferIndex = 0; + uint8_t validBufferIndexBit = 0; + for (uint16_t count = 0; count < fillCount; count++) { + // set validity buffer here. + bool nextVarValid = this->bitGetter(*buffer + + validBufferIndex, validBufferIndexBit); + registeredVariables[count]->setValid(nextVarValid); + + if(validBufferIndexBit == 7) { + validBufferIndex ++; + validBufferIndexBit = 0; + } + else { + validBufferIndexBit ++; + } + } + return result; +} + +ReturnValue_t LocalPoolDataSetBase::unlockDataPool() { + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->unlockMutex(); +} + +ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer, + size_t* size, size_t maxSize,SerializeIF::Endianness streamEndianness, + bool serializeFillCount) const { + // Serialize as uint8_t + uint8_t fillCount = this->fillCount; + if(serializeFillCount) { + SerializeAdapter::serialize(&fillCount, buffer, size, maxSize, + streamEndianness); + } + for (uint16_t count = 0; count < fillCount; count++) { + lp_id_t currentPoolId = registeredVariables[count]->getDataPoolId(); + auto result = SerializeAdapter::serialize(¤tPoolId, buffer, + size, maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization" + " error!" << std::endl; + return result; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + + +uint8_t LocalPoolDataSetBase::getLocalPoolIdsSerializedSize( + bool serializeFillCount) const { + if(serializeFillCount) { + return fillCount * sizeof(lp_id_t) + sizeof(uint8_t); + } + else { + return fillCount * sizeof(lp_id_t); + } +} + +size_t LocalPoolDataSetBase::getSerializedSize() const { + if(withValidityBuffer) { + uint8_t validityMaskSize = std::ceil(static_cast(fillCount)/8.0); + return validityMaskSize + PoolDataSetBase::getSerializedSize(); + } + else { + return PoolDataSetBase::getSerializedSize(); + } +} + +void LocalPoolDataSetBase::setValidityBufferGeneration( + bool withValidityBuffer) { + this->withValidityBuffer = withValidityBuffer; +} + +ReturnValue_t LocalPoolDataSetBase::deSerialize(const uint8_t **buffer, + size_t *size, SerializeIF::Endianness streamEndianness) { + if(withValidityBuffer) { + return this->deSerializeWithValidityBuffer(buffer, size, + streamEndianness); + } + else { + return PoolDataSetBase::deSerialize(buffer, size, streamEndianness); + } +} + +ReturnValue_t LocalPoolDataSetBase::serialize(uint8_t **buffer, size_t *size, + size_t maxSize, SerializeIF::Endianness streamEndianness) const { + if(withValidityBuffer) { + return this->serializeWithValidityBuffer(buffer, size, + maxSize, streamEndianness); + } + else { + return PoolDataSetBase::serialize(buffer, size, maxSize, + streamEndianness); + } +} + +void LocalPoolDataSetBase::bitSetter(uint8_t* byte, uint8_t position) const { + if(position > 7) { + sif::debug << "Pool Raw Access: Bit setting invalid position" + << std::endl; + return; + } + uint8_t shiftNumber = position + (7 - 2 * position); + *byte |= 1 << shiftNumber; +} + +void LocalPoolDataSetBase::setDiagnostic(bool isDiagnostics) { + this->diagnostic = isDiagnostics; +} + +bool LocalPoolDataSetBase::isDiagnostics() const { + return diagnostic; +} + +void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) { + this->reportingEnabled = reportingEnabled; +} + +bool LocalPoolDataSetBase::getReportingEnabled() const { + return reportingEnabled; +} + +void LocalPoolDataSetBase::initializePeriodicHelper( + float collectionInterval, dur_millis_t minimumPeriodicInterval, + bool isDiagnostics, uint8_t nonDiagIntervalFactor) { + periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, + isDiagnostics, nonDiagIntervalFactor); +} + +void LocalPoolDataSetBase::setChanged(bool changed) { + // TODO: Make this configurable? + MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); + this->changed = changed; +} + +bool LocalPoolDataSetBase::hasChanged() const { + // TODO: Make this configurable? + MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); + return changed; +} + +sid_t LocalPoolDataSetBase::getSid() const { + return sid; +} + +bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte, + uint8_t position) const { + if(position > 7) { + sif::debug << "Pool Raw Access: Bit setting invalid position" + << std::endl; + return false; + } + uint8_t shiftNumber = position + (7 - 2 * position); + return *byte & (1 << shiftNumber); +} + +bool LocalPoolDataSetBase::isValid() const { + MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 5); + return this->valid; +} + +void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) { + MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 5); + if(setEntriesRecursively) { + for(size_t idx = 0; idx < this->getFillCount(); idx++) { + registeredVariables[idx] -> setValid(valid); + } + } + this->valid = valid; +} diff --git a/datapoollocal/LocalPoolDataSetBase.h b/datapoollocal/LocalPoolDataSetBase.h new file mode 100644 index 00000000..aa155bf1 --- /dev/null +++ b/datapoollocal/LocalPoolDataSetBase.h @@ -0,0 +1,198 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ + +#include "HasLocalDataPoolIF.h" +#include "MarkChangedIF.h" + +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolDataSetBase.h" +#include "../serialize/SerializeIF.h" + +#include + +class LocalDataPoolManager; +class PeriodicHousekeepingHelper; + +/** + * @brief The LocalDataSet class manages a set of locally checked out + * variables for local data pools + * @details + * Extends the PoolDataSetBase class for local data pools by introducing + * a validity state, a flag to mark the set as changed, and various other + * functions to make it usable by the LocalDataPoolManager class. + * + * This class manages a list, where a set of local variables (or pool variables) + * are registered. They are checked-out (i.e. their values are looked + * up and copied) with the read call. After the user finishes working with the + * pool variables, he can write back all variable values to the pool with + * the commit call. The data set manages locking and freeing the local data + * pools, to ensure thread-safety. + * + * Pool variables can be added to the dataset by using the constructor + * argument of the pool variable or using the #registerVariable member function. + * + * An internal state manages usage of this class. Variables may only be + * registered before any read call is made, and the commit call can only happen + * after the read call. + * + * If pool variables are writable and not committed until destruction + * of the set, the DataSet class automatically sets the valid flag in the + * data pool to invalid (without) changing the variable's value. + * + * @ingroup data_pool + */ +class LocalPoolDataSetBase: public PoolDataSetBase, + public MarkChangedIF { + friend class LocalDataPoolManager; + friend class PeriodicHousekeepingHelper; +public: + /** + * @brief Constructor for the creator of local pool data. + * @details + * This constructor also initializes the components required for + * periodic handling. + */ + LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, + uint32_t setId, PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables, bool noPeriodicHandling = false); + + /** + * @brief Constructor for users of local pool data. + * @details + * @param sid Unique identifier of dataset consisting of object ID and + * set ID. + * @param registeredVariablesArray + * @param maxNumberOfVariables + */ + LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables); + + /** + * @brief The destructor automatically manages writing the valid + * information of variables. + * @details + * In case the data set was read out, but not committed(indicated by state), + * the destructor parses all variables that are still registered to the set. + * For each, the valid flag in the data pool is set to "invalid". + */ + ~LocalPoolDataSetBase(); + + void setValidityBufferGeneration(bool withValidityBuffer); + + sid_t getSid() const; + + /** SerializeIF overrides */ + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + ReturnValue_t deSerialize(const uint8_t** buffer, size_t *size, + SerializeIF::Endianness streamEndianness) override; + size_t getSerializedSize() const override; + + /** + * Special version of the serilization function which appends a + * validity buffer at the end. Each bit of this validity buffer + * denotes whether the container data set entries are valid from left + * to right, MSB first. (length = ceil(N/8), N = number of pool variables) + * @param buffer + * @param size + * @param maxSize + * @param bigEndian + * @param withValidityBuffer + * @return + */ + ReturnValue_t serializeWithValidityBuffer(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const; + ReturnValue_t deSerializeWithValidityBuffer(const uint8_t** buffer, + size_t *size, SerializeIF::Endianness streamEndianness); + ReturnValue_t serializeLocalPoolIds(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness, + bool serializeFillCount = true) const; + uint8_t getLocalPoolIdsSerializedSize(bool serializeFillCount = true) const; + + /** + * Set the dataset valid or invalid. These calls are mutex protected. + * @param setEntriesRecursively + * If this is true, all contained datasets will also be set recursively. + */ + void setValidity(bool valid, bool setEntriesRecursively); + bool isValid() const override; + + /** + * These calls are mutex protected. + * @param changed + */ + void setChanged(bool changed) override; + bool hasChanged() const override; + +protected: + sid_t sid; + MutexIF* mutex = nullptr; + + bool diagnostic = false; + void setDiagnostic(bool diagnostics); + bool isDiagnostics() const; + + /** + * Used for periodic generation. + */ + bool reportingEnabled = false; + void setReportingEnabled(bool enabled); + bool getReportingEnabled() const; + + void initializePeriodicHelper(float collectionInterval, + dur_millis_t minimumPeriodicInterval, + bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5); + + /** + * If the valid state of a dataset is always relevant to the whole + * data set we can use this flag. + */ + bool valid = false; + + /** + * Can be used to mark the dataset as changed, which is used + * by the LocalDataPoolManager to send out update messages. + */ + bool changed = false; + + /** + * Specify whether the validity buffer is serialized too when serializing + * or deserializing the packet. Each bit of the validity buffer will + * contain the validity state of the pool variables from left to right. + * The size of validity buffer thus will be ceil(N / 8) with N = number of + * pool variables. + */ + bool withValidityBuffer = true; + + /** + * @brief This is a small helper function to facilitate locking + * the global data pool. + * @details + * It makes use of the lockDataPool method offered by the DataPool class. + */ + ReturnValue_t lockDataPool(uint32_t timeoutMs) override; + /** + * @brief This is a small helper function to facilitate + * unlocking the global data pool + * @details + * It makes use of the freeDataPoolLock method offered by the DataPool class. + */ + ReturnValue_t unlockDataPool() override; + + LocalDataPoolManager* hkManager; + + /** + * Set n-th bit of a byte, with n being the position from 0 + * (most significant bit) to 7 (least significant bit) + */ + void bitSetter(uint8_t* byte, uint8_t position) const; + bool bitGetter(const uint8_t* byte, uint8_t position) const; + + PeriodicHousekeepingHelper* periodicHelper = nullptr; + +}; + + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ */ diff --git a/datapoollocal/LocalPoolObjectBase.cpp b/datapoollocal/LocalPoolObjectBase.cpp new file mode 100644 index 00000000..b4d0e306 --- /dev/null +++ b/datapoollocal/LocalPoolObjectBase.cpp @@ -0,0 +1,73 @@ +#include "LocalPoolObjectBase.h" + +LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, + HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode): localPoolId(poolId), + readWriteMode(setReadWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " + << "which is the NO_PARAMETER value!" << std::endl; + } + if(hkOwner == nullptr) { + sif::error << "LocalPoolVar::LocalPoolVar: The supplied pool " + << "owner is a invalid!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, + DataSetIF *dataSet, pool_rwm_t setReadWriteMode): localPoolId(poolId), + readWriteMode(setReadWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " + << "which is the NO_PARAMETER value!" << std::endl; + } + HasLocalDataPoolIF* hkOwner = + objectManager->get(poolOwner); + if(hkOwner == nullptr) { + sif::error << "LocalPoolVariable: The supplied pool owner did not " + << "implement the correct interface" + << " HasLocalDataPoolIF!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + if(dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +pool_rwm_t LocalPoolObjectBase::getReadWriteMode() const { + return readWriteMode; +} + +bool LocalPoolObjectBase::isValid() const { + return valid; +} + +void LocalPoolObjectBase::setValid(bool valid) { + this->valid = valid; +} + +lp_id_t LocalPoolObjectBase::getDataPoolId() const { + return localPoolId; +} + +void LocalPoolObjectBase::setDataPoolId(lp_id_t poolId) { + this->localPoolId = poolId; +} + +void LocalPoolObjectBase::setChanged(bool changed) { + this->changed = changed; +} + +bool LocalPoolObjectBase::hasChanged() const { + return changed; +} + +void LocalPoolObjectBase::setReadWriteMode(pool_rwm_t newReadWriteMode) { + this->readWriteMode = newReadWriteMode; +} diff --git a/datapoollocal/LocalPoolObjectBase.h b/datapoollocal/LocalPoolObjectBase.h new file mode 100644 index 00000000..7165fc24 --- /dev/null +++ b/datapoollocal/LocalPoolObjectBase.h @@ -0,0 +1,63 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ + +#include "MarkChangedIF.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../datapool/PoolVariableIF.h" + + +class LocalPoolObjectBase: public PoolVariableIF, + public HasReturnvaluesIF, + public MarkChangedIF { +public: + LocalPoolObjectBase(lp_id_t poolId, + HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode); + + LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + void setReadWriteMode(pool_rwm_t newReadWriteMode); + pool_rwm_t getReadWriteMode() const; + + bool isValid() const override; + void setValid(bool valid) override; + + void setChanged(bool changed) override; + bool hasChanged() const override; + + lp_id_t getDataPoolId() const override; + void setDataPoolId(lp_id_t poolId); + +protected: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool id is stored. + */ + uint32_t localPoolId = PoolVariableIF::NO_PARAMETER; + /** + * @brief The valid information as it was stored in the data pool + * is copied to this attribute. + */ + bool valid = false; + + /** + * @brief A local pool variable can be marked as changed. + */ + bool changed = false; + + /** + * @brief The information whether the class is read-write or + * read-only is stored here. + */ + ReadWriteMode_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; + + //! @brief Pointer to the class which manages the HK pool. + LocalDataPoolManager* hkManager; + +}; + + + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ */ diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h new file mode 100644 index 00000000..c18d5443 --- /dev/null +++ b/datapoollocal/LocalPoolVariable.h @@ -0,0 +1,185 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ + +#include "LocalPoolObjectBase.h" +#include "HasLocalDataPoolIF.h" +#include "LocalDataPoolManager.h" + +#include "../datapool/PoolVariableIF.h" +#include "../datapool/DataSetIF.h" +#include "../objectmanager/ObjectManagerIF.h" +#include "../serialize/SerializeAdapter.h" + +/** + * @brief Local Pool Variable class which is used to access the local pools. + * @details + * This class is not stored in the map. Instead, it is used to access + * the pool entries by using a pointer to the map storing the pool + * entries. It can also be used to organize these pool entries into data sets. + * + * @tparam T The template parameter sets the type of the variable. Currently, + * all plain data types are supported, but in principle any type is possible. + * @ingroup data_pool + */ +template +class LocalPoolVar: public LocalPoolObjectBase { +public: + //! Default ctor is forbidden. + LocalPoolVar() = delete; + + /** + * This constructor is used by the data creators to have pool variable + * instances which can also be stored in datasets. + * + * It does not fetch the current value from the data pool, which + * has to be done by calling the read() operation. + * Datasets can be used to access multiple local pool entries in an + * efficient way. A pointer to a dataset can be passed to register + * the pool variable in that dataset directly. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + * @param setReadWriteMode Specify the read-write mode of the pool variable. + */ + LocalPoolVar(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + /** + * This constructor is used by data users like controllers to have + * access to the local pool variables of data creators by supplying + * the respective creator object ID. + * + * It does not fetch the current value from the data pool, which + * has to be done by calling the read() operation. + * Datasets can be used to access multiple local pool entries in an + * efficient way. A pointer to a dataset can be passed to register + * the pool variable in that dataset directly. + * @param poolId ID of the local pool entry. + * @param hkOwner object ID of the pool owner. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * + */ + LocalPoolVar(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * Variation which takes the global unique identifier of a pool variable. + * @param globalPoolId + * @param dataSet + * @param setReadWriteMode + */ + LocalPoolVar(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + virtual~ LocalPoolVar() {}; + + /** + * @brief This is the local copy of the data pool entry. + * @details The user can work on this attribute + * just like he would on a simple local variable. + */ + T value = 0; + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; + + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the data pool and copies all array values and the valid + * information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + * + */ + ReturnValue_t read(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief The commit call copies the array values back to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the local valid flag is written back as well. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; + + + LocalPoolVar &operator=(const T& newValue); + LocalPoolVar &operator=(const LocalPoolVar& newPoolVariable); + + //! Explicit type conversion operator. Allows casting the class to + //! its template type to perform operations on value. + explicit operator T() const; + + bool operator==(const LocalPoolVar& other) const; + bool operator==(const T& other) const; + + bool operator!=(const LocalPoolVar& other) const; + bool operator!=(const T& other) const; + + bool operator<(const LocalPoolVar& other) const; + bool operator<(const T& other) const; + + bool operator>(const LocalPoolVar& other) const; + bool operator>(const T& other) const; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + + // std::ostream is the type for object std::cout + template + friend std::ostream& operator<< (std::ostream &out, + const LocalPoolVar &var); + +private: +}; + +#include "LocalPoolVariable.tpp" + +template +using lp_var_t = LocalPoolVar; + +using lp_bool_t = LocalPoolVar; +using lp_uint8_t = LocalPoolVar; +using lp_uint16_t = LocalPoolVar; +using lp_uint32_t = LocalPoolVar; +using lp_uint64_t = LocalPoolVar; +using lp_int8_t = LocalPoolVar; +using lp_int16_t = LocalPoolVar; +using lp_int32_t = LocalPoolVar; +using lp_int64_t = LocalPoolVar; +using lp_float_t = LocalPoolVar; +using lp_double_t = LocalPoolVar; + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ */ diff --git a/datapoollocal/LocalPoolVariable.tpp b/datapoollocal/LocalPoolVariable.tpp new file mode 100644 index 00000000..b9f7b906 --- /dev/null +++ b/datapoollocal/LocalPoolVariable.tpp @@ -0,0 +1,169 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ + +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ +#error Include LocalPoolVariable.h before LocalPoolVariable.tpp! +#endif + +template +inline LocalPoolVar::LocalPoolVar(HasLocalDataPoolIF* hkOwner, + lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} + +template +inline LocalPoolVar::LocalPoolVar(object_id_t poolOwner, lp_id_t poolId, + DataSetIF *dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} + + +template +inline LocalPoolVar::LocalPoolVar(gp_id_t globalPoolId, DataSetIF *dataSet, + pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, + dataSet, setReadWriteMode){} + + +template +inline ReturnValue_t LocalPoolVar::read(dur_millis_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, + lockTimeout); + return readWithoutLock(); +} + +template +inline ReturnValue_t LocalPoolVar::readWithoutLock() { + if(readWriteMode == pool_rwm_t::VAR_WRITE) { + sif::debug << "LocalPoolVar: Invalid read write " + "mode for read() call." << std::endl; + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } + + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + if(result != RETURN_OK and poolEntry != nullptr) { + sif::error << "PoolVector: Read of local pool variable of object " + "0x" << std::hex << std::setw(8) << std::setfill('0') << + hkManager->getOwner() << " and lp ID 0x" << localPoolId << + std::dec << " failed.\n" << std::flush; + return result; + } + this->value = *(poolEntry->address); + this->valid = poolEntry->valid; + return RETURN_OK; +} + +template +inline ReturnValue_t LocalPoolVar::commit(dur_millis_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, + lockTimeout); + return commitWithoutLock(); +} + +template +inline ReturnValue_t LocalPoolVar::commitWithoutLock() { + if(readWriteMode == pool_rwm_t::VAR_READ) { + sif::debug << "LocalPoolVar: Invalid read write " + "mode for commit() call." << std::endl; + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + if(result != RETURN_OK) { + sif::error << "PoolVector: Read of local pool variable of object " + "0x" << std::hex << std::setw(8) << std::setfill('0') << + hkManager->getOwner() << " and lp ID 0x" << localPoolId << + std::dec << " failed.\n" << std::flush; + return result; + } + *(poolEntry->address) = this->value; + poolEntry->valid = this->valid; + return RETURN_OK; +} + +template +inline ReturnValue_t LocalPoolVar::serialize(uint8_t** buffer, size_t* size, + const size_t max_size, SerializeIF::Endianness streamEndianness) const { + return SerializeAdapter::serialize(&value, + buffer, size ,max_size, streamEndianness); +} + +template +inline size_t LocalPoolVar::getSerializedSize() const { + return SerializeAdapter::getSerializedSize(&value); +} + +template +inline ReturnValue_t LocalPoolVar::deSerialize(const uint8_t** buffer, + size_t* size, SerializeIF::Endianness streamEndianness) { + return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness); +} + +template +inline std::ostream& operator<< (std::ostream &out, + const LocalPoolVar &var) { + out << var.value; + return out; +} + +template +inline LocalPoolVar::operator T() const { + return value; +} + +template +inline LocalPoolVar & LocalPoolVar::operator=(const T& newValue) { + value = newValue; + return *this; +} + +template +inline LocalPoolVar& LocalPoolVar::operator =( + const LocalPoolVar& newPoolVariable) { + value = newPoolVariable.value; + return *this; +} + +template +inline bool LocalPoolVar::operator ==(const LocalPoolVar &other) const { + return this->value == other.value; +} + +template +inline bool LocalPoolVar::operator ==(const T &other) const { + return this->value == other; +} + + +template +inline bool LocalPoolVar::operator !=(const LocalPoolVar &other) const { + return not (*this == other); +} + +template +inline bool LocalPoolVar::operator !=(const T &other) const { + return not (*this == other); +} + + +template +inline bool LocalPoolVar::operator <(const LocalPoolVar &other) const { + return this->value < other.value; +} + +template +inline bool LocalPoolVar::operator <(const T &other) const { + return this->value < other; +} + + +template +inline bool LocalPoolVar::operator >(const LocalPoolVar &other) const { + return not (*this < other); +} + +template +inline bool LocalPoolVar::operator >(const T &other) const { + return not (*this < other); +} + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */ diff --git a/datapoollocal/LocalPoolVector.h b/datapoollocal/LocalPoolVector.h new file mode 100644 index 00000000..58face3c --- /dev/null +++ b/datapoollocal/LocalPoolVector.h @@ -0,0 +1,174 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ + +#include "LocalPoolObjectBase.h" +#include "../datapool/DataSetIF.h" +#include "../datapool/PoolEntry.h" +#include "../datapool/PoolVariableIF.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../serialize/SerializeAdapter.h" +#include "../serviceinterface/ServiceInterfaceStream.h" + + +/** + * @brief This is the access class for array-type data pool entries. + * @details + * To ensure safe usage of the data pool, operation is not done directly on the + * data pool entries, but on local copies. This class provides simple type- + * and length-safe access to vector-style data pool entries (i.e. entries with + * length > 1). The class can be instantiated as read-write and read only. + * + * It provides a commit-and-roll-back semantic, which means that no array + * entry in the data pool is changed until the commit call is executed. + * There are two template parameters: + * @tparam T + * This template parameter specifies the data type of an array entry. Currently, + * all plain data types are supported, but in principle any type is possible. + * @tparam vector_size + * This template parameter specifies the vector size of this entry. Using a + * template parameter for this is not perfect, but avoids + * dynamic memory allocation. + * @ingroup data_pool + */ +template +class LocalPoolVector: public LocalPoolObjectBase { +public: + LocalPoolVector() = delete; + /** + * This constructor is used by the data creators to have pool variable + * instances which can also be stored in datasets. + * It does not fetch the current value from the data pool. This is performed + * by the read() operation (which is not thread-safe). + * Datasets can be used to access local pool entires in a thread-safe way. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + /** + * This constructor is used by data users like controllers to have + * access to the local pool variables of data creators by supplying + * the respective creator object ID. + * It does not fetch the current value from the data pool. This is performed + * by the read() operation (which is not thread-safe). + * Datasets can be used to access local pool entires in a thread-safe way. + * @param poolId ID of the local pool entry. + * @param hkOwner Pointer of the owner. This will generally be the calling + * class itself which passes "this". + * @param setReadWriteMode Specify the read-write mode of the pool variable. + * @param dataSet The data set in which the variable shall register itself. + * If nullptr, the variable is not registered. + */ + LocalPoolVector(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * Variation which takes the unique global identifier of a local pool + * vector. + * @param globalPoolId + * @param dataSet + * @param setReadWriteMode + */ + LocalPoolVector(gp_id_t globalPoolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + /** + * @brief This is the local copy of the data pool entry. + * @details + * The user can work on this attribute just like he would on a local + * array of this type. + */ + T value[vectorSize]; + /** + * @brief The classes destructor is empty. + * @details If commit() was not called, the local value is + * discarded and not written back to the data pool. + */ + ~LocalPoolVector() {}; + /** + * @brief The operation returns the number of array entries + * in this variable. + */ + uint8_t getSize() { + return vectorSize; + } + + T& operator [](int i); + const T &operator [](int i) const; + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t maxSize, + SerializeIF::Endianness streamEndiannes) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override; + + /** + * @brief This is a call to read the array's values + * from the global data pool. + * @details + * When executed, this operation tries to fetch the pool entry with matching + * data pool id from the data pool and copies all array values and the valid + * information to its local attributes. + * In case of a failure (wrong type, size or pool id not found), the + * variable is set to zero and invalid. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t read(uint32_t lockTimeout = MutexIF::BLOCKING) override; + /** + * @brief The commit call copies the array values back to the data pool. + * @details + * It checks type and size, as well as if the variable is writable. If so, + * the value is copied and the local valid flag is written back as well. + * The read call is protected with a lock. + * It is recommended to use DataSets to read and commit multiple variables + * at once to avoid the overhead of unnecessary lock und unlock operations. + */ + ReturnValue_t commit(uint32_t lockTimeout = MutexIF::BLOCKING) override; + +protected: + /** + * @brief Like #read, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t readWithoutLock() override; + /** + * @brief Like #commit, but without a lock protection of the global pool. + * @details + * The operation does NOT provide any mutual exclusive protection by itself. + * This can be used if the lock is handled externally to avoid the overhead + * of consecutive lock und unlock operations. + * Declared protected to discourage free public usage. + */ + ReturnValue_t commitWithoutLock() override; + +private: + + + // std::ostream is the type for object std::cout + template + friend std::ostream& operator<< (std::ostream &out, + const LocalPoolVector &var); + + +}; + +#include "LocalPoolVector.tpp" + +template +using lp_vec_t = LocalPoolVector; + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ */ diff --git a/datapoollocal/LocalPoolVector.tpp b/datapoollocal/LocalPoolVector.tpp new file mode 100644 index 00000000..46123ccc --- /dev/null +++ b/datapoollocal/LocalPoolVector.tpp @@ -0,0 +1,158 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ + +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#error Include LocalPoolVector.h before LocalPoolVector.tpp! +#endif + +template +inline LocalPoolVector::LocalPoolVector( + HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} + +template +inline LocalPoolVector::LocalPoolVector(object_id_t poolOwner, + lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} + + +template +inline LocalPoolVector::LocalPoolVector(gp_id_t globalPoolId, + DataSetIF *dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, + dataSet, setReadWriteMode) {} + +template +inline ReturnValue_t LocalPoolVector::read(uint32_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, + lockTimeout); + return readWithoutLock(); +} +template +inline ReturnValue_t LocalPoolVector::readWithoutLock() { + if(readWriteMode == pool_rwm_t::VAR_WRITE) { + sif::debug << "LocalPoolVar: Invalid read write " + "mode for read() call." << std::endl; + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } + + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + memset(this->value, 0, vectorSize * sizeof(T)); + + if(result != RETURN_OK) { + sif::error << "PoolVector: Read of local pool variable of object " + "0x" << std::hex << std::setw(8) << std::setfill('0') << + hkManager->getOwner() << "and lp ID 0x" << localPoolId << + std::dec << " failed." << std::endl; + return result; + } + std::memcpy(this->value, poolEntry->address, poolEntry->getByteSize()); + this->valid = poolEntry->valid; + return RETURN_OK; +} + +template +inline ReturnValue_t LocalPoolVector::commit( + uint32_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, + lockTimeout); + return commitWithoutLock(); +} + +template +inline ReturnValue_t LocalPoolVector::commitWithoutLock() { + if(readWriteMode == pool_rwm_t::VAR_READ) { + sif::debug << "LocalPoolVar: Invalid read write " + "mode for commit() call." << std::endl; + return PoolVariableIF::INVALID_READ_WRITE_MODE; + } + PoolEntry* poolEntry = nullptr; + ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + if(result != RETURN_OK) { + sif::error << "PoolVector: Read of local pool variable of object " + "0x" << std::hex << std::setw(8) << std::setfill('0') << + hkManager->getOwner() << " and lp ID 0x" << localPoolId << + std::dec << " failed.\n" << std::flush; + return result; + } + std::memcpy(poolEntry->address, this->value, poolEntry->getByteSize()); + poolEntry->valid = this->valid; + return RETURN_OK; +} + +template +inline T& LocalPoolVector::operator [](int i) { + if(i <= vectorSize) { + return value[i]; + } + // If this happens, I have to set some value. I consider this + // a configuration error, but I wont exit here. + sif::error << "LocalPoolVector: Invalid index. Setting or returning" + " last value!" << std::endl; + return value[i]; +} + +template +inline const T& LocalPoolVector::operator [](int i) const { + if(i <= vectorSize) { + return value[i]; + } + // If this happens, I have to set some value. I consider this + // a configuration error, but I wont exit here. + sif::error << "LocalPoolVector: Invalid index. Setting or returning" + " last value!" << std::endl; + return value[i]; +} + +template +inline ReturnValue_t LocalPoolVector::serialize(uint8_t** buffer, + size_t* size, size_t maxSize, + SerializeIF::Endianness streamEndianness) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t i = 0; i < vectorSize; i++) { + result = SerializeAdapter::serialize(&(value[i]), buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + break; + } + } + return result; +} + +template +inline size_t LocalPoolVector::getSerializedSize() const { + return vectorSize * SerializeAdapter::getSerializedSize(value); +} + +template +inline ReturnValue_t LocalPoolVector::deSerialize( + const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t i = 0; i < vectorSize; i++) { + result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, + streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + break; + } + } + return result; +} + +template +inline std::ostream& operator<< (std::ostream &out, + const LocalPoolVector &var) { + out << "Vector: ["; + for(int i = 0;i < vectorSize; i++) { + out << var.value[i]; + if(i < vectorSize - 1) { + out << ", "; + } + } + out << "]"; + return out; +} + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ */ diff --git a/datapoollocal/MarkChangedIF.h b/datapoollocal/MarkChangedIF.h new file mode 100644 index 00000000..e575d1d3 --- /dev/null +++ b/datapoollocal/MarkChangedIF.h @@ -0,0 +1,17 @@ +#ifndef FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ +#define FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ + +/** + * Common interface for local pool entities which can be marked as changed. + */ +class MarkChangedIF { +public: + virtual~ MarkChangedIF() {}; + + virtual bool hasChanged() const = 0; + virtual void setChanged(bool changed) = 0; +}; + + + +#endif /* FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ */ diff --git a/datapoollocal/SharedLocalDataSet.cpp b/datapoollocal/SharedLocalDataSet.cpp new file mode 100644 index 00000000..dd1bdcc4 --- /dev/null +++ b/datapoollocal/SharedLocalDataSet.cpp @@ -0,0 +1,16 @@ +#include "SharedLocalDataSet.h" + +SharedLocalDataSet::SharedLocalDataSet(object_id_t objectId, sid_t sid, + const size_t maxSize): SystemObject(objectId), + LocalPoolDataSetBase(sid, nullptr, maxSize) { + this->setContainer(poolVarVector.data()); + datasetLock = MutexFactory::instance()->createMutex(); +} + +ReturnValue_t SharedLocalDataSet::lockDataset(dur_millis_t mutexTimeout) { + return datasetLock->lockMutex(MutexIF::TimeoutType::WAITING, mutexTimeout); +} + +ReturnValue_t SharedLocalDataSet::unlockDataset() { + return datasetLock->unlockMutex(); +} diff --git a/datapoollocal/SharedLocalDataSet.h b/datapoollocal/SharedLocalDataSet.h new file mode 100644 index 00000000..2e5a76fa --- /dev/null +++ b/datapoollocal/SharedLocalDataSet.h @@ -0,0 +1,24 @@ +#ifndef FSFW_DATAPOOLLOCAL_SHAREDLOCALDATASET_H_ +#define FSFW_DATAPOOLLOCAL_SHAREDLOCALDATASET_H_ + +#include "LocalPoolDataSetBase.h" +#include "../datapool/SharedDataSetIF.h" +#include "../objectmanager/SystemObject.h" +#include + +class SharedLocalDataSet: public SystemObject, + public LocalPoolDataSetBase, + public SharedDataSetIF { +public: + SharedLocalDataSet(object_id_t objectId, sid_t sid, + const size_t maxSize); + ReturnValue_t lockDataset(dur_millis_t mutexTimeout) override; + ReturnValue_t unlockDataset() override; +private: + + MutexIF* datasetLock = nullptr; + std::vector poolVarVector; +}; + + +#endif /* FSFW_DATAPOOLLOCAL_SHAREDLOCALDATASET_H_ */ diff --git a/datapoollocal/StaticLocalDataSet.h b/datapoollocal/StaticLocalDataSet.h new file mode 100644 index 00000000..a637e360 --- /dev/null +++ b/datapoollocal/StaticLocalDataSet.h @@ -0,0 +1,50 @@ +#ifndef FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ +#define FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ + +#include "LocalPoolDataSetBase.h" +#include "../objectmanager/SystemObjectIF.h" +#include + +/** + * @brief This local dataset type is created on the stack. + * @details + * This will is the primary data structure to organize pool variables into + * sets which can be accessed via the housekeeping service interface or + * which can be sent to other software objects. + * + * It is recommended to read the documentation of the LocalPoolDataSetBase + * class for more information on how this class works and how to use it. + * @tparam capacity Capacity of the static dataset, which is usually known + * beforehand. + */ +template +class StaticLocalDataSet: public LocalPoolDataSetBase { +public: + /** + * Constructor used by data owner and creator like device handlers. + * This constructor also initialized the components required for + * periodic handling. + * @param hkOwner + * @param setId + */ + StaticLocalDataSet(HasLocalDataPoolIF* hkOwner, + uint32_t setId): LocalPoolDataSetBase(hkOwner, setId, nullptr, + NUM_VARIABLES) { + this->setContainer(poolVarList.data()); + } + + /** + * Constructor used by data users like controllers. + * @param hkOwner + * @param setId + */ + StaticLocalDataSet(sid_t sid): LocalPoolDataSetBase(sid, nullptr, + NUM_VARIABLES) { + this->setContainer(poolVarList.data()); + } + +private: + std::array poolVarList; +}; + +#endif /* FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ */ diff --git a/datapoollocal/locPoolDefinitions.h b/datapoollocal/locPoolDefinitions.h new file mode 100644 index 00000000..6e74d349 --- /dev/null +++ b/datapoollocal/locPoolDefinitions.h @@ -0,0 +1,93 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ +#define FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ + +#include +#include "../objectmanager/SystemObjectIF.h" +#include "../objectmanager/frameworkObjects.h" + +/** + * @brief Type definition for local pool entries. + */ +using lp_id_t = uint32_t; + +namespace localpool { +static constexpr uint32_t INVALID_LPID = -1; +} + +/** + * Used as a unique identifier for data sets. + */ +union sid_t { + static constexpr uint64_t INVALID_SID = -1; + static constexpr uint32_t INVALID_OBJECT_ID = objects::NO_OBJECT; + static constexpr uint32_t INVALID_SET_ID = -1; + + + sid_t(): raw(INVALID_SID) {} + + sid_t(object_id_t objectId, uint32_t setId): + objectId(objectId), + ownerSetId(setId) {} + + struct { + object_id_t objectId ; + /** + * A generic 32 bit ID to identify unique HK packets for a single + * object. For example, the DeviceCommandId_t is used for + * DeviceHandlers + */ + uint32_t ownerSetId; + }; + /** + * Alternative access to the raw value. This is also the size of the type. + */ + uint64_t raw; + + bool notSet() const { + return raw == INVALID_SID; + } + + bool operator==(const sid_t& other) const { + return raw == other.raw; + } + + bool operator!=(const sid_t& other) const { + return not (raw == other.raw); + } +}; + +/** + * Used as a global unique identifier for local pool variables. + */ +union gp_id_t { + static constexpr uint64_t INVALID_GPID = -1; + static constexpr uint32_t INVALID_OBJECT_ID = objects::NO_OBJECT; + static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID; + + gp_id_t(): raw(INVALID_GPID) {} + + gp_id_t(object_id_t objectId, lp_id_t localPoolId): + objectId(objectId), + localPoolId(localPoolId) {} + + struct { + object_id_t objectId; + lp_id_t localPoolId; + }; + + uint64_t raw; + + bool notSet() const { + return raw == INVALID_GPID; + } + + bool operator==(const sid_t& other) const { + return raw == other.raw; + } + + bool operator!=(const sid_t& other) const { + return not (raw == other.raw); + } +}; + +#endif /* FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ */ diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 710e8a83..e6c15f9e 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -2,15 +2,17 @@ #include "AcceptsDeviceResponsesIF.h" #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" -#include "../datapool/DataSet.h" -#include "../datapool/PoolVariable.h" #include "../globalfunctions/CRC.h" -#include "../subsystem/SubsystemBase.h" +#include "../housekeeping/HousekeepingMessage.h" +#include "../ipc/MessageQueueMessage.h" #include "../ipc/QueueFactory.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../subsystem/SubsystemBase.h" #include @@ -25,10 +27,11 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), deviceCommunicationId(deviceCommunication), comCookie(comCookie), healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), - actionHelper(this, nullptr), childTransitionFailure(RETURN_OK), - fdirInstance(fdirInstance), hkSwitcher(this), - defaultFDIRUsed(fdirInstance == nullptr), switchOffWasReported(false), - childTransitionDelay(5000), transitionSourceMode(_MODE_POWER_DOWN), + actionHelper(this, nullptr), hkManager(this, nullptr), + childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), + hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), + switchOffWasReported(false), childTransitionDelay(5000), + transitionSourceMode(_MODE_POWER_DOWN), transitionSourceSubMode(SUBMODE_NONE) { commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE); @@ -48,6 +51,10 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, } } +void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) { + this->hkDestination = hkDestination; +} + void DeviceHandlerBase::setThermalStateRequestPoolIds( uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId) { this->deviceThermalRequestPoolId = thermalStatePoolId; @@ -74,6 +81,7 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { decrementDeviceReplyMap(); fdirInstance->checkForFailures(); hkSwitcher.performOperation(); + hkManager.performHkOperation(); performOperationHook(); } if (mode == MODE_OFF) { @@ -120,7 +128,9 @@ ReturnValue_t DeviceHandlerBase::initialize() { result = communicationInterface->initializeInterface(comCookie); if (result != RETURN_OK) { - return result; + sif::error << "DeviceHandlerBase::initialize: Initializing " + "communication interface failed!" << std::endl; + return result; } IPCStore = objectManager->get(objects::IPC_STORE); @@ -183,11 +193,16 @@ ReturnValue_t DeviceHandlerBase::initialize() { return result; } + result = hkManager.initialize(commandQueue); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + fillCommandAndReplyMap(); //Set temperature target state to NON_OP. - DataSet mySet; - db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet, + GlobDataSet mySet; + gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, PoolVariableIF::VAR_WRITE); mySet.read(); thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; @@ -245,10 +260,10 @@ void DeviceHandlerBase::readCommandQueue() { return; } -// result = hkManager.handleHousekeepingMessage(&command); -// if (result == RETURN_OK) { -// return; -// } + result = hkManager.handleHousekeepingMessage(&command); + if (result == RETURN_OK) { + return; + } result = handleDeviceHandlerMessage(&command); if (result == RETURN_OK) { @@ -376,24 +391,28 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap( DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, - size_t replyLen, bool periodic, bool hasDifferentReplyId, - DeviceCommandId_t replyId) { + LocalPoolDataSetBase* replyDataSet, size_t replyLen, bool periodic, + bool hasDifferentReplyId, DeviceCommandId_t replyId) { //No need to check, as we may try to insert multiple times. insertInCommandMap(deviceCommand); if (hasDifferentReplyId) { - return insertInReplyMap(replyId, maxDelayCycles, replyLen, periodic); + return insertInReplyMap(replyId, maxDelayCycles, + replyDataSet, replyLen, periodic); } else { - return insertInReplyMap(deviceCommand, maxDelayCycles, replyLen, periodic); + return insertInReplyMap(deviceCommand, maxDelayCycles, + replyDataSet, replyLen, periodic); } } ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId, - uint16_t maxDelayCycles, size_t replyLen, bool periodic) { + uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet, + size_t replyLen, bool periodic) { DeviceReplyInfo info; info.maxDelayCycles = maxDelayCycles; info.periodic = periodic; info.delayCycles = 0; info.replyLen = replyLen; + info.dataSet = dataSet; info.command = deviceCommandMap.end(); auto resultPair = deviceReplyMap.emplace(replyId, info); if (resultPair.second) { @@ -419,13 +438,12 @@ ReturnValue_t DeviceHandlerBase::insertInCommandMap( ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply, uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic) { - std::map::iterator iter = - deviceReplyMap.find(deviceReply); - if (iter == deviceReplyMap.end()) { + auto replyIter = deviceReplyMap.find(deviceReply); + if (replyIter == deviceReplyMap.end()) { triggerEvent(INVALID_DEVICE_COMMAND, deviceReply); return RETURN_FAILED; } else { - DeviceReplyInfo *info = &(iter->second); + DeviceReplyInfo *info = &(replyIter->second); if (maxDelayCycles != 0) { info->maxDelayCycles = maxDelayCycles; } @@ -435,6 +453,17 @@ ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceRep } } + +ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId, + LocalPoolDataSetBase *dataSet) { + auto replyIter = deviceReplyMap.find(replyId); + if(replyIter == deviceReplyMap.end()) { + return HasReturnvaluesIF::RETURN_FAILED; + } + replyIter->second.dataSet = dataSet; + return HasReturnvaluesIF::RETURN_OK; +} + void DeviceHandlerBase::callChildStatemachine() { if (mode == _MODE_START_UP) { doStartUp(); @@ -469,8 +498,8 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) { Clock::getUptime(&timeoutStart); if (mode == MODE_OFF) { - DataSet mySet; - db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet, + GlobDataSet mySet; + gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { @@ -649,7 +678,7 @@ void DeviceHandlerBase::doGetRead() { void DeviceHandlerBase::parseReply(const uint8_t* receivedData, size_t receivedDataLen) { ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; - DeviceCommandId_t foundId = 0xFFFFFFFF; + DeviceCommandId_t foundId = DeviceHandlerIF::NO_COMMAND; size_t foundLen = 0; // The loop may not execute more often than the number of received bytes // (worst case). This approach avoids infinite loops due to buggy @@ -661,18 +690,26 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData, switch (result) { case RETURN_OK: handleReply(receivedData, foundId, foundLen); + if(foundLen == 0) { + sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" + " Packet parsing will be stuck." << std::endl; + } break; case APERIODIC_REPLY: { result = interpretDeviceReply(foundId, receivedData); if (result != RETURN_OK) { - replyRawReplyIfnotWiretapped(receivedData, foundLen); - triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, - foundId); + replyRawReplyIfnotWiretapped(receivedData, foundLen); + triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, + foundId); + } + if(foundLen == 0) { + sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" + " Packet parsing will be stuck." << std::endl; } - } - break; - case IGNORE_REPLY_DATA: break; + } + case IGNORE_REPLY_DATA: + continue; case IGNORE_FULL_PACKET: return; default: @@ -704,16 +741,19 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceReplyInfo *info = &(iter->second); if (info->delayCycles != 0) { + result = interpretDeviceReply(foundId, receivedData); - if (info->periodic != false) { + if(result == IGNORE_REPLY_DATA) { + return; + } + + if (info->periodic) { info->delayCycles = info->maxDelayCycles; } else { info->delayCycles = 0; } - result = interpretDeviceReply(foundId, receivedData); - if (result != RETURN_OK) { // Report failed interpretation to FDIR. replyRawReplyIfnotWiretapped(receivedData, foundLen); @@ -926,10 +966,10 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, if ((commandedMode == MODE_ON) && (mode == MODE_OFF) && (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) { - DataSet mySet; - db_int8_t thermalState(deviceThermalStatePoolId, &mySet, + GlobDataSet mySet; + gp_uint8_t thermalState(deviceThermalStatePoolId, &mySet, PoolVariableIF::VAR_READ); - db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet, + gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet, PoolVariableIF::VAR_READ); mySet.read(); if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { @@ -956,8 +996,8 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON); triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); - DataSet mySet; - db_int8_t thermalRequest(deviceThermalRequestPoolId, + GlobDataSet mySet; + gp_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { @@ -1089,19 +1129,6 @@ ReturnValue_t DeviceHandlerBase::handleDeviceHandlerMessage( } replyReturnvalueToCommand(RETURN_OK); return RETURN_OK; -// case DeviceHandlerMessage::CMD_SWITCH_IOBOARD: -// if (mode != MODE_OFF) { -// replyReturnvalueToCommand(WRONG_MODE_FOR_COMMAND); -// } else { -// result = switchCookieChannel( -// DeviceHandlerMessage::getIoBoardObjectId(message)); -// if (result == RETURN_OK) { -// replyReturnvalueToCommand(RETURN_OK); -// } else { -// replyReturnvalueToCommand(CANT_SWITCH_IO_ADDRESS); -// } -// } -// return RETURN_OK; case DeviceHandlerMessage::CMD_RAW: if ((mode != MODE_RAW)) { DeviceHandlerMessage::clear(message); @@ -1185,7 +1212,7 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data, } //Try to cast to GlobDataSet and commit data. if (!neverInDataPool) { - DataSet* dataSet = dynamic_cast(data); + GlobDataSet* dataSet = dynamic_cast(data); if (dataSet != NULL) { dataSet->commit(PoolVariableIF::VALID); } @@ -1248,10 +1275,14 @@ void DeviceHandlerBase::buildInternalCommand(void) { if (iter == deviceCommandMap.end()) { result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { + //so we can track misconfigurations sif::debug << std::hex << getObjectId() << ": DHB::buildInternalCommand: Command " - << deviceCommandId << " isExecuting" << std::endl; //so we can track misconfigurations - return; //this is an internal command, no need to report a failure here, missed reply will track if a reply is too late, otherwise, it's ok + << deviceCommandId << " isExecuting" << std::dec + << std::endl; + // this is an internal command, no need to report a failure here, + // missed reply will track if a reply is too late, otherwise, it's ok + return; } else { iter->second.sendReplyTo = NO_COMMANDER; iter->second.isExecuting = true; @@ -1340,12 +1371,50 @@ void DeviceHandlerBase::debugInterface(uint8_t positionTracker, void DeviceHandlerBase::performOperationHook() { } +ReturnValue_t DeviceHandlerBase::initializeLocalDataPool( + LocalDataPool &localDataPoolMap, + LocalDataPoolManager& poolManager) { + return RETURN_OK; +} + +LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { + return &hkManager; +} + + ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { // In this function, the task handle should be valid if the task // was implemented correctly. We still check to be 1000 % sure :-) if(executingTask != nullptr) { pstIntervalMs = executingTask->getPeriodMs(); } + this->hkManager.initializeAfterTaskCreation(); + + if(setStartupImmediately) { + startTransition(MODE_ON, SUBMODE_NONE); + } return HasReturnvaluesIF::RETURN_OK; } +LocalPoolDataSetBase* DeviceHandlerBase::getDataSetHandle(sid_t sid) { + auto iter = deviceReplyMap.find(sid.ownerSetId); + if(iter != deviceReplyMap.end()) { + return iter->second.dataSet; + } + else { + return nullptr; + } +} + +object_id_t DeviceHandlerBase::getObjectId() const { + return SystemObject::getObjectId(); +} + +void DeviceHandlerBase::setStartUpImmediately() { + this->setStartupImmediately = true; +} + +dur_millis_t DeviceHandlerBase::getPeriodicOperationFrequency() const { + return pstIntervalMs; +} + diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 5666f35e..eda318cb 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -1,12 +1,11 @@ -#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ -#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ +#ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ +#define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ #include "DeviceHandlerIF.h" #include "DeviceCommunicationIF.h" #include "DeviceHandlerFailureIsolation.h" #include "../objectmanager/SystemObject.h" -#include "../tasks/PeriodicTaskIF.h" #include "../tasks/ExecutableObjectIF.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../action/HasActionsIF.h" @@ -14,10 +13,13 @@ #include "../modes/HasModesIF.h" #include "../power/PowerSwitchIF.h" #include "../ipc/MessageQueueIF.h" +#include "../tasks/PeriodicTaskIF.h" #include "../action/ActionHelper.h" #include "../health/HealthHelper.h" #include "../parameters/ParameterHelper.h" #include "../datapool/HkSwitchHelper.h" +#include "../datapoollocal/HasLocalDataPoolIF.h" +#include "../datapoollocal/LocalDataPoolManager.h" #include @@ -38,17 +40,16 @@ class StorageManagerIF; * Documentation: Dissertation Baetz p.138,139, p.141-149 * * It features handling of @link DeviceHandlerIF::Mode_t Modes @endlink, - * communication with physical devices, using the @link DeviceCommunicationIF @endlink, - * and communication with commanding objects. - * It inherits SystemObject and thus can be created by the ObjectManagerIF. + * communication with physical devices, using the + * @link DeviceCommunicationIF @endlink, and communication with commanding + * objects. It inherits SystemObject and thus can be created by the + * ObjectManagerIF. * - * This class uses the opcode of ExecutableObjectIF to perform a step-wise execution. - * For each step an RMAP action is selected and executed. - * If data has been received (GET_READ), the data will be interpreted. - * The action for each step can be defined by the child class but as most - * device handlers share a 4-call (sendRead-getRead-sendWrite-getWrite) structure, - * a default implementation is provided. - * NOTE: RMAP is a standard which is used for FLP. + * This class uses the opcode of ExecutableObjectIF to perform a + * step-wise execution. For each step a different action is selected and + * executed. Currently, the device handler base performs a 4-step + * execution related to 4 communication steps (based on RMAP). + * NOTE: RMAP is a standard which is used for Flying Laptop. * RMAP communication is not mandatory for projects implementing the FSFW. * However, the communication principles are similar to RMAP as there are * two write and two send calls involved. @@ -69,9 +70,6 @@ class StorageManagerIF; * * Other important virtual methods with a default implementation * are the getTransitionDelayMs() function and the getSwitches() function. - * Please ensure that getSwitches() returns DeviceHandlerIF::NO_SWITCHES if - * power switches are not implemented yet. Otherwise, the device handler will - * not transition to MODE_ON, even if setMode(MODE_ON) is called. * If a transition to MODE_ON is desired without commanding, override the * intialize() function and call setMode(_MODE_START_UP) before calling * DeviceHandlerBase::initialize(). @@ -85,20 +83,18 @@ class DeviceHandlerBase: public DeviceHandlerIF, public HasModesIF, public HasHealthIF, public HasActionsIF, - public ReceivesParameterMessagesIF { + public ReceivesParameterMessagesIF, + public HasLocalDataPoolIF { friend void (Factory::setStaticFrameworkObjectIds)(); public: /** * The constructor passes the objectId to the SystemObject(). * * @param setObjectId the ObjectId to pass to the SystemObject() Constructor - * @param maxDeviceReplyLen the length the RMAP getRead call will be sent with - * @param setDeviceSwitch the switch the device is connected to, - * for devices using two switches, overwrite getSwitches() * @param deviceCommuncation Communcation Interface object which is used * to implement communication functions - * @param thermalStatePoolId - * @param thermalRequestPoolId + * @param comCookie This object will be passed to the communication inter- + * face and can contain user-defined information about the communication. * @param fdirInstance * @param cmdQueueSize */ @@ -106,8 +102,21 @@ public: CookieIF * comCookie, FailureIsolationBase* fdirInstance = nullptr, size_t cmdQueueSize = 20); + void setHkDestination(object_id_t hkDestination); void setThermalStateRequestPoolIds(uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId); + /** + * @brief Helper function to ease device handler development. + * This will instruct the transition to MODE_ON immediately + * (leading to doStartUp() being called for the transition to the ON mode), + * so external mode commanding is not necessary anymore. + * + * This has to be called before the task is started! + * (e.g. in the task factory). This is only a helper function for + * development. Regular mode commanding should be performed by commanding + * the AssemblyBase or Subsystem objects resposible for the device handler. + */ + void setStartUpImmediately(); /** * @brief This function is the device handler base core component and is @@ -153,6 +162,14 @@ public: * @return */ virtual ReturnValue_t initialize(); + + /** + * @brief Intialization steps performed after all tasks have been created. + * This function will be called by the executing task. + * @return + */ + virtual ReturnValue_t initializeAfterTaskCreation() override; + /** Destructor. */ virtual ~DeviceHandlerBase(); @@ -320,6 +337,8 @@ protected: * @param packet * @return * - @c RETURN_OK when the reply was interpreted. + * - @c IGNORE_REPLY_DATA Ignore the reply and don't reset reply cycle + * counter. * - @c RETURN_FAILED when the reply could not be interpreted, * e.g. logical errors or range violations occurred */ @@ -347,22 +366,10 @@ protected: * set to the maximum expected number of PST cycles between two replies * (also a tolerance should be added, as an FDIR message will be * generated if it is missed). - * - * (Robin) This part confuses me. "must do as soon as" implies that - * the developer must do something somewhere else in the code. Is - * that really the case? If I understood correctly, DHB performs - * almost everything (e.g. in erirm function) as long as the commands - * are inserted correctly. - * - * As soon as the replies are enabled, DeviceCommandInfo.periodic must - * be set to true, DeviceCommandInfo.delayCycles to - * DeviceCommandInfo.maxDelayCycles. * From then on, the base class handles the reception. * Then, scanForReply returns the id of the reply or the placeholder id * and the base class will take care of checking that all replies are * received and the interval is correct. - * When the replies are disabled, DeviceCommandInfo.periodic must be set - * to 0, DeviceCommandInfo.delayCycles to 0; * * - Aperiodic, unrequested replies. These are replies that are sent * by the device without any preceding command and not in a defined @@ -376,13 +383,17 @@ protected: * @param deviceCommand Identifier of the command to add. * @param maxDelayCycles The maximum number of delay cycles the command * waits until it times out. + * @param replyLen Will be supplied to the requestReceiveMessage call of + * the communication interface. * @param periodic Indicates if the command is periodic (i.e. it is sent * by the device repeatedly without request) or not. Default is aperiodic (0) * @return - @c RETURN_OK when the command was successfully inserted, * - @c RETURN_FAILED else. */ ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false, + uint16_t maxDelayCycles, + LocalPoolDataSetBase* replyDataSet = nullptr, + size_t replyLen = 0, bool periodic = false, bool hasDifferentReplyId = false, DeviceCommandId_t replyId = 0); /** @@ -396,7 +407,8 @@ protected: * - @c RETURN_FAILED else. */ ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, - uint16_t maxDelayCycles, size_t replyLen = 0, bool periodic = false); + uint16_t maxDelayCycles, LocalPoolDataSetBase* dataSet = nullptr, + size_t replyLen = 0, bool periodic = false); /** * @brief A simple command to add a command to the commandList. @@ -424,6 +436,9 @@ protected: uint16_t delayCycles, uint16_t maxDelayCycles, bool periodic = false); + ReturnValue_t setReplyDataset(DeviceCommandId_t replyId, + LocalPoolDataSetBase* dataset); + /** * @brief Can be implemented by child handler to * perform debugging @@ -477,18 +492,22 @@ protected: * @param localDataPoolMap * @return */ - //virtual ReturnValue_t initializePoolEntries( - // LocalDataPool& localDataPoolMap) override; + virtual ReturnValue_t initializeLocalDataPool(LocalDataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; /** Get the HK manager object handle */ - //virtual LocalDataPoolManager* getHkManagerHandle() override; + virtual LocalDataPoolManager* getHkManagerHandle() override; /** * @brief Hook function for child handlers which is called once per * performOperation(). Default implementation is empty. */ virtual void performOperationHook(); + public: + /** Explicit interface implementation of getObjectId */ + virtual object_id_t getObjectId() const override; + /** * @param parentQueueId */ @@ -608,7 +627,7 @@ protected: /** Action helper for HasActionsIF */ ActionHelper actionHelper; /** Housekeeping Manager */ - //LocalDataPoolManager hkManager; + LocalDataPoolManager hkManager; /** * @brief Information about commands @@ -647,7 +666,7 @@ protected: //! The dataset used to access housekeeping data related to the //! respective device reply. Will point to a dataset held by //! the child handler (if one is specified) - // DataSetIF* dataSet = nullptr; + LocalPoolDataSetBase* dataSet; //! The command that expects this reply. DeviceCommandMap::iterator command; }; @@ -689,14 +708,18 @@ protected: uint32_t deviceThermalRequestPoolId = PoolVariableIF::NO_PARAMETER; /** - * Optional Error code - * Can be set in doStartUp(), doShutDown() and doTransition() to signal cause for Transition failure. + * Optional Error code. Can be set in doStartUp(), doShutDown() and + * doTransition() to signal cause for Transition failure. */ ReturnValue_t childTransitionFailure; - uint32_t ignoreMissedRepliesCount = 0; //!< Counts if communication channel lost a reply, so some missed replys can be ignored. + /** Counts if communication channel lost a reply, so some missed + * replys can be ignored. */ + uint32_t ignoreMissedRepliesCount = 0; - FailureIsolationBase* fdirInstance; //!< Pointer to the used FDIR instance. If not provided by child, default class is instantiated. + /** Pointer to the used FDIR instance. If not provided by child, + * default class is instantiated. */ + FailureIsolationBase* fdirInstance; HkSwitchHelper hkSwitcher; @@ -944,14 +967,17 @@ protected: virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode); - virtual void startTransition(Mode_t mode, Submode_t submode); - virtual void setToExternalControl(); - virtual void announceMode(bool recursive); + + /* HasModesIF overrides */ + virtual void startTransition(Mode_t mode, Submode_t submode) override; + virtual void setToExternalControl() override; + virtual void announceMode(bool recursive) override; virtual ReturnValue_t letChildHandleMessage(CommandMessage *message); /** - * Overwrites SystemObject::triggerEvent in order to inform FDIR"Helper" faster about executed events. + * Overwrites SystemObject::triggerEvent in order to inform FDIR"Helper" + * faster about executed events. * This is a bit sneaky, but improves responsiveness of the device FDIR. * @param event The event to be thrown * @param parameter1 Optional parameter 1 @@ -1034,12 +1060,17 @@ private: /** the object used to set power switches */ PowerSwitchIF *powerSwitcher = nullptr; + /** HK destination can also be set individually */ + object_id_t hkDestination = objects::NO_OBJECT; + /** * @brief Used for timing out mode transitions. * Set when setMode() is called. */ uint32_t timeoutStart = 0; + bool setStartupImmediately = false; + /** * Delay for the current mode transition, used for time out */ @@ -1080,11 +1111,6 @@ private: void buildRawDeviceCommand(CommandMessage* message); void buildInternalCommand(void); -// /** -// * Send a reply with the current mode and submode. -// */ -// void announceMode(void); - /** * Decrement the counter for the timout of replies. * @@ -1111,10 +1137,14 @@ private: /** * Build and send a command to the device. * - * This routine checks whether a raw or direct command has been received, checks the content of the received command and - * calls buildCommandFromCommand() for direct commands or sets #rawpacket to the received raw packet. - * If no external command is received or the received command is invalid and the current mode is @c MODE_NORMAL or a transitional mode, - * it asks the child class to build a command (via getNormalDeviceCommand() or getTransitionalDeviceCommand() and buildCommand()) and + * This routine checks whether a raw or direct command has been received, + * checks the content of the received command and calls + * buildCommandFromCommand() for direct commands or sets #rawpacket + * to the received raw packet. + * If no external command is received or the received command is invalid and + * the current mode is @c MODE_NORMAL or a transitional mode, it asks the + * child class to build a command (via getNormalDeviceCommand() or + * getTransitionalDeviceCommand() and buildCommand()) and * sends the command via RMAP. */ void doSendWrite(void); @@ -1159,7 +1189,6 @@ private: ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, uint32_t *len); - /** * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW NOTHING ELSE!!! */ @@ -1170,25 +1199,14 @@ private: */ void callChildStatemachine(); - /** - * Switches the channel of the cookie used for the communication - * - * - * @param newChannel the object Id of the channel to switch to - * @return - * - @c RETURN_OK when cookie was changed - * - @c RETURN_FAILED when cookies could not be changed, eg because the newChannel is not enabled - * - @c returnvalues of RMAPChannelIF::isActive() - */ - ReturnValue_t switchCookieChannel(object_id_t newChannelId); - ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); - virtual ReturnValue_t initializeAfterTaskCreation() override; + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; - void parseReply(const uint8_t* receivedData, - size_t receivedDataLen); + virtual dur_millis_t getPeriodicOperationFrequency() const override; + + void parseReply(const uint8_t* receivedData, + size_t receivedDataLen); }; -#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */ - +#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */ diff --git a/fsfw.mk b/fsfw.mk index 3639717b..c5847554 100644 --- a/fsfw.mk +++ b/fsfw.mk @@ -9,6 +9,9 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/controller/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/coordinates/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapool/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoolglob/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/housekeeping/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/eventmatching/*.cpp) diff --git a/housekeeping/AcceptsHkPacketsIF.h b/housekeeping/AcceptsHkPacketsIF.h new file mode 100644 index 00000000..6fa151b1 --- /dev/null +++ b/housekeeping/AcceptsHkPacketsIF.h @@ -0,0 +1,12 @@ +#ifndef FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ +#define FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ + +#include "../ipc/MessageQueueMessageIF.h" + +class AcceptsHkPacketsIF { +public: + virtual~ AcceptsHkPacketsIF() {}; + virtual MessageQueueId_t getHkQueue() const = 0; +}; + +#endif /* FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ */ diff --git a/housekeeping/HousekeepingMessage.cpp b/housekeeping/HousekeepingMessage.cpp new file mode 100644 index 00000000..221f0a6f --- /dev/null +++ b/housekeeping/HousekeepingMessage.cpp @@ -0,0 +1,215 @@ +#include "HousekeepingMessage.h" + +#include "../objectmanager/ObjectManagerIF.h" +#include + +HousekeepingMessage::~HousekeepingMessage() {} + +void HousekeepingMessage::setHkReportReply(CommandMessage* message, sid_t sid, + store_address_t storeId) { + message->setCommand(HK_REPORT); + message->setMessageSize(HK_MESSAGE_SIZE); + setSid(message, sid); + message->setParameter3(storeId.raw); +} + +void HousekeepingMessage::setHkDiagnosticsReply(CommandMessage* message, + sid_t sid, store_address_t storeId) { + message->setCommand(DIAGNOSTICS_REPORT); + message->setMessageSize(HK_MESSAGE_SIZE); + setSid(message, sid); + message->setParameter3(storeId.raw); +} + +sid_t HousekeepingMessage::getHkDataReply(const CommandMessage *message, + store_address_t *storeIdToSet) { + if(storeIdToSet != nullptr) { + *storeIdToSet = message->getParameter3(); + } + return getSid(message); +} + +void HousekeepingMessage::setToggleReportingCommand(CommandMessage *message, + sid_t sid, bool enableReporting, bool isDiagnostics) { + if(isDiagnostics) { + if(enableReporting) { + message->setCommand(ENABLE_PERIODIC_DIAGNOSTICS_GENERATION); + } + else { + message->setCommand(DISABLE_PERIODIC_DIAGNOSTICS_GENERATION); + } + } + else { + if(enableReporting) { + message->setCommand(ENABLE_PERIODIC_HK_REPORT_GENERATION); + } + else { + message->setCommand(DISABLE_PERIODIC_HK_REPORT_GENERATION); + } + } + + setSid(message, sid); +} + +void HousekeepingMessage::setStructureReportingCommand(CommandMessage *command, + sid_t sid, bool isDiagnostics) { + if(isDiagnostics) { + command->setCommand(REPORT_DIAGNOSTICS_REPORT_STRUCTURES); + } + else { + command->setCommand(REPORT_HK_REPORT_STRUCTURES); + } + + setSid(command, sid); +} + +void HousekeepingMessage::setOneShotReportCommand(CommandMessage *command, + sid_t sid, bool isDiagnostics) { + if(isDiagnostics) { + command->setCommand(GENERATE_ONE_DIAGNOSTICS_REPORT); + } + else { + command->setCommand(GENERATE_ONE_PARAMETER_REPORT); + } + + setSid(command, sid); +} + +void HousekeepingMessage::setCollectionIntervalModificationCommand( + CommandMessage *command, sid_t sid, float collectionInterval, + bool isDiagnostics) { + if(isDiagnostics) { + command->setCommand(MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL); + } + else { + command->setCommand(MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL); + } + command->setParameter3(collectionInterval); + + setSid(command, sid); +} + +sid_t HousekeepingMessage::getCollectionIntervalModificationCommand( + const CommandMessage* command, float* newCollectionInterval) { + if(newCollectionInterval != nullptr) { + *newCollectionInterval = command->getParameter3(); + } + + return getSid(command); +} + +void HousekeepingMessage::setHkRequestSuccessReply(CommandMessage *reply, + sid_t sid) { + setSid(reply, sid); + reply->setCommand(HK_REQUEST_SUCCESS); +} + +void HousekeepingMessage::setHkRequestFailureReply(CommandMessage *reply, + sid_t sid, ReturnValue_t error) { + setSid(reply, sid); + reply->setCommand(HK_REQUEST_FAILURE); + reply->setParameter3(error); +} + +sid_t HousekeepingMessage::getHkRequestFailureReply(const CommandMessage *reply, + ReturnValue_t *error) { + if(error != nullptr) { + *error = reply->getParameter3(); + } + return getSid(reply); +} + +sid_t HousekeepingMessage::getSid(const CommandMessage* message) { + sid_t sid; + std::memcpy(&sid.raw, message->getData(), sizeof(sid.raw)); + return sid; +} + +void HousekeepingMessage::setSid(CommandMessage *message, sid_t sid) { + std::memcpy(message->getData(), &sid.raw, sizeof(sid.raw)); +} + +void HousekeepingMessage::setHkStuctureReportReply(CommandMessage *reply, + sid_t sid, store_address_t storeId) { + reply->setCommand(HK_DEFINITIONS_REPORT); + setSid(reply, sid); + reply->setParameter3(storeId.raw); +} + +void HousekeepingMessage::setDiagnosticsStuctureReportReply( + CommandMessage *reply, sid_t sid, store_address_t storeId) { + reply->setCommand(DIAGNOSTICS_DEFINITION_REPORT); + setSid(reply, sid); + reply->setParameter3(storeId.raw); +} + +void HousekeepingMessage::clear(CommandMessage* message) { + switch(message->getCommand()) { + case(HK_REPORT): + case(DIAGNOSTICS_REPORT): + case(HK_DEFINITIONS_REPORT): + case(DIAGNOSTICS_DEFINITION_REPORT): + case(UPDATE_SNAPSHOT_SET): { + store_address_t storeId; + getHkDataReply(message, &storeId); + StorageManagerIF *ipcStore = objectManager->get( + objects::IPC_STORE); + if (ipcStore != nullptr) { + ipcStore->deleteData(storeId); + } + } + } + message->setCommand(CommandMessage::CMD_NONE); +} + +void HousekeepingMessage::setUpdateNotificationSetCommand( + CommandMessage *command, sid_t sid) { + command->setCommand(UPDATE_NOTIFICATION_SET); + setSid(command, sid); +} + +void HousekeepingMessage::setUpdateNotificationVariableCommand( + CommandMessage *command, lp_id_t localPoolId) { + command->setCommand(UPDATE_NOTIFICATION_VARIABLE); + command->setParameter(localPoolId); +} + +void HousekeepingMessage::setUpdateSnapshotSetCommand(CommandMessage *command, + sid_t sid, store_address_t storeId) { + command->setCommand(UPDATE_SNAPSHOT_VARIABLE); + setSid(command, sid); + command->setParameter3(storeId.raw); +} + +void HousekeepingMessage::setUpdateSnapshotVariableCommand( + CommandMessage *command, lp_id_t localPoolId, store_address_t storeId) { + command->setCommand(UPDATE_SNAPSHOT_VARIABLE); + command->setParameter(localPoolId); + command->setParameter3(storeId.raw); +} + +sid_t HousekeepingMessage::getUpdateNotificationSetCommand( + const CommandMessage *command) { + return getSid(command); +} + +lp_id_t HousekeepingMessage::getUpdateNotificationVariableCommand( + const CommandMessage *command) { + return command->getParameter(); +} + +sid_t HousekeepingMessage::getUpdateSnapshotSetCommand( + const CommandMessage *command, store_address_t *storeId) { + if(storeId != nullptr) { + *storeId = command->getParameter3(); + } + return getSid(command); +} + +lp_id_t HousekeepingMessage::getUpdateSnapshotVariableCommand( + const CommandMessage *command, store_address_t *storeId) { + if(storeId != nullptr) { + *storeId = command->getParameter3(); + } + return command->getParameter(); +} diff --git a/housekeeping/HousekeepingMessage.h b/housekeeping/HousekeepingMessage.h new file mode 100644 index 00000000..90bbe594 --- /dev/null +++ b/housekeeping/HousekeepingMessage.h @@ -0,0 +1,149 @@ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ + +#include "../datapoollocal/locPoolDefinitions.h" +#include "../ipc/CommandMessage.h" +#include "../ipc/FwMessageTypes.h" +#include "../objectmanager/frameworkObjects.h" +#include "../storagemanager/StorageManagerIF.h" + + +/** + * @brief Special command message type for housekeeping messages + * @details + * This message is slightly larger than regular command messages to accomodate + * the uint64_t structure ID (SID). + */ +class HousekeepingMessage { +public: + + static constexpr size_t HK_MESSAGE_SIZE = CommandMessageIF::HEADER_SIZE + + sizeof(sid_t) + sizeof(uint32_t); + + /** + * Concrete instance is not used, instead this class operates on + * command message instances. + */ + HousekeepingMessage() = delete; + virtual ~HousekeepingMessage(); + + static constexpr uint8_t MESSAGE_ID = messagetypes::HOUSEKEEPING; + + static constexpr Command_t ENABLE_PERIODIC_HK_REPORT_GENERATION = + MAKE_COMMAND_ID(5); + static constexpr Command_t DISABLE_PERIODIC_HK_REPORT_GENERATION = + MAKE_COMMAND_ID(6); + + static constexpr Command_t ENABLE_PERIODIC_DIAGNOSTICS_GENERATION = + MAKE_COMMAND_ID(7); + static constexpr Command_t DISABLE_PERIODIC_DIAGNOSTICS_GENERATION = + MAKE_COMMAND_ID(8); + + static constexpr Command_t REPORT_HK_REPORT_STRUCTURES = MAKE_COMMAND_ID(9); + static constexpr Command_t REPORT_DIAGNOSTICS_REPORT_STRUCTURES = + MAKE_COMMAND_ID(11); + + static constexpr Command_t HK_DEFINITIONS_REPORT = MAKE_COMMAND_ID(10); + static constexpr Command_t DIAGNOSTICS_DEFINITION_REPORT = MAKE_COMMAND_ID(12); + + static constexpr Command_t HK_REPORT = MAKE_COMMAND_ID(25); + static constexpr Command_t DIAGNOSTICS_REPORT = MAKE_COMMAND_ID(26); + + static constexpr Command_t GENERATE_ONE_PARAMETER_REPORT = + MAKE_COMMAND_ID(27); + static constexpr Command_t GENERATE_ONE_DIAGNOSTICS_REPORT = + MAKE_COMMAND_ID(28); + + static constexpr Command_t MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL = + MAKE_COMMAND_ID(31); + static constexpr Command_t MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL = + MAKE_COMMAND_ID(32); + + static constexpr Command_t HK_REQUEST_SUCCESS = + MAKE_COMMAND_ID(128); + static constexpr Command_t HK_REQUEST_FAILURE = + MAKE_COMMAND_ID(129); + + static constexpr Command_t UPDATE_NOTIFICATION_SET = + MAKE_COMMAND_ID(130); + static constexpr Command_t UPDATE_NOTIFICATION_VARIABLE = + MAKE_COMMAND_ID(131); + + static constexpr Command_t UPDATE_SNAPSHOT_SET = MAKE_COMMAND_ID(132); + static constexpr Command_t UPDATE_SNAPSHOT_VARIABLE = MAKE_COMMAND_ID(133); + + //static constexpr Command_t UPDATE_HK_REPORT = MAKE_COMMAND_ID(134); + + static sid_t getSid(const CommandMessage* message); + + /* Housekeeping Interface Messages */ + + static void setToggleReportingCommand(CommandMessage* command, sid_t sid, + bool enableReporting, bool isDiagnostics); + static void setStructureReportingCommand(CommandMessage* command, sid_t sid, + bool isDiagnostics); + static void setOneShotReportCommand(CommandMessage* command, sid_t sid, + bool isDiagnostics); + static void setCollectionIntervalModificationCommand( + CommandMessage* command, sid_t sid, float collectionInterval, + bool isDiagnostics); + + static void setHkReportReply(CommandMessage* reply, sid_t sid, + store_address_t storeId); + static void setHkDiagnosticsReply(CommandMessage* reply, sid_t sid, + store_address_t storeId); + + static void setHkRequestSuccessReply(CommandMessage* reply, sid_t sid); + static void setHkRequestFailureReply(CommandMessage* reply, sid_t sid, + ReturnValue_t error); + + static void setHkStuctureReportReply(CommandMessage* reply, + sid_t sid, store_address_t storeId); + static void setDiagnosticsStuctureReportReply(CommandMessage* reply, + sid_t sid, store_address_t storeId); + + static sid_t getHkRequestFailureReply(const CommandMessage* reply, + ReturnValue_t* error); + + /** + * @brief Generic getter function for housekeeping data replies + * @details + * Command ID can be used beforehand to distinguish between diagnostics and + * regular HK packets. This getter function should be used for the + * command IDs 10, 12, 25 and 26. + */ + static sid_t getHkDataReply(const CommandMessage* message, + store_address_t * storeIdToSet); + static sid_t getCollectionIntervalModificationCommand( + const CommandMessage* command, float* newCollectionInterval); + + + /* Update Notification Messages */ + + static void setUpdateNotificationSetCommand(CommandMessage* command, + sid_t sid); + static void setUpdateNotificationVariableCommand(CommandMessage* command, + lp_id_t localPoolId); + + static void setUpdateSnapshotSetCommand(CommandMessage* command, sid_t sid, + store_address_t storeId); + static void setUpdateSnapshotVariableCommand(CommandMessage* command, + lp_id_t localPoolId, store_address_t storeId); + + static sid_t getUpdateNotificationSetCommand(const CommandMessage* command); + static lp_id_t getUpdateNotificationVariableCommand( + const CommandMessage* command); + + static sid_t getUpdateSnapshotSetCommand(const CommandMessage* command, + store_address_t* storeId); + static lp_id_t getUpdateSnapshotVariableCommand(const CommandMessage* command, + store_address_t* storeId); + + /** Utility */ + static void clear(CommandMessage* message); +private: + static void setSid(CommandMessage* message, sid_t sid); +}; + + +#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ */ diff --git a/housekeeping/HousekeepingPacketDownlink.h b/housekeeping/HousekeepingPacketDownlink.h new file mode 100644 index 00000000..ae0cc988 --- /dev/null +++ b/housekeeping/HousekeepingPacketDownlink.h @@ -0,0 +1,34 @@ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETDOWNLINK_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETDOWNLINK_H_ + +#include "../datapoollocal/LocalPoolDataSetBase.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../storagemanager/StorageManagerIF.h" + +/** + * @brief This class will be used to serialize general housekeeping packets + * which are destined to be downlinked into the store. + * @details + * The housekeeping packets are stored into the IPC store and forwarded + * to the designated housekeeping handler. + */ +class HousekeepingPacketDownlink: public SerialLinkedListAdapter { +public: + HousekeepingPacketDownlink(sid_t sid, LocalPoolDataSetBase* dataSetPtr): + sourceId(sid.objectId), setId(sid.ownerSetId), hkData(dataSetPtr) { + setLinks(); + } + +private: + void setLinks() { + setStart(&sourceId); + sourceId.setNext(&setId); + setId.setNext(&hkData); + } + + SerializeElement sourceId; + SerializeElement setId; + LinkedElement hkData; +}; + +#endif /* FRAMEWORK_HOUSEKEEPING_HOUSEKEEPINGPACKETDOWNLINK_H_ */ diff --git a/housekeeping/HousekeepingPacketUpdate.h b/housekeeping/HousekeepingPacketUpdate.h new file mode 100644 index 00000000..43ec0619 --- /dev/null +++ b/housekeeping/HousekeepingPacketUpdate.h @@ -0,0 +1,92 @@ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ + +#include "../serialize/SerialBufferAdapter.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../datapoollocal/LocalPoolDataSetBase.h" + +/** + * @brief This helper class will be used to serialize and deserialize + * update housekeeping packets into the store. + */ +class HousekeepingPacketUpdate: public SerializeIF { +public: + /** + * Update packet constructor for datasets + * @param timeStamp + * @param timeStampSize + * @param hkData + * @param hkDataSize + */ + HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, + LocalPoolDataSetBase* dataSetPtr): + timeStamp(timeStamp), timeStampSize(timeStampSize), + updateData(dataSetPtr) {}; + + /** + * Update packet constructor for pool variables. + * @param timeStamp + * @param timeStampSize + * @param dataSetPtr + */ + HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, + LocalPoolObjectBase* dataSetPtr): + timeStamp(timeStamp), timeStampSize(timeStampSize), + updateData(dataSetPtr) {}; + + virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize, Endianness streamEndianness) const { + if(timeStamp != nullptr) { + /* Endianness will always be MACHINE, so we can simply use memcpy + here. */ + std::memcpy(*buffer, timeStamp, timeStampSize); + *size += timeStampSize; + *buffer += timeStampSize; + } + if(updateData == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + return updateData->serialize(buffer, size, maxSize, streamEndianness); + } + + virtual size_t getSerializedSize() const { + if(updateData == nullptr) { + return 0; + } + return timeStampSize + updateData->getSerializedSize(); + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override { + if(*size < timeStampSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + + if(timeStamp != nullptr) { + /* Endianness will always be MACHINE, so we can simply use memcpy + here. */ + std::memcpy(timeStamp, *buffer, timeStampSize); + *size -= timeStampSize; + *buffer += timeStampSize; + } + + if(updateData == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(*size < updateData->getSerializedSize()) { + return SerializeIF::STREAM_TOO_SHORT; + } + + return updateData->deSerialize(buffer, size, streamEndianness); + } + +private: + uint8_t* timeStamp = nullptr; + size_t timeStampSize = 0; + + SerializeIF* updateData = nullptr; +}; + + +#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ */ diff --git a/housekeeping/HousekeepingSetPacket.h b/housekeeping/HousekeepingSetPacket.h new file mode 100644 index 00000000..f94720d4 --- /dev/null +++ b/housekeeping/HousekeepingSetPacket.h @@ -0,0 +1,59 @@ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGSETPACKET_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGSETPACKET_H_ + +#include "../housekeeping/HousekeepingMessage.h" +#include "../serialize/SerialLinkedListAdapter.h" +#include "../datapoollocal/LocalPoolDataSetBase.h" + +class HousekeepingSetPacket: public SerialLinkedListAdapter { +public: + HousekeepingSetPacket(sid_t sid, bool reportingEnabled, bool valid, + float collectionInterval, LocalPoolDataSetBase* dataSetPtr): + objectId(sid.objectId), setId(sid.ownerSetId), + reportingEnabled(reportingEnabled), valid(valid), + collectionIntervalSeconds(collectionInterval), dataSet(dataSetPtr) { + setLinks(); + } + + ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, Endianness streamEndianness) const override { + ReturnValue_t result = SerialLinkedListAdapter::serialize(buffer, size, + maxSize, streamEndianness); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return dataSet->serializeLocalPoolIds(buffer, size ,maxSize, + streamEndianness); + } + + size_t getSerializedSize() const override { + size_t linkedSize = SerialLinkedListAdapter::getSerializedSize(); + linkedSize += dataSet->getLocalPoolIdsSerializedSize(); + return linkedSize; + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_OK; + } + +private: + + void setLinks() { + setStart(&objectId); + objectId.setNext(&setId); + setId.setNext(&reportingEnabled); + reportingEnabled.setNext(&valid); + valid.setNext(&collectionIntervalSeconds); + collectionIntervalSeconds.setEnd(); + } + + SerializeElement objectId; + SerializeElement setId; + SerializeElement reportingEnabled; + SerializeElement valid; + SerializeElement collectionIntervalSeconds; + LocalPoolDataSetBase* dataSet; +}; + +#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGSETPACKET_H_ */ diff --git a/housekeeping/PeriodicHousekeepingHelper.cpp b/housekeeping/PeriodicHousekeepingHelper.cpp new file mode 100644 index 00000000..365f0004 --- /dev/null +++ b/housekeeping/PeriodicHousekeepingHelper.cpp @@ -0,0 +1,49 @@ +#include "PeriodicHousekeepingHelper.h" + +#include "../datapoollocal/LocalPoolDataSetBase.h" +#include + +PeriodicHousekeepingHelper::PeriodicHousekeepingHelper( + LocalPoolDataSetBase* owner): owner(owner) {} + + +void PeriodicHousekeepingHelper::initialize(float collectionInterval, + dur_millis_t minimumPeriodicInterval, bool isDiagnostics, + uint8_t nonDiagIntervalFactor) { + this->minimumPeriodicInterval = minimumPeriodicInterval; + if(not isDiagnostics) { + this->minimumPeriodicInterval = this->minimumPeriodicInterval * + nonDiagIntervalFactor; + } + collectionIntervalTicks = intervalSecondsToInterval(collectionInterval); +} + +float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() { + return intervalToIntervalSeconds(collectionIntervalTicks); +} + +bool PeriodicHousekeepingHelper::checkOpNecessary() { + if(internalTickCounter >= collectionIntervalTicks) { + internalTickCounter = 1; + return true; + } + internalTickCounter++; + return false; +} + +uint32_t PeriodicHousekeepingHelper::intervalSecondsToInterval( + float collectionIntervalSeconds) { + return std::ceil(collectionIntervalSeconds * 1000 + / minimumPeriodicInterval); +} + +float PeriodicHousekeepingHelper::intervalToIntervalSeconds( + uint32_t collectionInterval) { + return static_cast(collectionInterval * + minimumPeriodicInterval); +} + +void PeriodicHousekeepingHelper::changeCollectionInterval( + float newIntervalSeconds) { + collectionIntervalTicks = intervalSecondsToInterval(newIntervalSeconds); +} diff --git a/housekeeping/PeriodicHousekeepingHelper.h b/housekeeping/PeriodicHousekeepingHelper.h new file mode 100644 index 00000000..d96eae1d --- /dev/null +++ b/housekeeping/PeriodicHousekeepingHelper.h @@ -0,0 +1,32 @@ +#ifndef FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ +#define FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ + +#include "../timemanager/Clock.h" +#include + +class LocalPoolDataSetBase; + +class PeriodicHousekeepingHelper { +public: + PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner); + + void initialize(float collectionInterval, + dur_millis_t minimumPeriodicInterval, bool isDiagnostics, + uint8_t nonDiagIntervalFactor); + + void changeCollectionInterval(float newInterval); + float getCollectionIntervalInSeconds(); + bool checkOpNecessary(); +private: + LocalPoolDataSetBase* owner = nullptr; + + uint32_t intervalSecondsToInterval(float collectionIntervalSeconds); + float intervalToIntervalSeconds(uint32_t collectionInterval); + + dur_millis_t minimumPeriodicInterval = 0; + uint32_t internalTickCounter = 1; + uint32_t collectionIntervalTicks = 0; + +}; + +#endif /* FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ */ diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index 8d5c792b..12f36f33 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -1,3 +1,4 @@ +#include "../datapoolglob/GlobalDataSet.h" #include "InternalErrorReporter.h" #include "../ipc/QueueFactory.h" diff --git a/ipc/FwMessageTypes.h b/ipc/FwMessageTypes.h index e820b1df..8b49c122 100644 --- a/ipc/FwMessageTypes.h +++ b/ipc/FwMessageTypes.h @@ -3,7 +3,7 @@ namespace messagetypes { //Remember to add new Message Types to the clearCommandMessage function! -enum FW_MESSAGE_TYPE { +enum FsfwMessageTypes { COMMAND = 0, MODE_COMMAND, HEALTH_COMMAND, @@ -14,7 +14,10 @@ enum FW_MESSAGE_TYPE { MONITORING, MEMORY, PARAMETER, - FW_MESSAGES_COUNT + FILE_SYSTEM_MESSAGE, + HOUSEKEEPING, + + FW_MESSAGES_COUNT, }; } diff --git a/monitoring/MonitorBase.h b/monitoring/MonitorBase.h index b2d0e6cb..5173c479 100644 --- a/monitoring/MonitorBase.h +++ b/monitoring/MonitorBase.h @@ -1,12 +1,12 @@ #ifndef MONITORBASE_H_ #define MONITORBASE_H_ -#include "../datapool/DataSet.h" -#include "../datapool/PIDReader.h" -#include "LimitViolationReporter.h" -#include "MonitoringIF.h" -#include "MonitoringMessageContent.h" -#include "MonitorReporter.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. @@ -48,7 +48,7 @@ public: protected: virtual ReturnValue_t fetchSample(T* sample) { - DataSet mySet; + GlobDataSet mySet; PIDReader parameter(this->parameterId, &mySet); mySet.read(); if (!parameter.isValid()) { diff --git a/objectmanager/frameworkObjects.h b/objectmanager/frameworkObjects.h index 4d08f084..57783286 100644 --- a/objectmanager/frameworkObjects.h +++ b/objectmanager/frameworkObjects.h @@ -6,6 +6,7 @@ enum framework_objects { // Default verification reporter. PUS_SERVICE_1_VERIFICATION = 0x53000001, PUS_SERVICE_2_DEVICE_ACCESS = 0x53000002, + PUS_SERVICE_3_HOUSEKEEPING = 0x53000003, PUS_SERVICE_5_EVENT_REPORTING = 0x53000005, PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008, PUS_SERVICE_9_TIME_MGMT = 0x53000009, diff --git a/power/Fuse.cpp b/power/Fuse.cpp index 9986ab6b..3ea0b18c 100644 --- a/power/Fuse.cpp +++ b/power/Fuse.cpp @@ -1,7 +1,7 @@ #include "../monitoring/LimitViolationReporter.h" #include "../monitoring/MonitoringMessageContent.h" #include "../objectmanager/ObjectManagerIF.h" -#include "Fuse.h" +#include "../power/Fuse.h" #include "../serialize/SerialFixedArrayListAdapter.h" #include "../ipc/QueueFactory.h" @@ -12,7 +12,7 @@ Fuse::Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids, SystemObject(fuseObjectId), oldFuseState(0), fuseId(fuseId), powerIF( NULL), currentLimit(fuseObjectId, 1, ids.pidCurrent, confirmationCount, maxCurrent, FUSE_CURRENT_HIGH), powerMonitor(fuseObjectId, 2, - DataPool::poolIdAndPositionToPid(ids.poolIdPower, 0), + 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( @@ -109,7 +109,7 @@ size_t Fuse::getSerializedSize() const { } ReturnValue_t Fuse::deSerialize(const uint8_t** buffer, size_t* size, -Endianness streamEndianness) { + Endianness streamEndianness) { ReturnValue_t result = RETURN_FAILED; for (DeviceList::iterator iter = devices.begin(); iter != devices.end(); iter++) { diff --git a/power/Fuse.h b/power/Fuse.h index c67f69cc..362a30dd 100644 --- a/power/Fuse.h +++ b/power/Fuse.h @@ -1,12 +1,13 @@ #ifndef FUSE_H_ #define FUSE_H_ -#include "../datapool/DataSet.h" -#include "../datapool/PIDReader.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" +#include "../datapoolglob/PIDReader.h" #include "../devicehandlers/HealthDevice.h" #include "../monitoring/AbsLimitMonitor.h" -#include "PowerComponentIF.h" -#include "PowerSwitchIF.h" +#include "../power/PowerComponentIF.h" +#include "../power/PowerSwitchIF.h" #include "../returnvalues/HasReturnvaluesIF.h" #include "../parameters/ParameterHelper.h" #include @@ -84,12 +85,12 @@ private: }; PowerMonitor powerMonitor; - DataSet set; + GlobDataSet set; PIDReader voltage; PIDReader current; PIDReader state; - db_float_t power; - MessageQueueIF *commandQueue; + gp_float_t power; + MessageQueueIF* commandQueue; ParameterHelper parameterHelper; HealthHelper healthHelper; static object_id_t powerSwitchId; diff --git a/power/PowerSensor.h b/power/PowerSensor.h index 0f973e45..da0bd8c7 100644 --- a/power/PowerSensor.h +++ b/power/PowerSensor.h @@ -1,9 +1,9 @@ #ifndef POWERSENSOR_H_ #define POWERSENSOR_H_ -#include "../datapool/DataSet.h" -#include "../datapool/PIDReader.h" -#include "../datapool/PoolVariable.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" +#include "../datapoolglob/PIDReader.h" #include "../devicehandlers/HealthDevice.h" #include "../monitoring/LimitMonitor.h" #include "../parameters/ParameterHelper.h" @@ -53,12 +53,12 @@ private: MessageQueueIF* commandQueue; ParameterHelper parameterHelper; HealthHelper healthHelper; - DataSet set; + GlobDataSet set; //Variables in PIDReader current; PIDReader voltage; //Variables out - db_float_t power; + gp_float_t power; static const uint8_t MODULE_ID_CURRENT = 1; static const uint8_t MODULE_ID_VOLTAGE = 2; diff --git a/thermal/CoreComponent.cpp b/thermal/CoreComponent.cpp index 304712ef..657e79cb 100644 --- a/thermal/CoreComponent.cpp +++ b/thermal/CoreComponent.cpp @@ -2,7 +2,7 @@ CoreComponent::CoreComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, uint32_t targetStatePoolId, - uint32_t currentStatePoolId, uint32_t requestPoolId, DataSet* dataSet, + uint32_t currentStatePoolId, uint32_t requestPoolId, GlobDataSet* dataSet, AbstractTemperatureSensor* sensor, AbstractTemperatureSensor* firstRedundantSensor, AbstractTemperatureSensor* secondRedundantSensor, @@ -18,14 +18,14 @@ CoreComponent::CoreComponent(object_id_t reportingObjectId, uint8_t domainId, AbstractTemperatureSensor::ZERO_KELVIN_C), parameters( parameters), temperatureMonitor(reportingObjectId, domainId + 1, - DataPool::poolIdAndPositionToPid(temperaturePoolId, 0), + GlobalDataPool::poolIdAndPositionToPid(temperaturePoolId, 0), COMPONENT_TEMP_CONFIRMATION), domainId(domainId) { if (thermalModule != NULL) { thermalModule->registerComponent(this, priority); } //Set thermal state once, then leave to operator. - DataSet mySet; - PoolVariable writableTargetState(targetStatePoolId, &mySet, + GlobDataSet mySet; + gp_uint8_t writableTargetState(targetStatePoolId, &mySet, PoolVariableIF::VAR_WRITE); writableTargetState = initialTargetState; mySet.commit(PoolVariableIF::VALID); @@ -70,8 +70,8 @@ float CoreComponent::getLowerOpLimit() { } ReturnValue_t CoreComponent::setTargetState(int8_t newState) { - DataSet mySet; - PoolVariable writableTargetState(targetState.getDataPoolId(), + GlobDataSet mySet; + gp_uint8_t writableTargetState(targetState.getDataPoolId(), &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); if ((writableTargetState == STATE_REQUEST_OPERATIONAL) diff --git a/thermal/CoreComponent.h b/thermal/CoreComponent.h index 48a49f7d..8093711d 100644 --- a/thermal/CoreComponent.h +++ b/thermal/CoreComponent.h @@ -1,13 +1,14 @@ #ifndef MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ #define MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ -#include "../datapool/DataSet.h" -#include "../datapool/PoolVariable.h" -#include "ThermalComponentIF.h" -#include "AbstractTemperatureSensor.h" -#include "ThermalModule.h" -#include "ThermalMonitor.h" +#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 { @@ -22,7 +23,7 @@ public: CoreComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, uint32_t targetStatePoolId, uint32_t currentStatePoolId, - uint32_t requestPoolId, DataSet *dataSet, + uint32_t requestPoolId, GlobDataSet *dataSet, AbstractTemperatureSensor *sensor, AbstractTemperatureSensor *firstRedundantSensor, AbstractTemperatureSensor *secondRedundantSensor, @@ -57,10 +58,10 @@ protected: AbstractTemperatureSensor *secondRedundantSensor; ThermalModuleIF *thermalModule; - db_float_t temperature; - db_int8_t targetState; - db_int8_t currentState; - db_uint8_t heaterRequest; + gp_float_t temperature; + gp_int8_t targetState; + gp_int8_t currentState; + gp_uint8_t heaterRequest; bool isHeating; diff --git a/thermal/ThermalComponent.cpp b/thermal/ThermalComponent.cpp index 5dcd0bc6..50786654 100644 --- a/thermal/ThermalComponent.cpp +++ b/thermal/ThermalComponent.cpp @@ -3,7 +3,7 @@ ThermalComponent::ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, uint32_t targetStatePoolId, uint32_t currentStatePoolId, - uint32_t requestPoolId, DataSet* dataSet, + uint32_t requestPoolId, GlobDataSet* dataSet, AbstractTemperatureSensor* sensor, AbstractTemperatureSensor* firstRedundantSensor, AbstractTemperatureSensor* secondRedundantSensor, @@ -12,20 +12,18 @@ ThermalComponent::ThermalComponent(object_id_t reportingObjectId, CoreComponent(reportingObjectId, domainId, temperaturePoolId, targetStatePoolId, currentStatePoolId, requestPoolId, dataSet, sensor, firstRedundantSensor, secondRedundantSensor, - thermalModule, - { parameters.lowerOpLimit, parameters.upperOpLimit, - parameters.heaterOn, parameters.hysteresis, - parameters.heaterSwitchoff }, priority, - ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL), nopParameters( - { parameters.lowerNopLimit, parameters.upperNopLimit }) { + thermalModule,{ parameters.lowerOpLimit, parameters.upperOpLimit, + parameters.heaterOn, parameters.hysteresis, parameters.heaterSwitchoff }, + priority, ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL), + nopParameters({ parameters.lowerNopLimit, parameters.upperNopLimit }) { } ThermalComponent::~ThermalComponent() { } ReturnValue_t ThermalComponent::setTargetState(int8_t newState) { - DataSet mySet; - PoolVariable writableTargetState(targetState.getDataPoolId(), + GlobDataSet mySet; + gp_int8_t writableTargetState(targetState.getDataPoolId(), &mySet, PoolVariableIF::VAR_READ_WRITE); mySet.read(); if ((writableTargetState == STATE_REQUEST_OPERATIONAL) @@ -42,7 +40,7 @@ ReturnValue_t ThermalComponent::setTargetState(int8_t newState) { } } -ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, uint32_t size) { +ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, size_t size) { if (size != 4 * sizeof(parameters.lowerOpLimit)) { return MonitoringIF::INVALID_SIZE; } diff --git a/thermal/ThermalComponent.h b/thermal/ThermalComponent.h index 93243868..195f03b1 100644 --- a/thermal/ThermalComponent.h +++ b/thermal/ThermalComponent.h @@ -3,6 +3,9 @@ #include "CoreComponent.h" +/** + * What is it. How to use + */ class ThermalComponent: public CoreComponent { public: struct Parameters { @@ -14,13 +17,34 @@ public: float hysteresis; float heaterSwitchoff; }; + + /** + * Non-Operational Temperatures + */ struct NopParameters { float lowerNopLimit; float upperNopLimit; }; + + /** + * How to use. + * @param reportingObjectId + * @param domainId + * @param temperaturePoolId + * @param targetStatePoolId + * @param currentStatePoolId + * @param requestPoolId + * @param dataSet + * @param sensor + * @param firstRedundantSensor + * @param secondRedundantSensor + * @param thermalModule + * @param parameters + * @param priority + */ ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId, uint32_t targetStatePoolId, uint32_t currentStatePoolId, uint32_t requestPoolId, - DataSet *dataSet, AbstractTemperatureSensor *sensor, + GlobDataSet *dataSet, AbstractTemperatureSensor *sensor, AbstractTemperatureSensor *firstRedundantSensor, AbstractTemperatureSensor *secondRedundantSensor, ThermalModuleIF *thermalModule, Parameters parameters, @@ -29,7 +53,7 @@ public: ReturnValue_t setTargetState(int8_t newState); - virtual ReturnValue_t setLimits( const uint8_t* data, uint32_t size); + virtual ReturnValue_t setLimits( const uint8_t* data, size_t size); virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ParameterWrapper *parameterWrapper, diff --git a/thermal/ThermalModule.cpp b/thermal/ThermalModule.cpp index c573008e..fbd6939e 100644 --- a/thermal/ThermalModule.cpp +++ b/thermal/ThermalModule.cpp @@ -6,7 +6,7 @@ ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, uint32_t currentStatePoolId, uint32_t targetStatePoolId, - DataSet *dataSet, Parameters parameters, + GlobDataSet *dataSet, Parameters parameters, RedundantHeater::Parameters heaterParameters) : oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating( false), parameters(parameters), moduleTemperature( @@ -16,7 +16,7 @@ ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, heater = new RedundantHeater(heaterParameters); } -ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, DataSet* dataSet) : +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( @@ -250,8 +250,8 @@ bool ThermalModule::calculateModuleHeaterRequestAndSetModuleStatus( } void ThermalModule::setHeating(bool on) { - DataSet mySet; - PoolVariable writableTargetState(targetState.getDataPoolId(), + GlobDataSet mySet; + gp_int8_t writableTargetState(targetState.getDataPoolId(), &mySet, PoolVariableIF::VAR_WRITE); if (on) { writableTargetState = STATE_REQUEST_HEATING; diff --git a/thermal/ThermalModule.h b/thermal/ThermalModule.h index 19ab9a54..41be6baa 100644 --- a/thermal/ThermalModule.h +++ b/thermal/ThermalModule.h @@ -1,8 +1,8 @@ #ifndef THERMALMODULE_H_ #define THERMALMODULE_H_ -#include "../datapool/DataSet.h" -#include "../datapool/PoolVariable.h" +#include "../datapoolglob/GlobalDataSet.h" +#include "../datapoolglob/GlobalPoolVariable.h" #include "../devicehandlers/HealthDevice.h" #include "../events/EventReportingProxyIF.h" #include "ThermalModuleIF.h" @@ -11,6 +11,9 @@ #include "RedundantHeater.h" class PowerSwitchIF; +/** + * @brief Allows creation of different thermal control domains within a system. + */ class ThermalModule: public ThermalModuleIF { friend class ThermalController; public: @@ -20,10 +23,10 @@ public: }; ThermalModule(uint32_t moduleTemperaturePoolId, uint32_t currentStatePoolId, - uint32_t targetStatePoolId, DataSet *dataSet, Parameters parameters, + uint32_t targetStatePoolId, GlobDataSet *dataSet, Parameters parameters, RedundantHeater::Parameters heaterParameters); - ThermalModule(uint32_t moduleTemperaturePoolId, DataSet *dataSet); + ThermalModule(uint32_t moduleTemperaturePoolId, GlobDataSet *dataSet); virtual ~ThermalModule(); @@ -67,12 +70,12 @@ protected: Parameters parameters; - db_float_t moduleTemperature; + gp_float_t moduleTemperature; RedundantHeater *heater; - db_int8_t currentState; - db_int8_t targetState; + gp_int8_t currentState; + gp_int8_t targetState; std::list sensors; std::list components;