From 319fa9ddb6237c58d9fe8b0e5763b0b463ec82a4 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 5 Jun 2020 20:34:34 +0200 Subject: [PATCH] datapoollocal update --- datapoollocal/LocalDataSet.cpp | 69 +++------- datapoollocal/LocalDataSet.h | 141 +++------------------ datapoollocal/LocalPoolVariable.h | 143 +++++++++++++++------ datapoollocal/LocalPoolVariable.tpp | 83 +++++++++--- datapoollocal/LocalPoolVector.h | 189 ++++++++++++++++++++++++++++ datapoollocal/LocalPoolVector.tpp | 185 +++++++++++++++++++++++++++ 6 files changed, 582 insertions(+), 228 deletions(-) create mode 100644 datapoollocal/LocalPoolVector.h create mode 100644 datapoollocal/LocalPoolVector.tpp diff --git a/datapoollocal/LocalDataSet.cpp b/datapoollocal/LocalDataSet.cpp index 07f86e18..988f254a 100644 --- a/datapoollocal/LocalDataSet.cpp +++ b/datapoollocal/LocalDataSet.cpp @@ -1,66 +1,35 @@ #include +#include -LocalDataSet::LocalDataSet(): - fill_count(0), state(DATA_SET_UNINITIALISED) -{ - for (unsigned count = 0; count < DATA_SET_MAX_SIZE; count++) { - registeredVariables[count] = nullptr; +LocalDataSet::LocalDataSet(HasHkPoolParametersIF *hkOwner): DataSetBase() { + if(hkOwner != nullptr) { + hkManager = hkOwner->getHkManagerHandle(); + } + else { + // config error, error output here. } } -// who has the responsibility to lock the mutex? the local pool variable -// has access to the HK manager and could call its mutex lock function. -ReturnValue_t LocalDataSet::registerVariable( - PoolVariableIF *variable) { - return RETURN_OK; +LocalDataSet::LocalDataSet(object_id_t ownerId): DataSetBase() { + HasHkPoolParametersIF* hkOwner = objectManager->get( + ownerId); + if(hkOwner == nullptr) { + // config error, error output here. + } + hkManager = hkOwner->getHkManagerHandle(); } LocalDataSet::~LocalDataSet() { } -ReturnValue_t LocalDataSet::read() { - return RETURN_OK; -} - -ReturnValue_t LocalDataSet::commit(void) { - return RETURN_OK; -} - -ReturnValue_t LocalDataSet::commit(bool valid) { - return RETURN_OK; -} - -void LocalDataSet::setSetValid(bool valid) { -} - -void LocalDataSet::setEntriesValid(bool valid) { -} - -ReturnValue_t LocalDataSet::serialize(uint8_t **buffer, - size_t *size, const size_t max_size, bool bigEndian) const { - return RETURN_OK; -} - -size_t LocalDataSet::getSerializedSize() const { - return 0; -} - -ReturnValue_t LocalDataSet::deSerialize(const uint8_t **buffer, - size_t *size, bool bigEndian) { - return RETURN_OK; -} - -ReturnValue_t LocalDataSet::lockDataPool() { - return RETURN_OK; +ReturnValue_t LocalDataSet::lockDataPool(uint32_t timeoutMs) { + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->lockMutex(timeoutMs); } ReturnValue_t LocalDataSet::unlockDataPool() { - return RETURN_OK; + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->unlockMutex(); } -void LocalDataSet::handleAlreadyReadDatasetCommit() { -} -ReturnValue_t LocalDataSet::handleUnreadDatasetCommit() { - return RETURN_OK; -} diff --git a/datapoollocal/LocalDataSet.h b/datapoollocal/LocalDataSet.h index 6110175c..607d10b3 100644 --- a/datapoollocal/LocalDataSet.h +++ b/datapoollocal/LocalDataSet.h @@ -1,8 +1,12 @@ #ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ #define FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ +#include #include +#include #include +class HousekeepingManager; + /** * @brief The LocalDataSet class manages a set of locally checked out variables * for local data pools @@ -24,32 +28,22 @@ * * @ingroup data_pool */ -class LocalDataSet: - public DataSetIF, - public HasReturnvaluesIF, - public SerializeIF { +class LocalDataSet: public DataSetBase { 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_UNINITIALIZED = 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 The constructor simply sets the fill_count to zero and sets + * @brief Constructor for the creator of local pool data. + * The constructor simply sets the fill_count to zero and sets * the state to "uninitialized". */ - LocalDataSet(); + LocalDataSet(HasHkPoolParametersIF* hkOwner); /** - * @brief This operation is used to register the local variables in the set. - * @details It stores the pool variable pointer in a variable list. + * @brief Constructor for users of local pool data. The passed pool + * owner should implement the HasHkPoolParametersIF. + * The constructor simply sets the fill_count to zero and sets + * the state to "uninitialized". */ - ReturnValue_t registerVariable(PoolVariableIF* variable) override; + LocalDataSet(object_id_t ownerId); /** * @brief The destructor automatically manages writing the valid @@ -61,127 +55,30 @@ public: */ ~LocalDataSet(); - /** - * @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(bool valid); - - /** - * Set all entries - * @param valid - */ - void setSetValid(bool valid); - - /** - * 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); - - ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const override; - - size_t getSerializedSize() const override; - - ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian) override; +protected: private: - // SHOULDDO we could use a linked list of datapool variables - //! This definition sets the maximum number of variables - //! to register in one DataSet. - static const uint8_t DATA_SET_MAX_SIZE = 63; - /** - * @brief This array represents all pool variables registered in this set. - */ - 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; - /** * 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 underlying data data pool structure + * the global data pool. * @details * It makes use of the lockDataPool method offered by the DataPool class. */ - ReturnValue_t lockDataPool() override; - + ReturnValue_t lockDataPool(uint32_t timeoutMs) override; /** * @brief This is a small helper function to facilitate - * unlocking the underlying data data pool structure + * 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(); + HousekeepingManager* hkManager; }; #endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALDATASET_H_ */ diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h index 39c92f60..cb373a71 100644 --- a/datapoollocal/LocalPoolVariable.h +++ b/datapoollocal/LocalPoolVariable.h @@ -3,56 +3,63 @@ #include #include +#include +#include +#include #include -#include -/** - * @brief This is the access class for non-array local data pool entries. - * - * @details - * - * @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 - */ - /** * @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 + * @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 PoolVariableIF, HasReturnvaluesIF { public: - static constexpr lp_id_t INVALID_POOL_ID = 0xFFFFFFFF; + //! 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. - * @param set_id - * @param setReadWriteMode - * @param localPoolMap - * @param dataSet + * 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. */ LocalPoolVar(lp_id_t poolId, HasHkPoolParametersIF* hkOwner, - pool_rwm_t setReadWriteMode, DataSetIF* dataSet = nullptr); + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, + DataSetIF* dataSet = nullptr); /** * 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. - * @param poolId - * @param poolOwner - * @param setReadWriteMode - * @param dataSet + * 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. */ LocalPoolVar(lp_id_t poolId, object_id_t poolOwner, - pool_rwm_t setReadWriteMode, DataSetIF* dataSet = nullptr); + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, + DataSetIF* dataSet = nullptr); virtual~ LocalPoolVar() {}; @@ -63,33 +70,91 @@ public: */ T value = 0; - ReturnValue_t commit() override; - ReturnValue_t read() override; pool_rwm_t getReadWriteMode() const override; - uint32_t getDataPoolId() const override; + + lp_id_t getDataPoolId() const override; + void setDataPoolId(lp_id_t poolId); + bool isValid() const override; - void setValid(uint8_t validity) override; + void setValid(bool validity) override; + uint8_t getValid() const; ReturnValue_t serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const override; + const size_t max_size, bool bigEndian) const override; virtual size_t getSerializedSize() const override; virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - bool bigEndian) override; + bool bigEndian) 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; + + // std::ostream is the type for object std::cout +// friend std::ostream& operator<< (std::ostream &out, +// const LocalPoolVar &var) { +// out << static_cast(value); +// return out; +// } + private: - lp_id_t localPoolId = INVALID_POOL_ID; + //! @brief Pool ID of pool entry inside the used local pool. + lp_id_t localPoolId = PoolVariableIF::NO_PARAMETER; + //! @brief Read-write mode of the pool variable pool_rwm_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; + //! @brief Specifies whether the entry is valid or invalid. bool valid = false; - bool objectValid = true; //! Pointer to the class which manages the HK pool. HousekeepingManager* hkManager; }; #include -template -using lp_variable = LocalPoolVar; -using lp_bool_t = LocalPoolVar; +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; diff --git a/datapoollocal/LocalPoolVariable.tpp b/datapoollocal/LocalPoolVariable.tpp index 4bc4c662..b7a0e837 100644 --- a/datapoollocal/LocalPoolVariable.tpp +++ b/datapoollocal/LocalPoolVariable.tpp @@ -1,16 +1,24 @@ #ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ #define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ -#include -#include - -#include +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ +#error Include LocalPoolVariable.h before LocalPoolVariable.tpp! +#endif template inline LocalPoolVar::LocalPoolVar(lp_id_t poolId, HasHkPoolParametersIF* hkOwner, pool_rwm_t setReadWriteMode, DataSetIF* dataSet): localPoolId(poolId),readWriteMode(setReadWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVector: 0 passed as pool ID, which is the " + "NO_PARAMETER value!" << std::endl; + } + if(hkOwner == nullptr) { + sif::error << "LocalPoolVariable: The supplied pool owner is a nullptr!" + << std::endl; + return; + } hkManager = hkOwner->getHkManagerHandle(); if(dataSet != nullptr) { dataSet->registerVariable(this); @@ -21,12 +29,15 @@ template inline LocalPoolVar::LocalPoolVar(lp_id_t poolId, object_id_t poolOwner, pool_rwm_t setReadWriteMode, DataSetIF *dataSet): readWriteMode(readWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVector: 0 passed as pool ID, which is the " + "NO_PARAMETER value!" << std::endl; + } HasHkPoolParametersIF* hkOwner = objectManager->get(poolOwner); if(hkOwner == nullptr) { sif::error << "LocalPoolVariable: The supplied pool owner did not implement" "the correct interface HasHkPoolParametersIF!" << std::endl; - objectValid = false; return; } hkManager = hkOwner->getHkManagerHandle(); @@ -36,38 +47,59 @@ inline LocalPoolVar::LocalPoolVar(lp_id_t poolId, object_id_t poolOwner, } template -inline ReturnValue_t LocalPoolVar::read() { +inline ReturnValue_t LocalPoolVar::read(millis_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), 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; - // TODO: special return value - return HasReturnvaluesIF::RETURN_FAILED; + return PoolVariableIF::INVALID_READ_WRITE_MODE; } - MutexHelper(hkManager->getMutexHandle(), MutexIF::NO_TIMEOUT); + PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, poolEntry); - if(result != RETURN_OK) { + 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() { +inline ReturnValue_t LocalPoolVar::commit(millis_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), 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; - // TODO: special return value - return HasReturnvaluesIF::RETURN_FAILED; + return PoolVariableIF::INVALID_READ_WRITE_MODE; } - MutexHelper(hkManager->getMutexHandle(), MutexIF::NO_TIMEOUT); + // Wait maximum of 50 milliseconds. + MutexHelper(hkManager->getMutexHandle(), 50); PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, poolEntry); + 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; } @@ -81,16 +113,26 @@ inline lp_id_t LocalPoolVar::getDataPoolId() const { return localPoolId; } +template +inline void LocalPoolVar::setDataPoolId(lp_id_t poolId) { + this->localPoolId = poolId; +} + template inline bool LocalPoolVar::isValid() const { return valid; } template -inline void LocalPoolVar::setValid(uint8_t validity) { +inline void LocalPoolVar::setValid(bool validity) { this->valid = validity; } +template +inline uint8_t LocalPoolVar::getValid() const { + return valid; +} + template inline ReturnValue_t LocalPoolVar::serialize(uint8_t** buffer, size_t* size, const size_t max_size, bool bigEndian) const { @@ -109,4 +151,11 @@ inline ReturnValue_t LocalPoolVar::deSerialize(const uint8_t** buffer, return AutoSerializeAdapter::deSerialize(&value, buffer, size, bigEndian); } +//template +//inline friend std::ostream& LocalPoolVar::operator<< (std::ostream &out, +// const LocalPoolVar &var) { +// out << static_cast(out); +//} + + #endif diff --git a/datapoollocal/LocalPoolVector.h b/datapoollocal/LocalPoolVector.h new file mode 100644 index 00000000..02c47113 --- /dev/null +++ b/datapoollocal/LocalPoolVector.h @@ -0,0 +1,189 @@ +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ + +#include +#include +#include +#include +#include + + +/** + * @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 PoolVariableIF, public HasReturnvaluesIF { +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(lp_id_t poolId, HasHkPoolParametersIF* hkOwner, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, + DataSetIF* dataSet = nullptr); + + /** + * 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(lp_id_t poolId, object_id_t poolOwner, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE, + DataSetIF* dataSet = nullptr); + + /** + * @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; + } + + uint32_t getDataPoolId() const override; + /** + * @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); + + /** + * This method returns if the variable is write-only, read-write or read-only. + */ + pool_rwm_t getReadWriteMode() const; + + /** + * @brief With this call, the valid information of the variable is returned. + */ + bool isValid() const override; + void setValid(bool valid) override; + uint8_t getValid() const; + + T &operator [](int i); + const T &operator [](int i) const; + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override; + virtual size_t getSerializedSize() const override; + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) 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: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool id is stored. + */ + uint32_t localPoolId; + /** + * @brief The valid information as it was stored in the data pool + * is copied to this attribute. + */ + bool valid; + /** + * @brief The information whether the class is read-write or + * read-only is stored here. + */ + ReadWriteMode_t readWriteMode; + //! @brief Pointer to the class which manages the HK pool. + HousekeepingManager* hkManager; +}; + +#include + +template +using lp_vec_t = LocalPoolVector; + +#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ */ diff --git a/datapoollocal/LocalPoolVector.tpp b/datapoollocal/LocalPoolVector.tpp new file mode 100644 index 00000000..78637eff --- /dev/null +++ b/datapoollocal/LocalPoolVector.tpp @@ -0,0 +1,185 @@ +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ +#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ + +#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#error Include LocalPoolVector.h before LocalPoolVector.tpp! +#endif + +template +inline LocalPoolVector::LocalPoolVector(lp_id_t poolId, + HasHkPoolParametersIF* hkOwner, pool_rwm_t setReadWriteMode, + DataSetIF* dataSet) : + localPoolId(poolId), valid(false), readWriteMode(setReadWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVector: 0 passed as pool ID, which is the " + "NO_PARAMETER value!" << std::endl; + } + memset(this->value, 0, vectorSize * sizeof(T)); + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +template +inline LocalPoolVector::LocalPoolVector(lp_id_t poolId, + object_id_t poolOwner, pool_rwm_t setReadWriteMode, DataSetIF *dataSet): + readWriteMode(readWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVector: 0 passed as pool ID, which is the " + "NO_PARAMETER value!" << std::endl; + } + HasHkPoolParametersIF* hkOwner = + objectManager->get(poolOwner); + if(hkOwner == nullptr) { + sif::error << "LocalPoolVariable: The supplied pool owner did not implement" + "the correct interface HasHkPoolParametersIF!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + if(dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +template +inline ReturnValue_t LocalPoolVector::read(uint32_t lockTimeout) { + MutexHelper(hkManager->getMutexHandle(), 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; + } + 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(), 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; + } + // Wait maximum of 50 milliseconds. + MutexHelper(hkManager->getMutexHandle(), 50); + 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; + } + 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]; + } + sif::warning << "LocalPoolVector: Invalid index" << std::endl; + return 0; +} + +template +inline const T& LocalPoolVector::operator [](int i) const { + if(i <= vectorSize) { + return value[i]; + } + sif::warning << "LocalPoolVector: Invalid index" << std::endl; + return 0; +} + +template +inline ReturnValue_t LocalPoolVector::serialize(uint8_t** buffer, + size_t* size, const size_t max_size, bool bigEndian) const { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t i = 0; i < vectorSize; i++) { + result = SerializeAdapter::serialize(&(value[i]), buffer, size, + max_size, bigEndian); + 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, bool bigEndian) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + for (uint16_t i = 0; i < vectorSize; i++) { + result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, + bigEndian); + if (result != HasReturnvaluesIF::RETURN_OK) { + break; + } + } + return result; +} + +template +inline pool_rwm_t LocalPoolVector::getReadWriteMode() const { + return this->readWriteMode; +} + + +template +inline uint32_t LocalPoolVector::getDataPoolId() const { + return localPoolId; +} + +template +inline void LocalPoolVector::setDataPoolId(uint32_t poolId) { + this->localPoolId = poolId; +} + +template +inline void LocalPoolVector::setValid(bool valid) { + this->valid = valid; +} + +template +inline uint8_t LocalPoolVector::getValid() const { + return valid; +} + +template +inline bool LocalPoolVector::isValid() const { + return valid; +} + +#endif