diff --git a/container/FixedOrderedMultimap.h b/container/FixedOrderedMultimap.h index 96bc0073..acf2368a 100644 --- a/container/FixedOrderedMultimap.h +++ b/container/FixedOrderedMultimap.h @@ -3,6 +3,7 @@ #include "ArrayList.h" #include +#include /** * @brief An associative container which allows multiple entries of the same key. diff --git a/controller/ExtendedControllerBase.cpp b/controller/ExtendedControllerBase.cpp index 017acafe..e0aec63a 100644 --- a/controller/ExtendedControllerBase.cpp +++ b/controller/ExtendedControllerBase.cpp @@ -4,7 +4,7 @@ ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth): ControllerBase(objectId, parentId, commandQueueDepth), - localPoolManager(this, commandQueue), + poolManager(this, commandQueue), actionHelper(this, commandQueue) { } @@ -17,7 +17,7 @@ ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId, ReturnValue_t ExtendedControllerBase::initializeLocalDataPool( - LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { // needs to be overriden and implemented by child class. return HasReturnvaluesIF::RETURN_OK; } @@ -26,8 +26,8 @@ object_id_t ExtendedControllerBase::getObjectId() const { return SystemObject::getObjectId(); } -LocalDataPoolManager* ExtendedControllerBase::getHkManagerHandle() { - return &localPoolManager; +AccessPoolManagerIF* ExtendedControllerBase::getAccessorHandle() { + return &poolManager; } uint32_t ExtendedControllerBase::getPeriodicOperationFrequency() const { @@ -40,7 +40,7 @@ ReturnValue_t ExtendedControllerBase::handleCommandMessage( if(result == HasReturnvaluesIF::RETURN_OK) { return result; } - return localPoolManager.handleHousekeepingMessage(message); + return poolManager.handleHousekeepingMessage(message); } void ExtendedControllerBase::handleQueue() { @@ -64,7 +64,7 @@ void ExtendedControllerBase::handleQueue() { continue; } - result = localPoolManager.handleHousekeepingMessage(&command); + result = poolManager.handleHousekeepingMessage(&command); if (result == RETURN_OK) { continue; } @@ -88,16 +88,16 @@ ReturnValue_t ExtendedControllerBase::initialize() { return result; } - return localPoolManager.initialize(commandQueue); + return poolManager.initialize(commandQueue); } ReturnValue_t ExtendedControllerBase::initializeAfterTaskCreation() { - return localPoolManager.initializeAfterTaskCreation(); + return poolManager.initializeAfterTaskCreation(); } ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) { handleQueue(); - localPoolManager.performHkOperation(); + poolManager.performHkOperation(); performControlOperation(); return RETURN_OK; } @@ -113,3 +113,7 @@ LocalPoolDataSetBase* ExtendedControllerBase::getDataSetHandle(sid_t sid) { #endif return nullptr; } + +ProvidesDataPoolSubscriptionIF* ExtendedControllerBase::getSubscriptionInterface() { + return &poolManager; +} diff --git a/controller/ExtendedControllerBase.h b/controller/ExtendedControllerBase.h index 02c5728e..b2760514 100644 --- a/controller/ExtendedControllerBase.h +++ b/controller/ExtendedControllerBase.h @@ -32,10 +32,20 @@ public: virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual ReturnValue_t initializeAfterTaskCreation() override; + /** + * Provides a subscription interface for objects which required updates on changed + * controller variables or datasets + * @return + */ + ProvidesDataPoolSubscriptionIF* getSubscriptionInterface() override; + protected: - LocalDataPoolManager localPoolManager; + LocalDataPoolManager poolManager; ActionHelper actionHelper; + //! Accessor handle required for internal handling + AccessPoolManagerIF* getAccessorHandle() override; + /** * Implemented by child class. Handle all command messages which are * not health, mode, action or housekeeping messages. @@ -60,9 +70,8 @@ protected: /** HasLocalDatapoolIF overrides */ virtual object_id_t getObjectId() const override; virtual ReturnValue_t initializeLocalDataPool( - LocalDataPool& localDataPoolMap, + localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; - virtual LocalDataPoolManager* getHkManagerHandle() override; virtual uint32_t getPeriodicOperationFrequency() const override; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; }; diff --git a/datapool/PoolDataSetBase.cpp b/datapool/PoolDataSetBase.cpp index 5fb1c3c7..01069785 100644 --- a/datapool/PoolDataSetBase.cpp +++ b/datapool/PoolDataSetBase.cpp @@ -38,11 +38,12 @@ ReturnValue_t PoolDataSetBase::registerVariable( return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t PoolDataSetBase::read(uint32_t lockTimeout) { +ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType, + uint32_t lockTimeout) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t error = result; if (state == States::STATE_SET_UNINITIALISED) { - lockDataPool(lockTimeout); + lockDataPool(timeoutType, lockTimeout); for (uint16_t count = 0; count < fillCount; count++) { result = readVariable(count); if(result != RETURN_OK) { @@ -86,7 +87,9 @@ ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) { != PoolVariableIF::NO_PARAMETER) { if(protectEveryReadCommitCall) { - result = registeredVariables[count]->read(mutexTimeout); + result = registeredVariables[count]->read( + timeoutTypeForSingleVars, + mutexTimeoutForSingleVars); } else { result = registeredVariables[count]->readWithoutLock(); @@ -99,25 +102,29 @@ ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) { return result; } -ReturnValue_t PoolDataSetBase::commit(uint32_t lockTimeout) { +ReturnValue_t PoolDataSetBase::commit(MutexIF::TimeoutType timeoutType, + uint32_t lockTimeout) { if (state == States::STATE_SET_WAS_READ) { - handleAlreadyReadDatasetCommit(lockTimeout); + handleAlreadyReadDatasetCommit(timeoutType, lockTimeout); return HasReturnvaluesIF::RETURN_OK; } else { - return handleUnreadDatasetCommit(lockTimeout); + return handleUnreadDatasetCommit(timeoutType, lockTimeout); } } -void PoolDataSetBase::handleAlreadyReadDatasetCommit(uint32_t lockTimeout) { - lockDataPool(lockTimeout); +void PoolDataSetBase::handleAlreadyReadDatasetCommit( + MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) { + lockDataPool(timeoutType, lockTimeout); for (uint16_t count = 0; count < fillCount; count++) { if (registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_READ && registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) { if(protectEveryReadCommitCall) { - registeredVariables[count]->commit(mutexTimeout); + registeredVariables[count]->commit( + timeoutTypeForSingleVars, + mutexTimeoutForSingleVars); } else { registeredVariables[count]->commitWithoutLock(); @@ -128,16 +135,19 @@ void PoolDataSetBase::handleAlreadyReadDatasetCommit(uint32_t lockTimeout) { unlockDataPool(); } -ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(uint32_t lockTimeout) { +ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit( + MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - lockDataPool(lockTimeout); + lockDataPool(timeoutType, lockTimeout); for (uint16_t count = 0; count < fillCount; count++) { if (registeredVariables[count]->getReadWriteMode() == PoolVariableIF::VAR_WRITE && registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) { if(protectEveryReadCommitCall) { - result = registeredVariables[count]->commit(mutexTimeout); + result = registeredVariables[count]->commit( + timeoutTypeForSingleVars, + mutexTimeoutForSingleVars); } else { result = registeredVariables[count]->commitWithoutLock(); @@ -160,7 +170,8 @@ ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(uint32_t lockTimeout) { } -ReturnValue_t PoolDataSetBase::lockDataPool(uint32_t timeoutMs) { +ReturnValue_t PoolDataSetBase::lockDataPool(MutexIF::TimeoutType timeoutType, + uint32_t lockTimeout) { return HasReturnvaluesIF::RETURN_OK; } @@ -206,8 +217,14 @@ void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) { this->registeredVariables = variablesContainer; } -void PoolDataSetBase::setReadCommitProtectionBehaviour( - bool protectEveryReadCommit, uint32_t mutexTimeout) { - this->protectEveryReadCommitCall = protectEveryReadCommit; - this->mutexTimeout = mutexTimeout; +PoolVariableIF** PoolDataSetBase::getContainer() const { + return registeredVariables; +} + +void PoolDataSetBase::setReadCommitProtectionBehaviour( + bool protectEveryReadCommit, MutexIF::TimeoutType timeoutType, + uint32_t mutexTimeout) { + this->protectEveryReadCommitCall = protectEveryReadCommit; + this->timeoutTypeForSingleVars = timeoutType; + this->mutexTimeoutForSingleVars = mutexTimeout; } diff --git a/datapool/PoolDataSetBase.h b/datapool/PoolDataSetBase.h index 7c1d84a4..d741dabc 100644 --- a/datapool/PoolDataSetBase.h +++ b/datapool/PoolDataSetBase.h @@ -3,6 +3,7 @@ #include "PoolDataSetIF.h" #include "PoolVariableIF.h" +#include "../serialize/SerializeIF.h" #include "../ipc/MutexIF.h" /** @@ -62,8 +63,9 @@ public: * - @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; + virtual ReturnValue_t read( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t lockTimeout = 20) override; /** * @brief The commit call initializes writing back the registered variables. * @details @@ -82,8 +84,9 @@ public: * - @c COMMITING_WITHOUT_READING if set was not read yet and * contains non write-only variables */ - virtual ReturnValue_t commit(uint32_t lockTimeout = - MutexIF::BLOCKING) override; + virtual ReturnValue_t commit( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t lockTimeout = 20) override; /** * Register the passed pool variable instance into the data set. @@ -97,8 +100,9 @@ public: * thread-safety. Default implementation is empty * @return Always returns -@c RETURN_OK */ - virtual ReturnValue_t lockDataPool(uint32_t timeoutMs = - MutexIF::BLOCKING) override; + virtual ReturnValue_t lockDataPool( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; /** * Provides the means to unlock the underlying data structure to ensure * thread-safety. Default implementation is empty @@ -124,6 +128,7 @@ protected: * @param mutexTimeout */ void setReadCommitProtectionBehaviour(bool protectEveryReadCommit, + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, uint32_t mutexTimeout = 20); /** @@ -154,14 +159,20 @@ protected: const size_t maxFillCount = 0; void setContainer(PoolVariableIF** variablesContainer); + PoolVariableIF** getContainer() const; private: bool protectEveryReadCommitCall = false; - uint32_t mutexTimeout = 20; + MutexIF::TimeoutType timeoutTypeForSingleVars; + uint32_t mutexTimeoutForSingleVars = 20; ReturnValue_t readVariable(uint16_t count); - void handleAlreadyReadDatasetCommit(uint32_t lockTimeout); - ReturnValue_t handleUnreadDatasetCommit(uint32_t lockTimeout); + void handleAlreadyReadDatasetCommit( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20); + ReturnValue_t handleUnreadDatasetCommit( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20); }; #endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */ diff --git a/datapool/PoolDataSetIF.h b/datapool/PoolDataSetIF.h index 99c06cfd..1f52871d 100644 --- a/datapool/PoolDataSetIF.h +++ b/datapool/PoolDataSetIF.h @@ -18,7 +18,10 @@ public: * thread-safety * @return Lock operation result */ - virtual ReturnValue_t lockDataPool(dur_millis_t timeoutMs) = 0; + virtual ReturnValue_t lockDataPool( + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) = 0; + /** * @brief Unlock call corresponding to the lock call. * @return Unlock operation result diff --git a/datapool/PoolEntry.cpp b/datapool/PoolEntry.cpp index 58375162..a5867222 100644 --- a/datapool/PoolEntry.cpp +++ b/datapool/PoolEntry.cpp @@ -1,32 +1,24 @@ #include "PoolEntry.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" #include "../globalfunctions/arrayprinter.h" #include #include template -PoolEntry::PoolEntry(std::initializer_list initValue, uint8_t setLength, - bool setValid ) : length(setLength), valid(setValid) { +PoolEntry::PoolEntry(std::initializer_list initValue, bool setValid ): + length(initValue.size()), valid(setValid) { this->address = new T[this->length]; if(initValue.size() == 0) { std::memset(this->address, 0, this->getByteSize()); } - else if (initValue.size() != setLength){ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "PoolEntry: setLength is not equal to initializer list" - "length! Performing zero initialization with given setLength" - << std::endl; -#endif - std::memset(this->address, 0, this->getByteSize()); - } else { std::copy(initValue.begin(), initValue.end(), this->address); } } template -PoolEntry::PoolEntry( T* initValue, uint8_t setLength, bool setValid ) : +PoolEntry::PoolEntry(T* initValue, uint8_t setLength, bool setValid): length(setLength), valid(setValid) { this->address = new T[this->length]; if (initValue != nullptr) { @@ -70,14 +62,26 @@ bool PoolEntry::getValid() { template void PoolEntry::print() { + const char* validString = nullptr; + if(valid) { + validString = "Valid"; + } + else { + validString = "Invalid"; + } #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "Pool Entry Validity: " << - (this->valid? " (valid) " : " (invalid) ") << std::endl; -#endif - arrayprinter::print(reinterpret_cast(address), length); -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << std::dec << std::endl; + sif::info << "PoolEntry information." << std::endl; + sif::info << "PoolEntry validity: " << validString << std::endl; +#else + sif::printInfo("PoolEntry information.\n"); + sif::printInfo("PoolEntry validity: %s\n", validString); #endif + arrayprinter::print(reinterpret_cast(address), getByteSize()); +} + +template +inline T* PoolEntry::getDataPtr() { + return this->address; } template @@ -88,8 +92,10 @@ Type PoolEntry::getType() { template class PoolEntry; template class PoolEntry; template class PoolEntry; +template class PoolEntry; template class PoolEntry; template class PoolEntry; template class PoolEntry; +template class PoolEntry; template class PoolEntry; template class PoolEntry; diff --git a/datapool/PoolEntry.h b/datapool/PoolEntry.h index 033db40d..30940320 100644 --- a/datapool/PoolEntry.h +++ b/datapool/PoolEntry.h @@ -35,24 +35,22 @@ public: "uint8_t"); /** * @brief In the classe's constructor, space is allocated on the heap and - * potential init values are copied to that space. + * potential initialization values are copied to that space. * @details * Not passing any arguments will initialize an non-array pool entry - * (setLength = 1) with an initial invalid state. - * Please note that if an initializer list is passed, the correct - * corresponding length should be passed too, otherwise a zero - * initialization will be performed with the given setLength. + * with an initial invalid state and the value 0. + * Please note that if an initializer list is passed, the length of the + * initializer list needs to be correct for vector entries because + * required allocated space will be deduced from the initializer list length + * and the pool entry type. * @param initValue - * Initializer list with values to initialize with, for example {0,0} to - * initialize the two entries to zero. - * @param setLength - * Defines the array length of this entry. Should be equal to the - * intializer list length. + * Initializer list with values to initialize with, for example {0, 0} to + * initialize the a pool entry of a vector with two entries to 0. * @param setValid * Sets the initialization flag. It is invalid by default. */ - PoolEntry(std::initializer_list initValue = {}, uint8_t setLength = 1, - bool setValid = false); + PoolEntry(std::initializer_list initValue = {0}, bool setValid = false); + /** * @brief In the classe's constructor, space is allocated on the heap and * potential init values are copied to that space. @@ -66,9 +64,9 @@ public: */ PoolEntry(T* initValue, uint8_t setLength = 1, bool setValid = false); - //! Explicitely deleted copy ctor, copying is not allowed! + //! Explicitely deleted copy ctor, copying is not allowed. PoolEntry(const PoolEntry&) = delete; - //! Explicitely deleted copy assignment, copying is not allowed! + //! Explicitely deleted copy assignment, copying is not allowed. PoolEntry& operator=(const PoolEntry&) = delete; /** @@ -82,21 +80,16 @@ public: ~PoolEntry(); /** - * @brief This is the address pointing to the allocated memory. + * Return typed pointer to start of data. + * @return */ - T* address; - /** - * @brief This attribute stores the length information. - */ - uint8_t length; - /** - * @brief Here, the validity information for a variable is stored. - * Every entry (single variable or vector) has one valid flag. - */ - uint8_t valid; + T* getDataPtr(); + /** * @brief getSize returns the array size of the entry. - * @details A single parameter has size 1. + * @details + * For non-array pool entries return type size, for vector entries + * return type size times the number of entries. */ uint8_t getSize(); /** @@ -123,8 +116,22 @@ public: * information to the screen. It prints all array entries in a row. */ void print(); - Type getType(); + +private: + /** + * @brief This attribute stores the length information. + */ + uint8_t length; + /** + * @brief Here, the validity information for a variable is stored. + * Every entry (single variable or vector) has one valid flag. + */ + uint8_t valid; + /** + * @brief This is the address pointing to the allocated memory. + */ + T* address; }; #endif /* FSFW_DATAPOOL_POOLENTRY_H_ */ diff --git a/datapool/PoolVariableIF.h b/datapool/PoolVariableIF.h index 9740fc12..444e19d0 100644 --- a/datapool/PoolVariableIF.h +++ b/datapool/PoolVariableIF.h @@ -25,6 +25,7 @@ class PoolVariableIF : public SerializeIF, public: static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF; static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0); + static constexpr ReturnValue_t INVALID_POOL_ENTRY = MAKE_RETURN_CODE(0xA1); static constexpr bool VALID = 1; static constexpr bool INVALID = 0; diff --git a/datapool/ReadCommitIF.h b/datapool/ReadCommitIF.h index 0cdce371..efe51594 100644 --- a/datapool/ReadCommitIF.h +++ b/datapool/ReadCommitIF.h @@ -2,6 +2,7 @@ #define FSFW_DATAPOOL_READCOMMITIF_H_ #include +#include /** * @brief Common interface for all software objects which employ read-commit @@ -10,8 +11,10 @@ class ReadCommitIF { public: virtual ~ReadCommitIF() {} - virtual ReturnValue_t read(uint32_t mutexTimeout) = 0; - virtual ReturnValue_t commit(uint32_t mutexTimeout) = 0; + virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) = 0; + virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) = 0; protected: @@ -19,11 +22,11 @@ protected: //! members with commit and read semantics where the lock is only necessary //! once. virtual ReturnValue_t readWithoutLock() { - return read(20); + return read(MutexIF::TimeoutType::WAITING, 20); } virtual ReturnValue_t commitWithoutLock() { - return commit(20); + return commit(MutexIF::TimeoutType::WAITING, 20); } }; diff --git a/datapoollocal/AccessLocalPoolF.h b/datapoollocal/AccessLocalPoolF.h new file mode 100644 index 00000000..da08644f --- /dev/null +++ b/datapoollocal/AccessLocalPoolF.h @@ -0,0 +1,27 @@ +#ifndef FSFW_DATAPOOLLOCAL_ACCESSLOCALPOOLF_H_ +#define FSFW_DATAPOOLLOCAL_ACCESSLOCALPOOLF_H_ + +class LocalDataPoolManager; +class MutexIF; + +/** + * @brief Accessor class which can be used by classes which like to use the pool manager. + */ +class AccessPoolManagerIF { +public: + virtual ~AccessPoolManagerIF() {}; + + virtual MutexIF* getLocalPoolMutex() = 0; + + /** + * Can be used to get a handle to the local data pool manager. + * This function is protected because it should only be used by the + * class imlementing the interface. + */ + virtual LocalDataPoolManager* getHkManagerHandle() = 0; + +protected: + +}; + +#endif /* FSFW_DATAPOOLLOCAL_ACCESSLOCALPOOLF_H_ */ diff --git a/datapoollocal/CMakeLists.txt b/datapoollocal/CMakeLists.txt index c6b187cd..e2db39eb 100644 --- a/datapoollocal/CMakeLists.txt +++ b/datapoollocal/CMakeLists.txt @@ -5,4 +5,6 @@ target_sources(${LIB_FSFW_NAME} LocalPoolDataSetBase.cpp LocalPoolObjectBase.cpp SharedLocalDataSet.cpp -) \ No newline at end of file +) + +add_subdirectory(internal) \ No newline at end of file diff --git a/datapoollocal/HasLocalDataPoolIF.h b/datapoollocal/HasLocalDataPoolIF.h index 7707fab8..569f2b09 100644 --- a/datapoollocal/HasLocalDataPoolIF.h +++ b/datapoollocal/HasLocalDataPoolIF.h @@ -1,52 +1,40 @@ #ifndef FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ #define FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ -#include "locPoolDefinitions.h" +#include "localPoolDefinitions.h" #include "../datapool/PoolEntryIF.h" +#include "../serviceinterface/ServiceInterface.h" #include "../ipc/MessageQueueSenderIF.h" #include "../housekeeping/HousekeepingMessage.h" #include -class LocalDataPoolManager; +class AccessPoolManagerIF; +class ProvidesDataPoolSubscriptionIF; class LocalPoolDataSetBase; class LocalPoolObjectBase; - -using LocalDataPool = std::map; -using LocalDataPoolMapIter = LocalDataPool::iterator; +class LocalDataPoolManager; /** - * @brief This interface is implemented by classes which posses a local - * data pool (not the managing class). It defines the relationship - * between the local data pool owner and the LocalDataPoolManager. + * @brief This interface is implemented by classes which posses a local data pool (not the + * managing class). It defines the relationship between the local data pool owner + * and the LocalDataPoolManager. * @details - * Any class implementing this interface shall also have a LocalDataPoolManager - * member class which contains the actual pool data structure - * and exposes the public interface for it. - * This is required because the pool entries are templates, which makes - * specifying an interface rather difficult. The local data pool can be - * accessed by using the LocalPoolVariable, LocalPoolVector or LocalDataSet - * classes. + * Any class implementing this interface shall also have a LocalDataPoolManager member class which + * contains the actual pool data structure and exposes the public interface for it. + * The local data pool can be accessed using helper classes by using the + * LocalPoolVariable, LocalPoolVector or LocalDataSet classes. Every local pool variable can + * be uniquely identified by a global pool ID (gp_id_t) and every dataset tied + * to a pool manager can be uniqely identified by a global structure ID (sid_t). * - * Architectural Note: - * This could be circumvented by using a wrapper/accessor function or - * implementing the templated function in this interface.. - * The first solution sounds better than the second but - * the LocalPoolVariable classes are templates as well, so this just shifts - * the problem somewhere else. Interfaces are nice, but the most - * pragmatic solution I found was to offer the client the full interface - * of the LocalDataPoolManager. */ class HasLocalDataPoolIF { + friend class HasLocalDpIFManagerAttorney; + friend class HasLocalDpIFUserAttorney; public: virtual~ HasLocalDataPoolIF() {}; - static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; - - static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x00); - static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x01); - static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID; virtual object_id_t getObjectId() const = 0; @@ -59,13 +47,9 @@ public: * 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, + virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& 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. @@ -73,40 +57,17 @@ public: */ 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) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden" - << ". Returning nullptr!" << std::endl; -#endif - return nullptr; - } - /** * @brief This function will be called by the manager if an update * notification is received. - * @details + * @details HasLocalDataPoolIF * Can be overriden by the child class to handle changed datasets. * @param sid * @param storeId If a snapshot was requested, data will be located inside * the IPC store with this store ID. */ virtual void handleChangedDataset(sid_t sid, - store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { + store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { return; } @@ -124,18 +85,68 @@ public: return; } - /* These function can be implemented by pool owner, as they are required - * by the housekeeping message interface */ + /** + * These function can be implemented by pool owner, if they are required + * and used by the housekeeping message interface. + * */ virtual ReturnValue_t addDataSet(sid_t sid) { return HasReturnvaluesIF::RETURN_FAILED; }; virtual ReturnValue_t removeDataSet(sid_t sid) { return HasReturnvaluesIF::RETURN_FAILED; }; - virtual ReturnValue_t changeCollectionInterval(sid_t sid, - float newIntervalSeconds) { + virtual ReturnValue_t changeCollectionInterval(sid_t sid, float newIntervalSeconds) { return HasReturnvaluesIF::RETURN_FAILED; }; + + /** + * This function can be used by data pool consumers to retrieve a handle + * which allows subscriptions to dataset and variable updates in form of messages. + * The consumers can then read the most recent variable value by calling read with + * an own pool variable or set instance or using the deserialized snapshot data. + * @return + */ + virtual ProvidesDataPoolSubscriptionIF* getSubscriptionInterface() = 0; + +protected: + + /** + * Accessor handle required for internal handling. Not intended for users and therefore + * declared protected. Users should instead use pool variables, sets or the subscription + * interface to access pool entries. + * @return + */ + virtual AccessPoolManagerIF* getAccessorHandle() = 0; + + /** + * This function is used by the pool manager to get a valid dataset + * from a SID. This function is protected to prevent users from + * using raw data set pointers which could not be thread-safe. Users + * should use the #ProvidesDataPoolSubscriptionIF. + * @param sid Corresponding structure ID + * @return + */ + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) = 0; + + /** + * Similar to the function above, but used to get a local pool variable + * handle. This is only needed for update notifications, so it is not + * defined as abstract. This function is protected to prevent users from + * using raw pool variable pointers which could not be thread-safe. + * Users should use the #ProvidesDataPoolSubscriptionIF. + * @param localPoolId + * @return + */ + virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden" + << ". Returning nullptr!" << std::endl; +#else + sif::printWarning("HasLocalDataPoolIF::getPoolObjectHandle: " + "Not overriden. Returning nullptr!\n"); +#endif + return nullptr; + } }; #endif /* FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ */ diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp index 24516aad..462ef17f 100644 --- a/datapoollocal/LocalDataPoolManager.cpp +++ b/datapoollocal/LocalDataPoolManager.cpp @@ -1,11 +1,13 @@ +#include "HasLocalDataPoolIF.h" #include "LocalDataPoolManager.h" #include "LocalPoolObjectBase.h" #include "LocalPoolDataSetBase.h" +#include "internal/LocalPoolDataSetAttorney.h" +#include "internal/HasLocalDpIFManagerAttorney.h" #include "../housekeeping/HousekeepingPacketUpdate.h" #include "../housekeeping/HousekeepingSetPacket.h" #include "../housekeeping/AcceptsHkPacketsIF.h" - #include "../timemanager/CCSDSTime.h" #include "../ipc/MutexFactory.h" #include "../ipc/MutexHelper.h" @@ -14,797 +16,896 @@ #include #include -object_id_t LocalDataPoolManager::defaultHkDestination = - objects::PUS_SERVICE_3_HOUSEKEEPING; +object_id_t LocalDataPoolManager::defaultHkDestination = objects::PUS_SERVICE_3_HOUSEKEEPING; -LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, - MessageQueueIF* queueToUse, bool appendValidityBuffer): - appendValidityBuffer(appendValidityBuffer) { - if(owner == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalDataPoolManager::LocalDataPoolManager: " - << "Invalid supplied owner!" << std::endl; -#endif - return; - } - this->owner = owner; - mutex = MutexFactory::instance()->createMutex(); - if(mutex == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalDataPoolManager::LocalDataPoolManager: " - << "Could not create mutex." << std::endl; -#endif - } +LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, + bool appendValidityBuffer): + appendValidityBuffer(appendValidityBuffer) { + if(owner == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED, + "Invalid supplied owner"); + return; + } + this->owner = owner; + mutex = MutexFactory::instance()->createMutex(); + if(mutex == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "LocalDataPoolManager", HasReturnvaluesIF::RETURN_FAILED, + "Could not create mutex"); + } - hkQueue = queueToUse; + hkQueue = queueToUse; } LocalDataPoolManager::~LocalDataPoolManager() {} ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { - if(queueToUse == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalDataPoolManager::initialize: " - << std::hex << "0x" << owner->getObjectId() << ". Supplied " - << "queue invalid!" << std::dec << std::endl; -#endif - } - hkQueue = queueToUse; + if(queueToUse == nullptr) { + // error, all destinations invalid + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", QUEUE_OR_DESTINATION_INVALID); + } + hkQueue = queueToUse; - ipcStore = objectManager->get(objects::IPC_STORE); - if(ipcStore == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalDataPoolManager::initialize: " - << std::hex << "0x" << owner->getObjectId() << ": Could not " - << "set IPC store." <get(objects::IPC_STORE); + if(ipcStore == nullptr) { + // error, all destinations invalid + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", HasReturnvaluesIF::RETURN_FAILED, + "Could not set IPC store."); + return HasReturnvaluesIF::RETURN_FAILED; + } - if(defaultHkDestination != objects::NO_OBJECT) { - AcceptsHkPacketsIF* hkPacketReceiver = - objectManager->get(defaultHkDestination); - if(hkPacketReceiver != nullptr) { - hkDestinationId = hkPacketReceiver->getHkQueue(); - } - else { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalDataPoolManager::LocalDataPoolManager: " - << "Default HK destination object is invalid!" << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } - } + if(defaultHkDestination != objects::NO_OBJECT) { + AcceptsHkPacketsIF* hkPacketReceiver = + objectManager->get(defaultHkDestination); + if(hkPacketReceiver != nullptr) { + hkDestinationId = hkPacketReceiver->getHkQueue(); + } + else { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } + } - return HasReturnvaluesIF::RETURN_OK; + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation( - uint8_t nonDiagInvlFactor) { - setNonDiagnosticIntervalFactor(nonDiagInvlFactor); - return initializeHousekeepingPoolEntriesOnce(); + uint8_t nonDiagInvlFactor) { + setNonDiagnosticIntervalFactor(nonDiagInvlFactor); + return initializeHousekeepingPoolEntriesOnce(); } ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { - if(not mapInitialized) { - ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, - *this); - if(result == HasReturnvaluesIF::RETURN_OK) { - mapInitialized = true; - } - return result; - } -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "HousekeepingManager: The map should only be initialized " - << "once!" << std::endl; -#endif - return HasReturnvaluesIF::RETURN_OK; + if(not mapInitialized) { + ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, + *this); + if(result == HasReturnvaluesIF::RETURN_OK) { + mapInitialized = true; + } + return result; + } + + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "initialize", HasReturnvaluesIF::RETURN_FAILED, + "The map should only be initialized once"); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::performHkOperation() { - ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; - for(auto& receiver: hkReceiversMap) { - switch(receiver.reportingType) { - case(ReportingType::PERIODIC): { - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - // Periodic packets shall only be generated from datasets. - continue; - } - performPeriodicHkGeneration(receiver); - break; - } - case(ReportingType::UPDATE_HK): { - handleHkUpdate(receiver, status); - break; - } - case(ReportingType::UPDATE_NOTIFICATION): { - handleNotificationUpdate(receiver, status); - break; - } - case(ReportingType::UPDATE_SNAPSHOT): { - handleNotificationSnapshot(receiver, status); - break; - } - default: - // This should never happen. - return HasReturnvaluesIF::RETURN_FAILED; - } - } - resetHkUpdateResetHelper(); - return status; + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; + for(auto& receiver: hkReceiversMap) { + switch(receiver.reportingType) { + case(ReportingType::PERIODIC): { + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + // Periodic packets shall only be generated from datasets. + continue; + } + performPeriodicHkGeneration(receiver); + break; + } + case(ReportingType::UPDATE_HK): { + handleHkUpdate(receiver, status); + break; + } + case(ReportingType::UPDATE_NOTIFICATION): { + handleNotificationUpdate(receiver, status); + break; + } + case(ReportingType::UPDATE_SNAPSHOT): { + handleNotificationSnapshot(receiver, status); + break; + } + default: + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } + } + resetHkUpdateResetHelper(); + return status; } ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver, - ReturnValue_t& status) { - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - // Update packets shall only be generated from datasets. - return HasReturnvaluesIF::RETURN_FAILED; - } - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( - receiver.dataId.sid); - if(dataSet->hasChanged()) { - // prepare and send update notification - ReturnValue_t result = generateHousekeepingPacket( - receiver.dataId.sid, dataSet, true); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - } - handleChangeResetLogic(receiver.dataType, receiver.dataId, - dataSet); - return HasReturnvaluesIF::RETURN_OK; + ReturnValue_t& status) { + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + // Update packets shall only be generated from datasets. + return HasReturnvaluesIF::RETURN_FAILED; + } + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid); + if(dataSet->hasChanged()) { + // prepare and send update notification + ReturnValue_t result = generateHousekeepingPacket( + receiver.dataId.sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + } + handleChangeResetLogic(receiver.dataType, receiver.dataId, + dataSet); + return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t LocalDataPoolManager::handleNotificationUpdate( - HkReceiver& receiver, ReturnValue_t& status) { - MarkChangedIF* toReset = nullptr; - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle( - receiver.dataId.localPoolId); - if(poolObj == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - if(poolObj->hasChanged()) { - // prepare and send update notification. - CommandMessage notification; - HousekeepingMessage::setUpdateNotificationVariableCommand( - ¬ification, receiver.dataId.localPoolId); - ReturnValue_t result = hkQueue->sendMessage( - receiver.destinationQueue, ¬ification); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = poolObj; - } +ReturnValue_t LocalDataPoolManager::handleNotificationUpdate(HkReceiver& receiver, + ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, + receiver.dataId.localPoolId); + //LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle(receiver.dataId.localPoolId); + if(poolObj == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationUpdate", POOLOBJECT_NOT_FOUND); + return POOLOBJECT_NOT_FOUND; + } + if(poolObj->hasChanged()) { + // prepare and send update notification. + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationVariableCommand(¬ification, + receiver.dataId.localPoolId); + ReturnValue_t result = hkQueue->sendMessage( + receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } - } - else { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( - receiver.dataId.sid); - if(dataSet == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - if(dataSet->hasChanged()) { - // prepare and send update notification - CommandMessage notification; - HousekeepingMessage::setUpdateNotificationSetCommand( - ¬ification, receiver.dataId.sid); - ReturnValue_t result = hkQueue->sendMessage( - receiver.destinationQueue, ¬ification); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = dataSet; - } - } - if(toReset != nullptr) { - handleChangeResetLogic(receiver.dataType, - receiver.dataId, toReset); - } - return HasReturnvaluesIF::RETURN_OK; + } + else { + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationUpdate", DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } + if(dataSet->hasChanged()) { + // prepare and send update notification + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationSetCommand( + ¬ification, receiver.dataId.sid); + ReturnValue_t result = hkQueue->sendMessage( + receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; + } + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, + receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot( - HkReceiver& receiver, ReturnValue_t& status) { - MarkChangedIF* toReset = nullptr; - // check whether data has changed and send messages in case it has. - if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { - LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle( - receiver.dataId.localPoolId); - if(poolObj == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } + HkReceiver& receiver, ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + // check whether data has changed and send messages in case it has. + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, + receiver.dataId.localPoolId); + if(poolObj == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationSnapshot", POOLOBJECT_NOT_FOUND); + return POOLOBJECT_NOT_FOUND; + } - if (not poolObj->hasChanged()) { - return HasReturnvaluesIF::RETURN_OK; - } + if (not poolObj->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } - // prepare and send update snapshot. - timeval now; - Clock::getClock_timeval(&now); - CCSDSTime::CDS_short cds; - CCSDSTime::convertToCcsds(&cds, &now); - HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), - sizeof(cds), owner->getPoolObjectHandle( - receiver.dataId.localPoolId)); + // prepare and send update snapshot. + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + sizeof(cds), HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, + receiver.dataId.localPoolId)); - store_address_t storeId; - ReturnValue_t result = addUpdateToStore(updatePacket, storeId); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - CommandMessage notification; - HousekeepingMessage::setUpdateSnapshotVariableCommand(¬ification, - receiver.dataId.localPoolId, storeId); - result = hkQueue->sendMessage(receiver.destinationQueue, - ¬ification); - if (result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = poolObj; - } - else { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( - receiver.dataId.sid); - if(dataSet == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotVariableCommand(¬ification, + receiver.dataId.localPoolId, storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, + ¬ification); + if (result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } + else { + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "handleNotificationSnapshot", DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } - if(not dataSet->hasChanged()) { - return HasReturnvaluesIF::RETURN_OK; - } + if(not dataSet->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } - // prepare and send update snapshot. - timeval now; - Clock::getClock_timeval(&now); - CCSDSTime::CDS_short cds; - CCSDSTime::convertToCcsds(&cds, &now); - HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), - sizeof(cds), owner->getDataSetHandle(receiver.dataId.sid)); + // prepare and send update snapshot. + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + sizeof(cds), HasLocalDpIFManagerAttorney::getDataSetHandle(owner, + receiver.dataId.sid)); - store_address_t storeId; - ReturnValue_t result = addUpdateToStore(updatePacket, storeId); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - CommandMessage notification; - HousekeepingMessage::setUpdateSnapshotSetCommand( - ¬ification, receiver.dataId.sid, storeId); - result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); - if(result != HasReturnvaluesIF::RETURN_OK) { - status = result; - } - toReset = dataSet; + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotSetCommand( + ¬ification, receiver.dataId.sid, storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; - } - if(toReset != nullptr) { - handleChangeResetLogic(receiver.dataType, - receiver.dataId, toReset); - } - return HasReturnvaluesIF::RETURN_OK; + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, + receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::addUpdateToStore( - HousekeepingPacketUpdate& updatePacket, store_address_t& storeId) { - size_t updatePacketSize = updatePacket.getSerializedSize(); - uint8_t *storePtr = nullptr; - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - updatePacket.getSerializedSize(), &storePtr); - if (result != HasReturnvaluesIF::RETURN_OK) { - return result; - } - size_t serializedSize = 0; - result = updatePacket.serialize(&storePtr, &serializedSize, - updatePacketSize, SerializeIF::Endianness::MACHINE); - return result;; + HousekeepingPacketUpdate& updatePacket, store_address_t& storeId) { + size_t updatePacketSize = updatePacket.getSerializedSize(); + uint8_t *storePtr = nullptr; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + updatePacket.getSerializedSize(), &storePtr); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t serializedSize = 0; + result = updatePacket.serialize(&storePtr, &serializedSize, + updatePacketSize, SerializeIF::Endianness::MACHINE); + return result;; } void LocalDataPoolManager::handleChangeResetLogic( - DataType type, DataId dataId, MarkChangedIF* toReset) { - if(hkUpdateResetList == nullptr) { - // config error! - return; - } + DataType type, DataId dataId, MarkChangedIF* toReset) { + if(hkUpdateResetList == nullptr) { + // config error! + return; + } + HkUpdateResetList& listRef = *hkUpdateResetList; + for(auto& changeInfo: listRef) { + if(changeInfo.dataType != type) { + continue; + } + if((changeInfo.dataType == DataType::DATA_SET) and + (changeInfo.dataId.sid != dataId.sid)) { + continue; + } + if((changeInfo.dataType == DataType::LOCAL_POOL_VARIABLE) and + (changeInfo.dataId.localPoolId != dataId.localPoolId)) { + continue; + } - for(auto& changeInfo: *hkUpdateResetList) { - if(changeInfo.dataType != type) { - continue; - } - if((changeInfo.dataType == DataType::DATA_SET) and - (changeInfo.dataId.sid != dataId.sid)) { - continue; - } - if((changeInfo.dataType == DataType::LOCAL_POOL_VARIABLE) and - (changeInfo.dataId.localPoolId != dataId.localPoolId)) { - continue; - } - - if(changeInfo.updateCounter <= 1) { - toReset->setChanged(false); - } - if(changeInfo.currentUpdateCounter == 0) { - toReset->setChanged(false); - } - else { - changeInfo.currentUpdateCounter--; - } - return; - } + // only one update recipient, we can reset changes status immediately. + if(changeInfo.updateCounter <= 1) { + toReset->setChanged(false); + } + // All recipients have been notified, reset the changed flag. + if(changeInfo.currentUpdateCounter <= 1) { + toReset->setChanged(false); + changeInfo.currentUpdateCounter = 0; + } + // Not all recipiens have been notified yet, decrement. + else { + changeInfo.currentUpdateCounter--; + } + return; + } } void LocalDataPoolManager::resetHkUpdateResetHelper() { - if(hkUpdateResetList == nullptr) { - return; - } + if(hkUpdateResetList == nullptr) { + return; + } - for(auto& changeInfo: *hkUpdateResetList) { - changeInfo.currentUpdateCounter = changeInfo.updateCounter; - } + for(auto& changeInfo: *hkUpdateResetList) { + changeInfo.currentUpdateCounter = changeInfo.updateCounter; + } } ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid, - bool enableReporting, float collectionInterval, bool isDiagnostics, - object_id_t packetDestination) { - AcceptsHkPacketsIF* hkReceiverObject = - objectManager->get(packetDestination); - if(hkReceiverObject == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" - << " Invalid receiver!"<< std::endl; -#endif - return HasReturnvaluesIF::RETURN_OK; - } + bool enableReporting, float collectionInterval, bool isDiagnostics, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + objectManager->get(packetDestination); + if(hkReceiverObject == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } - struct HkReceiver hkReceiver; - hkReceiver.dataId.sid = sid; - hkReceiver.reportingType = ReportingType::PERIODIC; - hkReceiver.dataType = DataType::DATA_SET; - hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); + struct HkReceiver hkReceiver; + hkReceiver.dataId.sid = sid; + hkReceiver.reportingType = ReportingType::PERIODIC; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(dataSet != nullptr) { - dataSet->setReportingEnabled(enableReporting); - dataSet->setDiagnostic(isDiagnostics); - dataSet->initializePeriodicHelper(collectionInterval, - owner->getPeriodicOperationFrequency(), isDiagnostics); - } + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(dataSet != nullptr) { + LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enableReporting); + LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); + LocalPoolDataSetAttorney::initializePeriodicHelper(*dataSet, collectionInterval, + owner->getPeriodicOperationFrequency(), isDiagnostics); + } - hkReceiversMap.push_back(hkReceiver); - return HasReturnvaluesIF::RETURN_OK; + hkReceiversMap.push_back(hkReceiver); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::subscribeForUpdatePackets(sid_t sid, - bool isDiagnostics, bool reportingEnabled, - object_id_t packetDestination) { - AcceptsHkPacketsIF* hkReceiverObject = - objectManager->get(packetDestination); - if(hkReceiverObject == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" - << " Invalid receiver!"<< std::endl; -#endif - return HasReturnvaluesIF::RETURN_OK; - } + bool isDiagnostics, bool reportingEnabled, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + objectManager->get(packetDestination); + if(hkReceiverObject == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "subscribeForPeriodicPacket", QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } - struct HkReceiver hkReceiver; - hkReceiver.dataId.sid = sid; - hkReceiver.reportingType = ReportingType::UPDATE_HK; - hkReceiver.dataType = DataType::DATA_SET; - hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); + struct HkReceiver hkReceiver; + hkReceiver.dataId.sid = sid; + hkReceiver.reportingType = ReportingType::UPDATE_HK; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(dataSet != nullptr) { - dataSet->setReportingEnabled(true); - dataSet->setDiagnostic(isDiagnostics); - } + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(dataSet != nullptr) { + LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, true); + LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); + } - hkReceiversMap.push_back(hkReceiver); + hkReceiversMap.push_back(hkReceiver); - handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); - return HasReturnvaluesIF::RETURN_OK; + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessages( - const uint32_t setId, object_id_t destinationObject, - MessageQueueId_t targetQueueId, bool generateSnapshot) { - struct HkReceiver hkReceiver; - hkReceiver.dataType = DataType::DATA_SET; - hkReceiver.dataId.sid = sid_t(this->getOwner()->getObjectId(), setId); - hkReceiver.destinationQueue = targetQueueId; - hkReceiver.objectId = destinationObject; - if(generateSnapshot) { - hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; - } - else { - hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; - } + const uint32_t setId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.dataId.sid = sid_t(owner->getObjectId(), setId); + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } - hkReceiversMap.push_back(hkReceiver); + hkReceiversMap.push_back(hkReceiver); - handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); - return HasReturnvaluesIF::RETURN_OK; + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessages( - const lp_id_t localPoolId, object_id_t destinationObject, - MessageQueueId_t targetQueueId, bool generateSnapshot) { - struct HkReceiver hkReceiver; - hkReceiver.dataType = DataType::LOCAL_POOL_VARIABLE; - hkReceiver.dataId.localPoolId = localPoolId; - hkReceiver.destinationQueue = targetQueueId; - hkReceiver.objectId = destinationObject; - if(generateSnapshot) { - hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; - } - else { - hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; - } + const lp_id_t localPoolId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::LOCAL_POOL_VARIABLE; + hkReceiver.dataId.localPoolId = localPoolId; + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } - hkReceiversMap.push_back(hkReceiver); + hkReceiversMap.push_back(hkReceiver); - handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); - return HasReturnvaluesIF::RETURN_OK; + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; } void LocalDataPoolManager::handleHkUpdateResetListInsertion(DataType dataType, - DataId dataId) { - if(hkUpdateResetList == nullptr) { - hkUpdateResetList = new std::vector(); - } + DataId dataId) { + if(hkUpdateResetList == nullptr) { + hkUpdateResetList = new std::vector(); + } - for(auto& updateResetStruct: *hkUpdateResetList) { - if(dataType == DataType::DATA_SET) { - if(updateResetStruct.dataId.sid == dataId.sid) { - updateResetStruct.updateCounter++; - updateResetStruct.currentUpdateCounter++; - return; - } - } - else { - if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) { - updateResetStruct.updateCounter++; - updateResetStruct.currentUpdateCounter++; - return; - } - } + for(auto& updateResetStruct: *hkUpdateResetList) { + if(dataType == DataType::DATA_SET) { + if(updateResetStruct.dataId.sid == dataId.sid) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + else { + if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } - } - HkUpdateResetHelper hkUpdateResetHelper; - hkUpdateResetHelper.currentUpdateCounter = 1; - hkUpdateResetHelper.updateCounter = 1; - hkUpdateResetHelper.dataType = dataType; - if(dataType == DataType::DATA_SET) { - hkUpdateResetHelper.dataId.sid = dataId.sid; - } - else { - hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId; - } - hkUpdateResetList->push_back(hkUpdateResetHelper); + } + HkUpdateResetHelper hkUpdateResetHelper; + hkUpdateResetHelper.currentUpdateCounter = 1; + hkUpdateResetHelper.updateCounter = 1; + hkUpdateResetHelper.dataType = dataType; + if(dataType == DataType::DATA_SET) { + hkUpdateResetHelper.dataId.sid = dataId.sid; + } + else { + hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId; + } + hkUpdateResetList->push_back(hkUpdateResetHelper); } ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( - CommandMessage* message) { - Command_t command = message->getCommand(); - sid_t sid = HousekeepingMessage::getSid(message); - ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; - switch(command) { - // Houskeeping interface handling. - case(HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): { - result = togglePeriodicGeneration(sid, true, true); - break; - } + CommandMessage* message) { + Command_t command = message->getCommand(); + sid_t sid = HousekeepingMessage::getSid(message); + ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; + switch(command) { + // Houskeeping interface handling. + case(HousekeepingMessage::ENABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, true, true); + break; + } - case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): { - result = togglePeriodicGeneration(sid, false, true); - break; - } + case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): { + result = togglePeriodicGeneration(sid, false, true); + break; + } - case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): { - result = togglePeriodicGeneration(sid, true, false); - break; - } + case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, true, false); + break; + } - case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): { - result = togglePeriodicGeneration(sid, false, false); - break; - } + case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): { + result = togglePeriodicGeneration(sid, false, false); + break; + } - case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): - return generateSetStructurePacket(sid, true); - case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): - return generateSetStructurePacket(sid, false); - case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL): - case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): { - float newCollIntvl = 0; - HousekeepingMessage::getCollectionIntervalModificationCommand(message, - &newCollIntvl); - if(command == HousekeepingMessage:: - MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) { - result = changeCollectionInterval(sid, newCollIntvl, true); - } - else { - result = changeCollectionInterval(sid, newCollIntvl, false); - } - break; - } + case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): { + return generateSetStructurePacket(sid, true); + } - case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): - case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT - and dataSet->isDiagnostics()) { - return WRONG_HK_PACKET_TYPE; - } - else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT - and not dataSet->isDiagnostics()) { - return WRONG_HK_PACKET_TYPE; - } - return generateHousekeepingPacket(HousekeepingMessage::getSid(message), - dataSet, true); - } + case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): { + return generateSetStructurePacket(sid, false); + } + case(HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL): + case(HousekeepingMessage::MODIFY_PARAMETER_REPORT_COLLECTION_INTERVAL): { + float newCollIntvl = 0; + HousekeepingMessage::getCollectionIntervalModificationCommand(message, + &newCollIntvl); + if(command == HousekeepingMessage:: + MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) { + result = changeCollectionInterval(sid, newCollIntvl, true); + } + else { + result = changeCollectionInterval(sid, newCollIntvl, false); + } + break; + } - // Notification handling. - case(HousekeepingMessage::UPDATE_NOTIFICATION_SET): { - owner->handleChangedDataset(sid); - return HasReturnvaluesIF::RETURN_OK; - } - case(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE): { - lp_id_t locPoolId = HousekeepingMessage:: - getUpdateNotificationVariableCommand(message); - owner->handleChangedPoolVariable(locPoolId); - return HasReturnvaluesIF::RETURN_OK; - } - case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { - store_address_t storeId; - HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId); - owner->handleChangedDataset(sid, storeId); - return HasReturnvaluesIF::RETURN_OK; - } - case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { - store_address_t storeId; - lp_id_t localPoolId = HousekeepingMessage:: - getUpdateSnapshotVariableCommand(message, &storeId); - owner->handleChangedPoolVariable(localPoolId, storeId); - return HasReturnvaluesIF::RETURN_OK; - } + case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): + case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { + LocalPoolDataSetBase* dataSet =HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT + and LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { + return WRONG_HK_PACKET_TYPE; + } + else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT + and not LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { + return WRONG_HK_PACKET_TYPE; + } + return generateHousekeepingPacket(HousekeepingMessage::getSid(message), + dataSet, true); + } - default: - return CommandMessageIF::UNKNOWN_COMMAND; - } + // Notification handling. + case(HousekeepingMessage::UPDATE_NOTIFICATION_SET): { + owner->handleChangedDataset(sid); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE): { + lp_id_t locPoolId = HousekeepingMessage:: + getUpdateNotificationVariableCommand(message); + owner->handleChangedPoolVariable(locPoolId); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { + store_address_t storeId; + HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId); + owner->handleChangedDataset(sid, storeId); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { + store_address_t storeId; + lp_id_t localPoolId = HousekeepingMessage:: + getUpdateSnapshotVariableCommand(message, &storeId); + owner->handleChangedPoolVariable(localPoolId, storeId); + return HasReturnvaluesIF::RETURN_OK; + } - CommandMessage reply; - if(result != HasReturnvaluesIF::RETURN_OK) { - HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); - } - else { - HousekeepingMessage::setHkRequestSuccessReply(&reply, sid); - } - hkQueue->sendMessage(hkDestinationId, &reply); - return result; + default: + return CommandMessageIF::UNKNOWN_COMMAND; + } + + CommandMessage reply; + if(result != HasReturnvaluesIF::RETURN_OK) { + HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); + } + else { + HousekeepingMessage::setHkRequestSuccessReply(&reply, sid); + } + hkQueue->sendMessage(hkDestinationId, &reply); + return result; } ReturnValue_t LocalDataPoolManager::printPoolEntry( - lp_id_t localPoolId) { - auto poolIter = localPoolMap.find(localPoolId); - if (poolIter == localPoolMap.end()) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "HousekeepingManager::fechPoolEntry:" - << " Pool entry not found." << std::endl; -#endif - return HasLocalDataPoolIF::POOL_ENTRY_NOT_FOUND; - } - poolIter->second->print(); - return HasReturnvaluesIF::RETURN_OK; + lp_id_t localPoolId) { + auto poolIter = localPoolMap.find(localPoolId); + if (poolIter == localPoolMap.end()) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, "printPoolEntry", + localpool::POOL_ENTRY_NOT_FOUND); + return localpool::POOL_ENTRY_NOT_FOUND; + } + poolIter->second->print(); + return HasReturnvaluesIF::RETURN_OK; } MutexIF* LocalDataPoolManager::getMutexHandle() { - return mutex; + return mutex; } HasLocalDataPoolIF* LocalDataPoolManager::getOwner() { - return owner; + return owner; } ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, - LocalPoolDataSetBase* dataSet, bool forDownlink, - MessageQueueId_t destination) { - if(dataSet == nullptr) { - // Configuration error. -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "HousekeepingManager::generateHousekeepingPacket:" - << " Set ID not found or dataset not assigned!" << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } + LocalPoolDataSetBase* dataSet, bool forDownlink, + MessageQueueId_t destination) { + if(dataSet == nullptr) { + // Configuration error. + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateHousekeepingPacket", + DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } - store_address_t storeId; - HousekeepingPacketDownlink hkPacket(sid, dataSet); - size_t serializedSize = 0; - ReturnValue_t result = serializeHkPacketIntoStore(hkPacket, storeId, - forDownlink, &serializedSize); - if(result != HasReturnvaluesIF::RETURN_OK or serializedSize == 0) { - return result; - } + store_address_t storeId; + HousekeepingPacketDownlink hkPacket(sid, dataSet); + size_t serializedSize = 0; + ReturnValue_t result = serializeHkPacketIntoStore(hkPacket, storeId, + forDownlink, &serializedSize); + if(result != HasReturnvaluesIF::RETURN_OK or serializedSize == 0) { + return result; + } - // and now we set a HK message and send it the HK packet destination. - CommandMessage hkMessage; - if(dataSet->isDiagnostics()) { - HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); - } - else { - HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId); - } + // and now we set a HK message and send it the HK packet destination. + CommandMessage hkMessage; + if(LocalPoolDataSetAttorney::isDiagnostics(*dataSet)) { + HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); + } + else { + HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId); + } - if(hkQueue == nullptr) { - return QUEUE_OR_DESTINATION_NOT_SET; - } - if(destination == MessageQueueIF::NO_QUEUE) { - if(hkDestinationId == MessageQueueIF::NO_QUEUE) { - // error, all destinations invalid - return HasReturnvaluesIF::RETURN_FAILED; - } - destination = hkDestinationId; - } + if(hkQueue == nullptr) { + // error, no queue available to send packet with. + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateHousekeepingPacket", + QUEUE_OR_DESTINATION_INVALID); + return QUEUE_OR_DESTINATION_INVALID; + } + if(destination == MessageQueueIF::NO_QUEUE) { + if(hkDestinationId == MessageQueueIF::NO_QUEUE) { + // error, all destinations invalid + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateHousekeepingPacket", + QUEUE_OR_DESTINATION_INVALID); + } + destination = hkDestinationId; + } - return hkQueue->sendMessage(destination, &hkMessage); + return hkQueue->sendMessage(destination, &hkMessage); } ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( - HousekeepingPacketDownlink& hkPacket, - store_address_t& storeId, bool forDownlink, - size_t* serializedSize) { - uint8_t* dataPtr = nullptr; - const size_t maxSize = hkPacket.getSerializedSize(); - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - maxSize, &dataPtr); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + HousekeepingPacketDownlink& hkPacket, + store_address_t& storeId, bool forDownlink, + size_t* serializedSize) { + uint8_t* dataPtr = nullptr; + const size_t maxSize = hkPacket.getSerializedSize(); + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + maxSize, &dataPtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } - if(forDownlink) { - return hkPacket.serialize(&dataPtr, serializedSize, maxSize, - SerializeIF::Endianness::BIG); - } - return hkPacket.serialize(&dataPtr, serializedSize, maxSize, - SerializeIF::Endianness::MACHINE); + if(forDownlink) { + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::BIG); + } + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::MACHINE); } void LocalDataPoolManager::setNonDiagnosticIntervalFactor( - uint8_t nonDiagInvlFactor) { - this->nonDiagnosticIntervalFactor = nonDiagInvlFactor; + uint8_t nonDiagInvlFactor) { + this->nonDiagnosticIntervalFactor = nonDiagInvlFactor; } void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { - sid_t sid = receiver.dataId.sid; - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(not dataSet->getReportingEnabled()) { - return; - } + sid_t sid = receiver.dataId.sid; + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "performPeriodicHkGeneration", + DATASET_NOT_FOUND); + return; + } - if(dataSet->periodicHelper == nullptr) { - // Configuration error. - return; - } + if(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet)) { + return; + } - if(not dataSet->periodicHelper->checkOpNecessary()) { - return; - } + PeriodicHousekeepingHelper* periodicHelper = + LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); - ReturnValue_t result = generateHousekeepingPacket( - sid, dataSet, true); - if(result != HasReturnvaluesIF::RETURN_OK) { - // configuration error + if(periodicHelper == nullptr) { + // Configuration error. + return; + } + + if(periodicHelper->checkOpNecessary()) { + return; + } + + ReturnValue_t result = generateHousekeepingPacket( + sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + // configuration error #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "LocalDataPoolManager::performHkOperation:" - << "0x" << std::hex << std::setfill('0') << std::setw(8) - << owner->getObjectId() << " Error generating " - << "HK packet" << std::setfill(' ') << std::dec << std::endl; + sif::warning << "LocalDataPoolManager::performHkOperation: " + << "HK generation failed." << std::endl; +#else + sif::printWarning("LocalDataPoolManager::performHkOperation: " + "HK generation failed.\n"); #endif - } + } } ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, - bool enable, bool isDiagnostics) { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if((dataSet->isDiagnostics() and not isDiagnostics) or - (not dataSet->isDiagnostics() and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } + bool enable, bool isDiagnostics) { + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if((LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and not isDiagnostics) or + (not LocalPoolDataSetAttorney::isDiagnostics(*dataSet) and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } - if((dataSet->getReportingEnabled() and enable) or - (not dataSet->getReportingEnabled() and not enable)) { - return REPORTING_STATUS_UNCHANGED; - } + if((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or + (not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) { + return REPORTING_STATUS_UNCHANGED; + } - dataSet->setReportingEnabled(enable); - return HasReturnvaluesIF::RETURN_OK; + LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, - float newCollectionInterval, bool isDiagnostics) { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - bool targetIsDiagnostics = dataSet->isDiagnostics(); - if((targetIsDiagnostics and not isDiagnostics) or - (not targetIsDiagnostics and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } + float newCollectionInterval, bool isDiagnostics) { + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } - if(dataSet->periodicHelper == nullptr) { - // config error - return PERIODIC_HELPER_INVALID; - } + PeriodicHousekeepingHelper* periodicHelper = + LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); - dataSet->periodicHelper->changeCollectionInterval(newCollectionInterval); - return HasReturnvaluesIF::RETURN_OK; + if(periodicHelper == nullptr) { + // config error + return PERIODIC_HELPER_INVALID; + } + + periodicHelper->changeCollectionInterval(newCollectionInterval); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, - bool isDiagnostics) { - // Get and check dataset first. - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(dataSet == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "HousekeepingManager::generateHousekeepingPacket:" - << " Set ID not found" << std::endl; -#endif - return HasReturnvaluesIF::RETURN_FAILED; - } + bool isDiagnostics) { + // Get and check dataset first. + //LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); + if(dataSet == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "performPeriodicHkGeneration", + DATASET_NOT_FOUND); + return DATASET_NOT_FOUND; + } - bool targetIsDiagnostics = dataSet->isDiagnostics(); - if((targetIsDiagnostics and not isDiagnostics) or - (not targetIsDiagnostics and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } + bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } - bool valid = dataSet->isValid(); - bool reportingEnabled = dataSet->getReportingEnabled(); - float collectionInterval = - dataSet->periodicHelper->getCollectionIntervalInSeconds(); + bool valid = dataSet->isValid(); + bool reportingEnabled = LocalPoolDataSetAttorney::getReportingEnabled(*dataSet); + float collectionInterval = LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet)-> + getCollectionIntervalInSeconds(); - // Generate set packet which can be serialized. - HousekeepingSetPacket setPacket(sid, - reportingEnabled, valid, collectionInterval, dataSet); - size_t expectedSize = setPacket.getSerializedSize(); - uint8_t* storePtr = nullptr; - store_address_t storeId; - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - expectedSize,&storePtr); - if(result != HasReturnvaluesIF::RETURN_OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "HousekeepingManager::generateHousekeepingPacket: " - << "Could not get free element from IPC store." << std::endl; -#endif - return result; - } + // Generate set packet which can be serialized. + HousekeepingSetPacket setPacket(sid, + reportingEnabled, valid, collectionInterval, dataSet); + size_t expectedSize = setPacket.getSerializedSize(); + uint8_t* storePtr = nullptr; + store_address_t storeId; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + expectedSize,&storePtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, + "Could not get free element from IPC store."); + return result; + } - // Serialize set packet into store. - size_t size = 0; - result = setPacket.serialize(&storePtr, &size, expectedSize, - SerializeIF::Endianness::BIG); - if(expectedSize != size) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "HousekeepingManager::generateSetStructurePacket: " - << "Expected size is not equal to serialized size" << std::endl; -#endif - } + // Serialize set packet into store. + size_t size = 0; + result = setPacket.serialize(&storePtr, &size, expectedSize, + SerializeIF::Endianness::BIG); + if(expectedSize != size) { + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "generateSetStructurePacket", HasReturnvaluesIF::RETURN_FAILED, + "Expected size is not equal to serialized size"); + } - // Send structure reporting reply. - CommandMessage reply; - if(isDiagnostics) { - HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, - sid, storeId); - } - else { - HousekeepingMessage::setHkStuctureReportReply(&reply, - sid, storeId); - } + // Send structure reporting reply. + CommandMessage reply; + if(isDiagnostics) { + HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, + sid, storeId); + } + else { + HousekeepingMessage::setHkStuctureReportReply(&reply, + sid, storeId); + } - hkQueue->reply(&reply); - return result; + hkQueue->reply(&reply); + return result; +} + +void LocalDataPoolManager::clearReceiversList() { + // clear the vector completely and releases allocated memory. + HkReceivers().swap(hkReceiversMap); +} + +MutexIF* LocalDataPoolManager::getLocalPoolMutex() { + return this->mutex; +} + +object_id_t LocalDataPoolManager::getCreatorObjectId() const { + return owner->getObjectId(); + //return owner->getObjectId(); +} + +void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType, + const char* functionName, ReturnValue_t error, const char* errorPrint) { + if(errorPrint == nullptr) { + if(error == DATASET_NOT_FOUND) { + errorPrint = "Dataset not found"; + } + else if(error == POOLOBJECT_NOT_FOUND) { + errorPrint = "Pool Object not found"; + } + else if(error == HasReturnvaluesIF::RETURN_FAILED) { + if(outputType == sif::OutputTypes::OUT_WARNING) { + errorPrint = "Generic Warning"; + } + else { + errorPrint = "Generic error"; + } + } + else if(error == QUEUE_OR_DESTINATION_INVALID) { + errorPrint = "Queue or destination not set"; + } + else if(error == localpool::POOL_ENTRY_TYPE_CONFLICT) { + errorPrint = "Pool entry type conflict"; + } + else if(error == localpool::POOL_ENTRY_NOT_FOUND) { + errorPrint = "Pool entry not found"; + } + else { + errorPrint = "Unknown error"; + } + } + + if(outputType == sif::OutputTypes::OUT_WARNING) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "LocalDataPoolManager::" << functionName + << ": Object ID " << std::setw(8) << std::setfill('0') + << std::hex << owner->getObjectId() << " | " << errorPrint + << std::dec << std::setfill(' ') << std::endl; +#else + sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", + owner->getObjectId(), errorPrint); +#endif + } + else if(outputType == sif::OutputTypes::OUT_ERROR) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "LocalDataPoolManager::" << functionName + << ": Object ID " << std::setw(8) << std::setfill('0') + << std::hex << owner->getObjectId() << " | " << errorPrint + << std::dec << std::setfill(' ') << std::endl; +#else + sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", + owner->getObjectId(), errorPrint); +#endif + } +} + +LocalDataPoolManager* LocalDataPoolManager::getHkManagerHandle() { + return this; } diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h index 0e98b90c..580ac8b9 100644 --- a/datapoollocal/LocalDataPoolManager.h +++ b/datapoollocal/LocalDataPoolManager.h @@ -1,8 +1,10 @@ #ifndef FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ #define FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ -#include "HasLocalDataPoolIF.h" +#include "ProvidesDataPoolSubscriptionIF.h" +#include "AccessLocalPoolF.h" +#include "../serviceinterface/ServiceInterface.h" #include "../housekeeping/HousekeepingPacketDownlink.h" #include "../housekeeping/HousekeepingMessage.h" #include "../housekeeping/PeriodicHousekeepingHelper.h" @@ -15,6 +17,7 @@ #include "../ipc/MutexHelper.h" #include +#include namespace Factory { void setStaticFrameworkObjectIds(); @@ -22,6 +25,8 @@ void setStaticFrameworkObjectIds(); class LocalPoolDataSetBase; class HousekeepingPacketUpdate; +class HasLocalDataPoolIF; +class LocalDataPool; /** * @brief This class is the managing instance for the local data pool. @@ -47,19 +52,23 @@ class HousekeepingPacketUpdate; * Each pool entry has a valid state too. * @author R. Mueller */ -class LocalDataPoolManager { - template friend class LocalPoolVariable; - template friend class LocalPoolVector; - friend class LocalPoolDataSetBase; +class LocalDataPoolManager: public ProvidesDataPoolSubscriptionIF, + public AccessPoolManagerIF { friend void (Factory::setStaticFrameworkObjectIds)(); + //! Some classes using the pool manager directly need to access class internals of the + //! manager. The attorney provides granular control of access to these internals. + friend class LocalDpManagerAttorney; public: static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER; - static constexpr ReturnValue_t QUEUE_OR_DESTINATION_NOT_SET = MAKE_RETURN_CODE(0x0); + static constexpr ReturnValue_t QUEUE_OR_DESTINATION_INVALID = MAKE_RETURN_CODE(0); + + static constexpr ReturnValue_t WRONG_HK_PACKET_TYPE = MAKE_RETURN_CODE(1); + static constexpr ReturnValue_t REPORTING_STATUS_UNCHANGED = MAKE_RETURN_CODE(2); + static constexpr ReturnValue_t PERIODIC_HELPER_INVALID = MAKE_RETURN_CODE(3); + static constexpr ReturnValue_t POOLOBJECT_NOT_FOUND = MAKE_RETURN_CODE(4); + static constexpr ReturnValue_t DATASET_NOT_FOUND = MAKE_RETURN_CODE(5); - static constexpr ReturnValue_t WRONG_HK_PACKET_TYPE = MAKE_RETURN_CODE(0x01); - static constexpr ReturnValue_t REPORTING_STATUS_UNCHANGED = MAKE_RETURN_CODE(0x02); - static constexpr ReturnValue_t PERIODIC_HELPER_INVALID = MAKE_RETURN_CODE(0x03); /** * This constructor is used by a class which wants to implement @@ -116,7 +125,7 @@ public: */ ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting, float collectionInterval, bool isDiagnostics, - object_id_t packetDestination = defaultHkDestination); + object_id_t packetDestination = defaultHkDestination) override; /** * @brief Subscribe for the generation of packets if the dataset @@ -130,7 +139,7 @@ public: */ ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled, bool isDiagnostics, - object_id_t packetDestination = defaultHkDestination); + object_id_t packetDestination = defaultHkDestination) override; /** * @brief Subscribe for a notification message which will be sent @@ -149,7 +158,7 @@ public: ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId, object_id_t destinationObject, MessageQueueId_t targetQueueId, - bool generateSnapshot); + bool generateSnapshot) override; /** * @brief Subscribe for an notification message which will be sent if a @@ -168,7 +177,9 @@ public: ReturnValue_t subscribeForVariableUpdateMessages(const lp_id_t localPoolId, object_id_t destinationObject, MessageQueueId_t targetQueueId, - bool generateSnapshot); + bool generateSnapshot) override; + + MutexIF* getLocalPoolMutex() override; /** * Non-Diagnostics packets usually have a lower minimum sampling frequency @@ -247,8 +258,18 @@ public: LocalDataPoolManager(const LocalDataPoolManager &) = delete; LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete; + /** + * This function can be used to clear the receivers list. This is + * intended for test functions and not for regular operations, because + * the insertion operations allocate dynamically. + */ + void clearReceiversList(); + + object_id_t getCreatorObjectId() const; + + virtual LocalDataPoolManager* getHkManagerHandle() override; private: - LocalDataPool localPoolMap; + localpool::DataPool localPoolMap; //! Every housekeeping data manager has a mutex to protect access //! to it's data pool. MutexIF* mutex = nullptr; @@ -367,6 +388,11 @@ private: ReturnValue_t& status); ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket, store_address_t& storeId); + + void printWarningOrError(sif::OutputTypes outputType, + const char* functionName, + ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED, + const char* errorPrint = nullptr); }; @@ -375,20 +401,16 @@ ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, PoolEntry **poolEntry) { auto poolIter = localPoolMap.find(localPoolId); if (poolIter == localPoolMap.end()) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "HousekeepingManager::fechPoolEntry: Pool entry " - "not found." << std::endl; -#endif - return HasLocalDataPoolIF::POOL_ENTRY_NOT_FOUND; + printWarningOrError(sif::OutputTypes::OUT_ERROR, "fetchPoolEntry", + localpool::POOL_ENTRY_NOT_FOUND); + return localpool::POOL_ENTRY_NOT_FOUND; } *poolEntry = dynamic_cast< PoolEntry* >(poolIter->second); if(*poolEntry == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "HousekeepingManager::fetchPoolEntry:" - " Pool entry not found." << std::endl; -#endif - return HasLocalDataPoolIF::POOL_ENTRY_TYPE_CONFLICT; + printWarningOrError(sif::OutputTypes::OUT_ERROR, "fetchPoolEntry", + localpool::POOL_ENTRY_TYPE_CONFLICT); + return localpool::POOL_ENTRY_TYPE_CONFLICT; } return HasReturnvaluesIF::RETURN_OK; } diff --git a/datapoollocal/LocalPoolDataSetBase.cpp b/datapoollocal/LocalPoolDataSetBase.cpp index dbe34dfd..5343a9c9 100644 --- a/datapoollocal/LocalPoolDataSetBase.cpp +++ b/datapoollocal/LocalPoolDataSetBase.cpp @@ -1,4 +1,8 @@ #include "LocalPoolDataSetBase.h" +#include "HasLocalDataPoolIF.h" +#include "internal/HasLocalDpIFUserAttorney.h" + +#include "../serviceinterface/ServiceInterface.h" #include "../datapoollocal/LocalDataPoolManager.h" #include "../housekeeping/PeriodicHousekeepingHelper.h" #include "../serialize/SerializeAdapter.h" @@ -15,15 +19,22 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " << "invalid!" << std::endl; -#endif +#else + sif::printError("LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " + "invalid!\n\r"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ return; } - hkManager = hkOwner->getHkManagerHandle(); + AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); + + if(poolManager != nullptr) { + poolManager = accessor->getHkManagerHandle(); + mutexIfSingleDataCreator = accessor->getLocalPoolMutex(); + } + this->sid.objectId = hkOwner->getObjectId(); this->sid.ownerSetId = setId; - mutex = MutexFactory::instance()->createMutex(); - // Data creators get a periodic helper for periodic HK data generation. if(periodicHandling) { periodicHelper = new PeriodicHousekeepingHelper(this); @@ -34,23 +45,34 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, const size_t maxNumberOfVariables): PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { - HasLocalDataPoolIF* hkOwner = objectManager->get( + AccessPoolManagerIF* hkOwner = objectManager->get( sid.objectId); if(hkOwner != nullptr) { - hkManager = hkOwner->getHkManagerHandle(); + mutexIfSingleDataCreator = hkOwner->getLocalPoolMutex(); } - this->sid = sid; - mutex = MutexFactory::instance()->createMutex(); + this->sid = sid; } +LocalPoolDataSetBase::LocalPoolDataSetBase( + PoolVariableIF **registeredVariablesArray, + const size_t maxNumberOfVariables, bool protectEveryReadCommitCall): + PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { + this->setReadCommitProtectionBehaviour(protectEveryReadCommitCall); +} + + LocalPoolDataSetBase::~LocalPoolDataSetBase() { + if(periodicHelper != nullptr) { + delete periodicHelper; + } } -ReturnValue_t LocalPoolDataSetBase::lockDataPool(uint32_t timeoutMs) { - if(hkManager != nullptr) { - MutexIF* mutex = hkManager->getMutexHandle(); - return mutex->lockMutex(MutexIF::TimeoutType::WAITING, timeoutMs); +ReturnValue_t LocalPoolDataSetBase::lockDataPool( + MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + if(mutexIfSingleDataCreator != nullptr) { + return mutexIfSingleDataCreator->lockMutex(timeoutType, timeoutMs); } return HasReturnvaluesIF::RETURN_OK; } @@ -128,9 +150,8 @@ ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer( } ReturnValue_t LocalPoolDataSetBase::unlockDataPool() { - if(hkManager != nullptr) { - MutexIF* mutex = hkManager->getMutexHandle(); - return mutex->unlockMutex(); + if(mutexIfSingleDataCreator != nullptr) { + return mutexIfSingleDataCreator->unlockMutex(); } return HasReturnvaluesIF::RETURN_OK; } @@ -150,9 +171,12 @@ ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer, size, maxSize, streamEndianness); if(result != HasReturnvaluesIF::RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalDataSet::serializeLocalPoolIds: Serialization" - " error!" << std::endl; -#endif + sif::warning << "LocalPoolDataSetBase::serializeLocalPoolIds: " + << "Serialization error!" << std::endl; +#else + sif::printWarning("LocalPoolDataSetBase::serializeLocalPoolIds: " + "Serialization error!\n\r"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ return result; } } @@ -211,8 +235,11 @@ ReturnValue_t LocalPoolDataSetBase::serialize(uint8_t **buffer, size_t *size, void LocalPoolDataSetBase::bitSetter(uint8_t* byte, uint8_t position) const { if(position > 7) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "Pool Raw Access: Bit setting invalid position" + sif::warning << "LocalPoolDataSetBase::bitSetter: Invalid position!" << std::endl; +#else + sif::printWarning("LocalPoolDataSetBase::bitSetter: " + "Invalid position!\n\r"); #endif return; } @@ -244,14 +271,10 @@ void LocalPoolDataSetBase::initializePeriodicHelper( } void LocalPoolDataSetBase::setChanged(bool changed) { - // TODO: Make this configurable? - MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); this->changed = changed; } bool LocalPoolDataSetBase::hasChanged() const { - // TODO: Make this configurable? - MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); return changed; } @@ -273,12 +296,10 @@ bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte, } bool LocalPoolDataSetBase::isValid() const { - MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 5); return this->valid; } void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) { - MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 5); if(setEntriesRecursively) { for(size_t idx = 0; idx < this->getFillCount(); idx++) { registeredVariables[idx] -> setValid(valid); @@ -287,8 +308,9 @@ void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) { this->valid = valid; } -void LocalPoolDataSetBase::setReadCommitProtectionBehaviour( - bool protectEveryReadCommit, uint32_t mutexTimeout) { - PoolDataSetBase::setReadCommitProtectionBehaviour(protectEveryReadCommit, - mutexTimeout); +object_id_t LocalPoolDataSetBase::getCreatorObjectId() { + if(poolManager != nullptr) { + return poolManager->getCreatorObjectId(); + } + return objects::NO_OBJECT; } diff --git a/datapoollocal/LocalPoolDataSetBase.h b/datapoollocal/LocalPoolDataSetBase.h index d9b6a221..5f17eeb6 100644 --- a/datapoollocal/LocalPoolDataSetBase.h +++ b/datapoollocal/LocalPoolDataSetBase.h @@ -1,16 +1,16 @@ #ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ #define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ -#include "HasLocalDataPoolIF.h" #include "MarkChangedIF.h" +#include "localPoolDefinitions.h" #include "../datapool/DataSetIF.h" #include "../datapool/PoolDataSetBase.h" -#include "../serialize/SerializeIF.h" #include class LocalDataPoolManager; +class HasLocalDataPoolIF; class PeriodicHousekeepingHelper; /** @@ -43,7 +43,7 @@ class PeriodicHousekeepingHelper; */ class LocalPoolDataSetBase: public PoolDataSetBase, public MarkChangedIF { - friend class LocalDataPoolManager; + friend class LocalPoolDataSetAttorney; friend class PeriodicHousekeepingHelper; public: /** @@ -57,8 +57,11 @@ public: const size_t maxNumberOfVariables, bool periodicHandling = true); /** - * @brief Constructor for users of local pool data. + * @brief Constructor for users of the local pool data, which need + * to access data created by one (!) HK manager. * @details + * Unlike the first constructor, no component for periodic handling + * will be initiated. * @param sid Unique identifier of dataset consisting of object ID and * set ID. * @param registeredVariablesArray @@ -67,6 +70,28 @@ public: LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, const size_t maxNumberOfVariables); + /** + * @brief Simple constructor, if the dataset is not the owner by + * a class with a HK manager. + * @details + * This constructor won't create components required for periodic handling + * and it also won't try to deduce the HK manager because no SID is + * supplied. This function should therefore be called by classes which need + * to access pool variables from different creators. + * + * If the class is intended to access pool variables from different + * creators, the third argument should be set to true. The mutex + * properties can be set with #setReadCommitProtectionBehaviour . + * @param registeredVariablesArray + * @param maxNumberOfVariables + * @param protectEveryReadCommitCall If the pool variables are created by + * multiple creators, this flag can be set to protect all read and + * commit calls separately. + */ + LocalPoolDataSetBase(PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables, + bool protectEveryReadCommitCall = true); + /** * @brief The destructor automatically manages writing the valid * information of variables. @@ -77,16 +102,6 @@ public: */ ~LocalPoolDataSetBase(); - /** - * If the data is pulled from different local data pools, every read and - * commit call should be mutex protected for thread safety. - * This can be specified with the second parameter. - * @param dataCreator - * @param protectEveryReadCommit - */ - void setReadCommitProtectionBehaviour(bool protectEveryReadCommit, - uint32_t mutexTimeout = 20); - void setValidityBufferGeneration(bool withValidityBuffer); sid_t getSid() const; @@ -136,10 +151,11 @@ public: void setChanged(bool changed) override; bool hasChanged() const override; + object_id_t getCreatorObjectId(); protected: sid_t sid; - uint32_t mutexTimeout = 20; - MutexIF* mutex = nullptr; + //! This mutex is used if the data is created by one object only. + MutexIF* mutexIfSingleDataCreator = nullptr; bool diagnostic = false; void setDiagnostic(bool diagnostics); @@ -183,7 +199,9 @@ protected: * @details * It makes use of the lockDataPool method offered by the DataPool class. */ - ReturnValue_t lockDataPool(uint32_t timeoutMs) override; + ReturnValue_t lockDataPool(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) override; + /** * @brief This is a small helper function to facilitate * unlocking the global data pool @@ -192,8 +210,6 @@ protected: */ ReturnValue_t unlockDataPool() override; - LocalDataPoolManager* hkManager = nullptr; - /** * Set n-th bit of a byte, with n being the position from 0 * (most significant bit) to 7 (least significant bit) @@ -202,6 +218,7 @@ protected: bool bitGetter(const uint8_t* byte, uint8_t position) const; PeriodicHousekeepingHelper* periodicHelper = nullptr; + LocalDataPoolManager* poolManager = nullptr; }; diff --git a/datapoollocal/LocalPoolObjectBase.cpp b/datapoollocal/LocalPoolObjectBase.cpp index 4b57dede..bd1bfa0f 100644 --- a/datapoollocal/LocalPoolObjectBase.cpp +++ b/datapoollocal/LocalPoolObjectBase.cpp @@ -1,81 +1,128 @@ +#include "LocalDataPoolManager.h" #include "LocalPoolObjectBase.h" +#include "internal/HasLocalDpIFUserAttorney.h" +#include "HasLocalDataPoolIF.h" -LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, - HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, - pool_rwm_t setReadWriteMode): localPoolId(poolId), - readWriteMode(setReadWriteMode) { - if(poolId == PoolVariableIF::NO_PARAMETER) { +#include "../objectmanager/ObjectManagerIF.h" + +LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, + DataSetIF* dataSet, pool_rwm_t setReadWriteMode): + localPoolId(poolId), readWriteMode(setReadWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " - << "which is the NO_PARAMETER value!" << std::endl; + sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " + << "which is the NO_PARAMETER value!" << std::endl; #endif - } - if(hkOwner == nullptr) { + } + if(hkOwner == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalPoolVar::LocalPoolVar: The supplied pool " - << "owner is a invalid!" << std::endl; + sif::error << "LocalPoolVar::LocalPoolVar: The supplied pool " + << "owner is a invalid!" << std::endl; #endif - return; - } - hkManager = hkOwner->getHkManagerHandle(); - if (dataSet != nullptr) { - dataSet->registerVariable(this); - } + return; + } + AccessPoolManagerIF* poolManAccessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); + hkManager = poolManAccessor->getHkManagerHandle(); + + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } } -LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, - DataSetIF *dataSet, pool_rwm_t setReadWriteMode): localPoolId(poolId), - readWriteMode(setReadWriteMode) { - if(poolId == PoolVariableIF::NO_PARAMETER) { +LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, DataSetIF *dataSet, + pool_rwm_t setReadWriteMode): + localPoolId(poolId), readWriteMode(setReadWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " - << "which is the NO_PARAMETER value!" << std::endl; + sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " + << "which is the NO_PARAMETER value!" << std::endl; #endif - } - HasLocalDataPoolIF* hkOwner = - objectManager->get(poolOwner); - if(hkOwner == nullptr) { + } + HasLocalDataPoolIF* hkOwner = objectManager->get(poolOwner); + if(hkOwner == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalPoolVariable: The supplied pool owner did not " - << "implement the correct interface" - << " HasLocalDataPoolIF!" << std::endl; + sif::error << "LocalPoolVariable: The supplied pool owner did not " + << "implement the correct interface" + << " HasLocalDataPoolIF!" << std::endl; #endif - return; - } - hkManager = hkOwner->getHkManagerHandle(); - if(dataSet != nullptr) { - dataSet->registerVariable(this); - } + return; + } + //hkManager = hkOwner->getHkManagerHandle(); + AccessPoolManagerIF* poolManAccessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); + //hkManager = HasLocalDpIFUserAttorney::getHkManagerHandle(hkOwner); + hkManager = poolManAccessor->getHkManagerHandle(); + if(dataSet != nullptr) { + dataSet->registerVariable(this); + } } pool_rwm_t LocalPoolObjectBase::getReadWriteMode() const { - return readWriteMode; + return readWriteMode; } bool LocalPoolObjectBase::isValid() const { - return valid; + return valid; } void LocalPoolObjectBase::setValid(bool valid) { - this->valid = valid; + this->valid = valid; } lp_id_t LocalPoolObjectBase::getDataPoolId() const { - return localPoolId; + return localPoolId; } void LocalPoolObjectBase::setDataPoolId(lp_id_t poolId) { - this->localPoolId = poolId; + this->localPoolId = poolId; } void LocalPoolObjectBase::setChanged(bool changed) { - this->changed = changed; + this->changed = changed; } bool LocalPoolObjectBase::hasChanged() const { - return changed; + return changed; } void LocalPoolObjectBase::setReadWriteMode(pool_rwm_t newReadWriteMode) { this->readWriteMode = newReadWriteMode; } + +void LocalPoolObjectBase::reportReadCommitError(const char* variableType, + ReturnValue_t error, bool read, object_id_t objectId, lp_id_t lpId) { +#if FSFW_DISABLE_PRINTOUT == 0 + const char* type = nullptr; + if(read) { + type = "read"; + } + else { + type = "commit"; + } + + const char* errMsg = nullptr; + if(error == localpool::POOL_ENTRY_NOT_FOUND) { + errMsg = "Pool entry not found"; + } + else if(error == localpool::POOL_ENTRY_TYPE_CONFLICT) { + errMsg = "Pool entry type conflict"; + } + else if(error == PoolVariableIF::INVALID_READ_WRITE_MODE) { + errMsg = "Pool variable wrong read-write mode"; + } + else if(error == PoolVariableIF::INVALID_POOL_ENTRY) { + errMsg = "Pool entry invalid"; + } + else { + errMsg = "Unknown error code"; + } + +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << variableType << ": " << type << " call | " << errMsg << " | Owner: 0x" + << std::hex << std::setw(8) << std::setfill('0') << objectId << std::dec + << " LPID: " << lpId << std::endl; +#else + sif::printWarning("%s: %s call | %s | Owner: 0x%08x LPID: %lu\n", + variableType, type, errMsg, objectId, lpId); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ +#endif /* FSFW_DISABLE_PRINTOUT == 0 */ +} diff --git a/datapoollocal/LocalPoolObjectBase.h b/datapoollocal/LocalPoolObjectBase.h index 7165fc24..2dddc246 100644 --- a/datapoollocal/LocalPoolObjectBase.h +++ b/datapoollocal/LocalPoolObjectBase.h @@ -1,10 +1,15 @@ #ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ #define FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ +#include #include "MarkChangedIF.h" -#include "../datapoollocal/LocalDataPoolManager.h" +#include "../objectmanager/SystemObjectIF.h" #include "../datapool/PoolVariableIF.h" +#include "../returnvalues/HasReturnvaluesIF.h" +class LocalDataPoolManager; +class DataSetIF; +class HasLocalDataPoolIF; class LocalPoolObjectBase: public PoolVariableIF, public HasReturnvaluesIF, @@ -54,8 +59,10 @@ protected: ReadWriteMode_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; //! @brief Pointer to the class which manages the HK pool. - LocalDataPoolManager* hkManager; + LocalDataPoolManager* hkManager = nullptr; + void reportReadCommitError(const char* variableType, + ReturnValue_t error, bool read, object_id_t objectId, lp_id_t lpId); }; diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h index 84be54b1..859c8f08 100644 --- a/datapoollocal/LocalPoolVariable.h +++ b/datapoollocal/LocalPoolVariable.h @@ -4,9 +4,12 @@ #include "LocalPoolObjectBase.h" #include "HasLocalDataPoolIF.h" #include "LocalDataPoolManager.h" +#include "AccessLocalPoolF.h" +#include "internal/LocalDpManagerAttorney.h" #include "../datapool/PoolVariableIF.h" #include "../datapool/DataSetIF.h" +#include "../serviceinterface/ServiceInterface.h" #include "../objectmanager/ObjectManagerIF.h" #include "../serialize/SerializeAdapter.h" @@ -105,7 +108,9 @@ public: * at once to avoid the overhead of unnecessary lock und unlock operations. * */ - ReturnValue_t read(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; + ReturnValue_t read(MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; /** * @brief The commit call copies the array values back to the data pool. * @details @@ -115,8 +120,21 @@ public: * 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; + ReturnValue_t commit(MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; + /** + * @brief This commit function can be used to set the pool variable valid + * as well. + * @param setValid + * @param timeoutType + * @param timeoutMs + * @return + */ + ReturnValue_t commit(bool setValid, MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20); LocalPoolVariable &operator=(const T& newValue); LocalPoolVariable &operator=(const LocalPoolVariable& newPoolVariable); @@ -163,8 +181,6 @@ protected: friend std::ostream& operator<< (std::ostream &out, const LocalPoolVariable &var); #endif - -private: }; #include "LocalPoolVariable.tpp" diff --git a/datapoollocal/LocalPoolVariable.tpp b/datapoollocal/LocalPoolVariable.tpp index cd5117c8..6fd34171 100644 --- a/datapoollocal/LocalPoolVariable.tpp +++ b/datapoollocal/LocalPoolVariable.tpp @@ -24,73 +24,91 @@ inline LocalPoolVariable::LocalPoolVariable(gp_id_t globalPoolId, template -inline ReturnValue_t LocalPoolVariable::read(dur_millis_t lockTimeout) { - MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, - lockTimeout); +inline ReturnValue_t LocalPoolVariable::read( + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); return readWithoutLock(); } template inline ReturnValue_t LocalPoolVariable::readWithoutLock() { if(readWriteMode == pool_rwm_t::VAR_WRITE) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "LocalPoolVar: Invalid read write " - "mode for read() call." << std::endl; -#endif + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", + PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId, + localPoolId); return PoolVariableIF::INVALID_READ_WRITE_MODE; } PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); - if(result != RETURN_OK or poolEntry == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "PoolVector: Read of local pool variable of object " - << std::hex << std::setw(8) << std::setfill('0') - << hkManager->getOwner() << " and lp ID " << localPoolId - << std::dec << " failed." << std::setfill(' ') << std::endl; -#endif + ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, + &poolEntry); + //ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + if(result != RETURN_OK) { + object_id_t ownerObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVariable", result, + false, ownerObjectId, localPoolId); return result; } - this->value = *(poolEntry->address); - this->valid = poolEntry->valid; + + // Actually this should never happen.. +// if(poolEntry->address == nullptr) { +// result = PoolVariableIF::INVALID_POOL_ENTRY; +// object_id_t ownerObjectId = hkManager->getOwner()->getObjectId(); +// reportReadCommitError("LocalPoolVariable", result, +// false, ownerObjectId, localPoolId); +// return result; +// } + + this->value = *(poolEntry->getDataPtr()); + this->valid = poolEntry->getValid(); return RETURN_OK; } template -inline ReturnValue_t LocalPoolVariable::commit(dur_millis_t lockTimeout) { - MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, - lockTimeout); +inline ReturnValue_t LocalPoolVariable::commit(bool setValid, + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + this->setValid(setValid); + return commit(timeoutType, timeoutMs); +} + +template +inline ReturnValue_t LocalPoolVariable::commit( + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); return commitWithoutLock(); } template inline ReturnValue_t LocalPoolVariable::commitWithoutLock() { if(readWriteMode == pool_rwm_t::VAR_READ) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "LocalPoolVariable: Invalid read write " - "mode for commit() call." << std::endl; -#endif + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", + PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId, + localPoolId); return PoolVariableIF::INVALID_READ_WRITE_MODE; } + PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + //ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, + &poolEntry); if(result != RETURN_OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - 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; -#endif + object_id_t ownerObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVariable", result, + false, ownerObjectId, localPoolId); return result; } - *(poolEntry->address) = this->value; - poolEntry->valid = this->valid; + + *(poolEntry->getDataPtr()) = this->value; + poolEntry->setValid(this->valid); return RETURN_OK; } template -inline ReturnValue_t LocalPoolVariable::serialize(uint8_t** buffer, size_t* size, - const size_t max_size, SerializeIF::Endianness streamEndianness) const { +inline ReturnValue_t LocalPoolVariable::serialize(uint8_t** buffer, + size_t* size, const size_t max_size, + SerializeIF::Endianness streamEndianness) const { return SerializeAdapter::serialize(&value, buffer, size ,max_size, streamEndianness); } @@ -121,7 +139,8 @@ inline LocalPoolVariable::operator T() const { } template -inline LocalPoolVariable & LocalPoolVariable::operator=(const T& newValue) { +inline LocalPoolVariable & LocalPoolVariable::operator=( + const T& newValue) { value = newValue; return *this; } @@ -134,7 +153,8 @@ inline LocalPoolVariable& LocalPoolVariable::operator =( } template -inline bool LocalPoolVariable::operator ==(const LocalPoolVariable &other) const { +inline bool LocalPoolVariable::operator ==( + const LocalPoolVariable &other) const { return this->value == other.value; } @@ -145,7 +165,8 @@ inline bool LocalPoolVariable::operator ==(const T &other) const { template -inline bool LocalPoolVariable::operator !=(const LocalPoolVariable &other) const { +inline bool LocalPoolVariable::operator !=( + const LocalPoolVariable &other) const { return not (*this == other); } @@ -156,7 +177,8 @@ inline bool LocalPoolVariable::operator !=(const T &other) const { template -inline bool LocalPoolVariable::operator <(const LocalPoolVariable &other) const { +inline bool LocalPoolVariable::operator <( + const LocalPoolVariable &other) const { return this->value < other.value; } @@ -167,7 +189,8 @@ inline bool LocalPoolVariable::operator <(const T &other) const { template -inline bool LocalPoolVariable::operator >(const LocalPoolVariable &other) const { +inline bool LocalPoolVariable::operator >( + const LocalPoolVariable &other) const { return not (*this < other); } diff --git a/datapoollocal/LocalPoolVector.h b/datapoollocal/LocalPoolVector.h index 58face3c..74255605 100644 --- a/datapoollocal/LocalPoolVector.h +++ b/datapoollocal/LocalPoolVector.h @@ -2,12 +2,14 @@ #define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ #include "LocalPoolObjectBase.h" +#include "internal/LocalDpManagerAttorney.h" + #include "../datapool/DataSetIF.h" #include "../datapool/PoolEntry.h" #include "../datapool/PoolVariableIF.h" #include "../datapoollocal/LocalDataPoolManager.h" #include "../serialize/SerializeAdapter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" /** @@ -100,8 +102,8 @@ public: return vectorSize; } - T& operator [](int i); - const T &operator [](int i) const; + T& operator [](size_t i); + const T &operator [](size_t i) const; virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize, @@ -123,7 +125,10 @@ public: * 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; + ReturnValue_t read(MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; + /** * @brief The commit call copies the array values back to the data pool. * @details @@ -133,7 +138,17 @@ public: * 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; + ReturnValue_t commit(MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20) override; + + /** + * @brief This commit call also sets the validity of the pool entry. + * @details + */ + ReturnValue_t commit(bool valid, MutexIF::TimeoutType timeoutType = + MutexIF::TimeoutType::WAITING, + uint32_t timeoutMs = 20); protected: /** @@ -157,12 +172,12 @@ protected: private: - +#if FSFW_CPP_OSTREAM_ENABLED == 1 // std::ostream is the type for object std::cout template friend std::ostream& operator<< (std::ostream &out, const LocalPoolVector &var); - +#endif }; diff --git a/datapoollocal/LocalPoolVector.tpp b/datapoollocal/LocalPoolVector.tpp index 5c3b0ce0..acffebee 100644 --- a/datapoollocal/LocalPoolVector.tpp +++ b/datapoollocal/LocalPoolVector.tpp @@ -24,98 +24,106 @@ inline LocalPoolVector::LocalPoolVector(gp_id_t globalPoolId, dataSet, setReadWriteMode) {} template -inline ReturnValue_t LocalPoolVector::read(uint32_t lockTimeout) { - MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, - lockTimeout); +inline ReturnValue_t LocalPoolVector::read( + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); return readWithoutLock(); } template inline ReturnValue_t LocalPoolVector::readWithoutLock() { if(readWriteMode == pool_rwm_t::VAR_WRITE) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "LocalPoolVar: Invalid read write " - "mode for read() call." << std::endl; -#endif + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", + PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId, + localPoolId); return PoolVariableIF::INVALID_READ_WRITE_MODE; } PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, + &poolEntry); memset(this->value, 0, vectorSize * sizeof(T)); if(result != RETURN_OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - 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; -#endif + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", result, true, targetObjectId, + localPoolId); return result; } - std::memcpy(this->value, poolEntry->address, poolEntry->getByteSize()); - this->valid = poolEntry->valid; + std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize()); + this->valid = poolEntry->getValid(); return RETURN_OK; } +template +inline ReturnValue_t LocalPoolVector::commit(bool valid, + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + this->setValid(valid); + return commit(timeoutType, timeoutMs); +} + template inline ReturnValue_t LocalPoolVector::commit( - uint32_t lockTimeout) { - MutexHelper(hkManager->getMutexHandle(), MutexIF::TimeoutType::WAITING, - lockTimeout); + MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { + MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); return commitWithoutLock(); } template inline ReturnValue_t LocalPoolVector::commitWithoutLock() { if(readWriteMode == pool_rwm_t::VAR_READ) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "LocalPoolVar: Invalid read write " - "mode for commit() call." << std::endl; -#endif + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", + PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId, + localPoolId); return PoolVariableIF::INVALID_READ_WRITE_MODE; } PoolEntry* poolEntry = nullptr; - ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry); + ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, + &poolEntry); if(result != RETURN_OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - 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; -#endif + object_id_t targetObjectId = hkManager->getCreatorObjectId(); + reportReadCommitError("LocalPoolVector", result, false, targetObjectId, + localPoolId); return result; } - std::memcpy(poolEntry->address, this->value, poolEntry->getByteSize()); - poolEntry->valid = this->valid; + std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize()); + poolEntry->setValid(this->valid); return RETURN_OK; } template -inline T& LocalPoolVector::operator [](int i) { - if(i <= vectorSize) { +inline T& LocalPoolVector::operator [](size_t i) { + if(i < vectorSize) { return value[i]; } // If this happens, I have to set some value. I consider this // a configuration error, but I wont exit here. #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalPoolVector: Invalid index. Setting or returning" + sif::warning << "LocalPoolVector: Invalid index. Setting or returning" " last value!" << std::endl; +#else + sif::printWarning("LocalPoolVector: Invalid index. Setting or returning" + " last value!\n"); #endif - return value[i]; + return value[vectorSize - 1]; } template -inline const T& LocalPoolVector::operator [](int i) const { - if(i <= vectorSize) { +inline const T& LocalPoolVector::operator [](size_t i) const { + if(i < vectorSize) { return value[i]; } // If this happens, I have to set some value. I consider this // a configuration error, but I wont exit here. #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "LocalPoolVector: Invalid index. Setting or returning" + sif::warning << "LocalPoolVector: Invalid index. Setting or returning" " last value!" << std::endl; +#else + sif::printWarning("LocalPoolVector: Invalid index. Setting or returning" + " last value!\n"); #endif - return value[i]; + return value[vectorSize - 1]; } template @@ -153,6 +161,7 @@ inline ReturnValue_t LocalPoolVector::deSerialize( return result; } +#if FSFW_CPP_OSTREAM_ENABLED == 1 template inline std::ostream& operator<< (std::ostream &out, const LocalPoolVector &var) { @@ -166,5 +175,6 @@ inline std::ostream& operator<< (std::ostream &out, out << "]"; return out; } +#endif #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ */ diff --git a/datapoollocal/PoolReadHelper.h b/datapoollocal/PoolReadHelper.h index 0510dbb5..6a816c1f 100644 --- a/datapoollocal/PoolReadHelper.h +++ b/datapoollocal/PoolReadHelper.h @@ -1,7 +1,8 @@ #ifndef FSFW_DATAPOOLLOCAL_POOLREADHELPER_H_ #define FSFW_DATAPOOLLOCAL_POOLREADHELPER_H_ -#include +#include "LocalPoolDataSetBase.h" +#include "../serviceinterface/ServiceInterface.h" #include /** @@ -9,13 +10,17 @@ */ class PoolReadHelper { public: - PoolReadHelper(ReadCommitIF* readObject, uint32_t mutexTimeout = 20): + PoolReadHelper(ReadCommitIF* readObject, + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, + uint32_t mutexTimeout = 20): readObject(readObject), mutexTimeout(mutexTimeout) { if(readObject != nullptr) { - readResult = readObject->read(mutexTimeout); -#if FSFW_PRINT_VERBOSITY_LEVEL == 1 + readResult = readObject->read(timeoutType, mutexTimeout); +#if FSFW_VERBOSE_LEVEL == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PoolReadHelper: Read failed!" << std::endl; +#else + sif::printError("PoolReadHelper: Read failed!\n"); #endif /* FSFW_PRINT_VERBOSITY_LEVEL == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ } @@ -27,7 +32,7 @@ public: ~PoolReadHelper() { if(readObject != nullptr) { - readObject->commit(mutexTimeout); + readObject->commit(timeoutType, mutexTimeout); } } @@ -35,6 +40,7 @@ public: private: ReadCommitIF* readObject = nullptr; ReturnValue_t readResult = HasReturnvaluesIF::RETURN_OK; + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; uint32_t mutexTimeout = 20; }; diff --git a/datapoollocal/ProvidesDataPoolSubscriptionIF.h b/datapoollocal/ProvidesDataPoolSubscriptionIF.h new file mode 100644 index 00000000..e6d6257e --- /dev/null +++ b/datapoollocal/ProvidesDataPoolSubscriptionIF.h @@ -0,0 +1,84 @@ +#ifndef FSFW_DATAPOOLLOCAL_PROVIDESDATAPOOLSUBSCRIPTION_H_ +#define FSFW_DATAPOOLLOCAL_PROVIDESDATAPOOLSUBSCRIPTION_H_ + +#include +#include +#include + + + +class ProvidesDataPoolSubscriptionIF { +public: + virtual ~ProvidesDataPoolSubscriptionIF(){}; + + /** + * @brief Subscribe for the generation of periodic packets. + * @details + * This subscription mechanism will generally be used by the data creator + * to generate housekeeping packets which are downlinked directly. + * @return + */ + virtual ReturnValue_t subscribeForPeriodicPacket(sid_t sid, + bool enableReporting, + float collectionInterval, bool isDiagnostics, + object_id_t packetDestination) = 0; + + + /** + * @brief Subscribe for the generation of packets if the dataset + * is marked as changed. + * @details + * This subscription mechanism will generally be used by the data creator. + * @param sid + * @param isDiagnostics + * @param packetDestination + * @return + */ + virtual ReturnValue_t subscribeForUpdatePackets(sid_t sid, + bool reportingEnabled, + bool isDiagnostics, + object_id_t packetDestination) = 0; + + + /** + * @brief Subscribe for a notification message which will be sent + * if a dataset has changed. + * @details + * This subscription mechanism will generally be used internally by + * other software components. + * @param setId Set ID of the set to receive update messages from. + * @param destinationObject + * @param targetQueueId + * @param generateSnapshot If this is set to true, a copy of the current + * data with a timestamp will be generated and sent via message. + * Otherwise, only an notification message is sent. + * @return + */ + virtual ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId, + object_id_t destinationObject, + MessageQueueId_t targetQueueId, + bool generateSnapshot) = 0; + + /** + * @brief Subscribe for an notification message which will be sent if a + * pool variable has changed. + * @details + * This subscription mechanism will generally be used internally by + * other software components. + * @param localPoolId Pool ID of the pool variable + * @param destinationObject + * @param targetQueueId + * @param generateSnapshot If this is set to true, a copy of the current + * data with a timestamp will be generated and sent via message. + * Otherwise, only an notification message is sent. + * @return + */ + virtual ReturnValue_t subscribeForVariableUpdateMessages( + const lp_id_t localPoolId, + object_id_t destinationObject, + MessageQueueId_t targetQueueId, + bool generateSnapshot) = 0; + +}; + +#endif /* FSFW_DATAPOOLLOCAL_PROVIDESDATAPOOLSUBSCRIPTION_H_ */ diff --git a/datapoollocal/SharedLocalDataSet.h b/datapoollocal/SharedLocalDataSet.h index 2e5a76fa..713d435b 100644 --- a/datapoollocal/SharedLocalDataSet.h +++ b/datapoollocal/SharedLocalDataSet.h @@ -6,6 +6,13 @@ #include "../objectmanager/SystemObject.h" #include +/** + * This local dataset variation can be used if the dataset is used concurrently across + * multiple threads. It provides a lock in addition to all other functionalities provided + * by the LocalPoolDataSetBase class. + * + * TODO: override and protect read, commit and some other calls used by pool manager. + */ class SharedLocalDataSet: public SystemObject, public LocalPoolDataSetBase, public SharedDataSetIF { diff --git a/datapoollocal/internal/CMakeLists.txt b/datapoollocal/internal/CMakeLists.txt new file mode 100644 index 00000000..554f3b88 --- /dev/null +++ b/datapoollocal/internal/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${LIB_FSFW_NAME} + PRIVATE + HasLocalDpIFUserAttorney.cpp + HasLocalDpIFManagerAttorney.cpp +) diff --git a/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp b/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp new file mode 100644 index 00000000..bc07170f --- /dev/null +++ b/datapoollocal/internal/HasLocalDpIFManagerAttorney.cpp @@ -0,0 +1,18 @@ +#include "HasLocalDpIFManagerAttorney.h" +#include "../LocalPoolObjectBase.h" +#include "../LocalPoolDataSetBase.h" +#include "../HasLocalDataPoolIF.h" + +LocalPoolDataSetBase* HasLocalDpIFManagerAttorney::getDataSetHandle(HasLocalDataPoolIF* clientIF, + sid_t sid) { + return clientIF->getDataSetHandle(sid); +} + +LocalPoolObjectBase* HasLocalDpIFManagerAttorney::getPoolObjectHandle(HasLocalDataPoolIF* clientIF, + lp_id_t localPoolId) { + return clientIF->getPoolObjectHandle(localPoolId); +} + +object_id_t HasLocalDpIFManagerAttorney::getObjectId(HasLocalDataPoolIF* clientIF) { + return clientIF->getObjectId(); +} diff --git a/datapoollocal/internal/HasLocalDpIFManagerAttorney.h b/datapoollocal/internal/HasLocalDpIFManagerAttorney.h new file mode 100644 index 00000000..ef180b37 --- /dev/null +++ b/datapoollocal/internal/HasLocalDpIFManagerAttorney.h @@ -0,0 +1,22 @@ +#ifndef FSFW_DATAPOOLLOCAL_HASLOCALDPIFMANAGERATTORNEY_H_ +#define FSFW_DATAPOOLLOCAL_HASLOCALDPIFMANAGERATTORNEY_H_ + +#include "../localPoolDefinitions.h" + +class HasLocalDataPoolIF; +class LocalPoolDataSetBase; +class LocalPoolObjectBase; + +class HasLocalDpIFManagerAttorney { + + static LocalPoolDataSetBase* getDataSetHandle(HasLocalDataPoolIF* clientIF, sid_t sid); + + static LocalPoolObjectBase* getPoolObjectHandle(HasLocalDataPoolIF* clientIF, + lp_id_t localPoolId); + + static object_id_t getObjectId(HasLocalDataPoolIF* clientIF); + + friend class LocalDataPoolManager; +}; + +#endif /* FSFW_DATAPOOLLOCAL_HASLOCALDPIFMANAGERATTORNEY_H_ */ diff --git a/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp b/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp new file mode 100644 index 00000000..838204a7 --- /dev/null +++ b/datapoollocal/internal/HasLocalDpIFUserAttorney.cpp @@ -0,0 +1,7 @@ +#include "HasLocalDpIFUserAttorney.h" +#include "../AccessLocalPoolF.h" +#include "../HasLocalDataPoolIF.h" + +AccessPoolManagerIF* HasLocalDpIFUserAttorney::getAccessorHandle(HasLocalDataPoolIF *clientIF) { + return clientIF->getAccessorHandle(); +} diff --git a/datapoollocal/internal/HasLocalDpIFUserAttorney.h b/datapoollocal/internal/HasLocalDpIFUserAttorney.h new file mode 100644 index 00000000..a07c2d59 --- /dev/null +++ b/datapoollocal/internal/HasLocalDpIFUserAttorney.h @@ -0,0 +1,18 @@ +#ifndef FSFW_DATAPOOLLOCAL_HASLOCALDPIFUSERATTORNEY_H_ +#define FSFW_DATAPOOLLOCAL_HASLOCALDPIFUSERATTORNEY_H_ + +class HasLocalDataPoolIF; +class AccessPoolManagerIF; + +class HasLocalDpIFUserAttorney { +private: + + static AccessPoolManagerIF* getAccessorHandle(HasLocalDataPoolIF* clientIF); + + friend class LocalPoolObjectBase; + friend class LocalPoolDataSetBase; + +}; + + +#endif /* FSFW_DATAPOOLLOCAL_HASLOCALDPIFUSERATTORNEY_H_ */ diff --git a/datapoollocal/internal/LocalDpManagerAttorney.h b/datapoollocal/internal/LocalDpManagerAttorney.h new file mode 100644 index 00000000..1d72f607 --- /dev/null +++ b/datapoollocal/internal/LocalDpManagerAttorney.h @@ -0,0 +1,32 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALDPMANAGERATTORNEY_H_ +#define FSFW_DATAPOOLLOCAL_LOCALDPMANAGERATTORNEY_H_ + +#include + +/** + * @brief This is a helper class implements the Attorney-Client idiom for access to + * LocalDataPoolManager internals + * @details + * This helper class provides better control over which classes are allowed to access + * LocalDataPoolManager internals in a granular and encapsulated way when compared to + * other methods like direct friend declarations. It allows these classes to use + * an explicit subset of the pool manager private/protected functions. + * See: https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Friendship_and_the_Attorney-Client + */ +class LocalDpManagerAttorney { +private: + template static ReturnValue_t fetchPoolEntry(LocalDataPoolManager& manager, + lp_id_t localPoolId, PoolEntry **poolEntry) { + return manager.fetchPoolEntry(localPoolId, poolEntry); + } + + static MutexIF* getMutexHandle(LocalDataPoolManager& manager) { + return manager.getMutexHandle(); + } + + + template friend class LocalPoolVariable; + template friend class LocalPoolVector; +}; + +#endif /* FSFW_DATAPOOLLOCAL_LOCALDPMANAGERATTORNEY_H_ */ diff --git a/datapoollocal/internal/LocalPoolDataSetAttorney.h b/datapoollocal/internal/LocalPoolDataSetAttorney.h new file mode 100644 index 00000000..9804444a --- /dev/null +++ b/datapoollocal/internal/LocalPoolDataSetAttorney.h @@ -0,0 +1,39 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETATTORNEY_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETATTORNEY_H_ + +#include "../LocalPoolDataSetBase.h" + +class LocalPoolDataSetAttorney { +private: + static void setDiagnostic(LocalPoolDataSetBase& set, bool diagnostics) { + set.setDiagnostic(diagnostics); + } + + static bool isDiagnostics(LocalPoolDataSetBase& set) { + return set.isDiagnostics(); + } + + static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval, + uint32_t minimumPeriodicIntervalMs, + bool isDiagnostics, uint8_t nonDiagIntervalFactor = 5) { + set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs, isDiagnostics, + nonDiagIntervalFactor); + } + + static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) { + set.setReportingEnabled(enabled); + } + + static bool getReportingEnabled(LocalPoolDataSetBase& set) { + return set.getReportingEnabled(); + } + + static PeriodicHousekeepingHelper* getPeriodicHelper(LocalPoolDataSetBase& set) { + return set.periodicHelper; + } + + friend class LocalDataPoolManager; +}; + + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETATTORNEY_H_ */ diff --git a/datapoollocal/locPoolDefinitions.h b/datapoollocal/localPoolDefinitions.h similarity index 68% rename from datapoollocal/locPoolDefinitions.h rename to datapoollocal/localPoolDefinitions.h index 6e74d349..3ff1feed 100644 --- a/datapoollocal/locPoolDefinitions.h +++ b/datapoollocal/localPoolDefinitions.h @@ -1,10 +1,13 @@ -#ifndef FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ -#define FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLDEFINITIONS_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLDEFINITIONS_H_ -#include +#include "../datapool/PoolEntryIF.h" #include "../objectmanager/SystemObjectIF.h" #include "../objectmanager/frameworkObjects.h" +#include +#include + /** * @brief Type definition for local pool entries. */ @@ -12,10 +15,21 @@ using lp_id_t = uint32_t; namespace localpool { static constexpr uint32_t INVALID_LPID = -1; + +static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; + +static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x00); +static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x01); + +//! This is the core data structure of the local data pools. Users should insert all desired +//! pool variables, using the std::map interface. +using DataPool = std::map; +using DataPoolMapIter = DataPool::iterator; + } /** - * Used as a unique identifier for data sets. + * Used as a unique identifier for data sets. Consists of 4 byte object ID and 4 byte set ID. */ union sid_t { static constexpr uint64_t INVALID_SID = -1; @@ -57,7 +71,8 @@ union sid_t { }; /** - * Used as a global unique identifier for local pool variables. + * Used as a global unique identifier for local pool variables. Consists of 4 byte object ID + * and 4 byte local pool ID. */ union gp_id_t { static constexpr uint64_t INVALID_GPID = -1; @@ -90,4 +105,4 @@ union gp_id_t { } }; -#endif /* FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ */ +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLDEFINITIONS_H_ */ diff --git a/defaultcfg/fsfwconfig/FSFWConfig.h b/defaultcfg/fsfwconfig/FSFWConfig.h index 261e3d6d..ed86e6e1 100644 --- a/defaultcfg/fsfwconfig/FSFWConfig.h +++ b/defaultcfg/fsfwconfig/FSFWConfig.h @@ -9,18 +9,14 @@ //! the C stdio functions can be used alternatively #define FSFW_CPP_OSTREAM_ENABLED 1 -//! More FSFW related printouts. -//! Be careful, this also turns off most diagnostic prinouts! -#define FSFW_ENHANCED_PRINTOUT 0 +//! More FSFW related printouts depending on level. Useful for development. +#define FSFW_VERBOSE_LEVEL 1 //! Can be used to completely disable printouts, even the C stdio ones. -#if FSFW_CPP_OSTREAM_ENABLED == 0 && FSFW_ENHANCED_PRINTOUT == 0 +#if FSFW_CPP_OSTREAM_ENABLED == 0 && FSFW_VERBOSE_LEVEL == 0 #define FSFW_DISABLE_PRINTOUT 0 #endif -//! Can be used to enable additional debugging printouts for developing the FSFW -#define FSFW_PRINT_VERBOSITY_LEVEL 0 - //! Can be used to disable the ANSI color sequences for C stdio. #define FSFW_COLORED_OUTPUT 1 diff --git a/devicehandlers/DeviceHandlerBase.cpp b/devicehandlers/DeviceHandlerBase.cpp index 1af6932a..c4098525 100644 --- a/devicehandlers/DeviceHandlerBase.cpp +++ b/devicehandlers/DeviceHandlerBase.cpp @@ -2,7 +2,7 @@ #include "AcceptsDeviceResponsesIF.h" #include "DeviceTmReportingWrapper.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" #include "../objectmanager/ObjectManager.h" #include "../storagemanager/StorageManagerIF.h" #include "../thermal/ThermalComponentIF.h" @@ -13,9 +13,6 @@ #include "../subsystem/SubsystemBase.h" #include "../datapoollocal/LocalPoolVariable.h" -#include - - object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT; object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT; @@ -27,7 +24,7 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), deviceCommunicationId(deviceCommunication), comCookie(comCookie), healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), - actionHelper(this, nullptr), hkManager(this, nullptr), + actionHelper(this, nullptr), poolManager(this, nullptr), childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), switchOffWasReported(false), childTransitionDelay(5000), @@ -39,13 +36,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, cookieInfo.state = COOKIE_UNUSED; cookieInfo.pendingCommand = deviceCommandMap.end(); if (comCookie == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex - << std::setw(8) << std::setfill('0') << this->getObjectId() - << std::dec << ": Do not pass nullptr as a cookie, consider " - << std::setfill(' ') << "passing a dummy cookie instead!" - << std::endl; -#endif + printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", + HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie"); } if (this->fdirInstance == nullptr) { this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, @@ -115,7 +107,7 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) { doGetRead(); // This will be performed after datasets have been updated by the // custom device implementation. - hkManager.performHkOperation(); + poolManager.performHkOperation(); break; default: break; @@ -132,30 +124,24 @@ ReturnValue_t DeviceHandlerBase::initialize() { communicationInterface = objectManager->get( deviceCommunicationId); if (communicationInterface == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "DeviceHandlerBase::initialize: Communication interface " - "invalid." << std::endl; - sif::error << "Make sure it is set up properly and implements" - " DeviceCommunicationIF" << std::endl; -#endif + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + ObjectManagerIF::CHILD_INIT_FAILED, + "Passed communication IF invalid"); return ObjectManagerIF::CHILD_INIT_FAILED; } result = communicationInterface->initializeInterface(comCookie); if (result != RETURN_OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "DeviceHandlerBase::initialize: Initializing " - "communication interface failed!" << std::endl; -#endif + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + ObjectManagerIF::CHILD_INIT_FAILED, + "ComIF initialization failed"); return result; } IPCStore = objectManager->get(objects::IPC_STORE); if (IPCStore == nullptr) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "DeviceHandlerBase::initialize: IPC store not set up in " - "factory." << std::endl; -#endif + printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize", + ObjectManagerIF::CHILD_INIT_FAILED, "IPC Store not set up"); return ObjectManagerIF::CHILD_INIT_FAILED; } @@ -164,11 +150,15 @@ ReturnValue_t DeviceHandlerBase::initialize() { AcceptsDeviceResponsesIF>(rawDataReceiverId); if (rawReceiver == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", ObjectManagerIF::CHILD_INIT_FAILED, + "Raw receiver object ID set but no valid object found."); #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "DeviceHandlerBase::initialize: Raw receiver object " - "ID set but no valid object found." << std::endl; sif::error << "Make sure the raw receiver object is set up properly" " and implements AcceptsDeviceResponsesIF" << std::endl; +#else + sif::printError("Make sure the raw receiver object is set up " + "properly and implements AcceptsDeviceResponsesIF\n"); #endif return ObjectManagerIF::CHILD_INIT_FAILED; } @@ -178,11 +168,15 @@ ReturnValue_t DeviceHandlerBase::initialize() { if(powerSwitcherId != objects::NO_OBJECT) { powerSwitcher = objectManager->get(powerSwitcherId); if (powerSwitcher == nullptr) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "initialize", ObjectManagerIF::CHILD_INIT_FAILED, + "Power switcher set but no valid object found."); #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "DeviceHandlerBase::initialize: Power switcher " - << "object ID set but no valid object found." << std::endl; - sif::error << "Make sure the raw receiver object is set up properly" - << " and implements PowerSwitchIF" << std::endl; + sif::error << "Make sure the power switcher object is set up " + << "properly and implements PowerSwitchIF" << std::endl; +#else + sif::printError("Make sure the power switcher object is set up " + "properly and implements PowerSwitchIF\n"); #endif return ObjectManagerIF::CHILD_INIT_FAILED; } @@ -216,7 +210,7 @@ ReturnValue_t DeviceHandlerBase::initialize() { return result; } - result = hkManager.initialize(commandQueue); + result = poolManager.initialize(commandQueue); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -229,7 +223,8 @@ ReturnValue_t DeviceHandlerBase::initialize() { if(result == HasReturnvaluesIF::RETURN_OK) { thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; - thermalSet->commit(PoolVariableIF::VALID); + thermalSet->heaterRequest.setValid(true); + thermalSet->commit(); } } @@ -285,7 +280,7 @@ void DeviceHandlerBase::readCommandQueue() { return; } - result = hkManager.handleHousekeepingMessage(&command); + result = poolManager.handleHousekeepingMessage(&command); if (result == RETURN_OK) { return; } @@ -555,17 +550,17 @@ void DeviceHandlerBase::replyReturnvalueToCommand(ReturnValue_t status, void DeviceHandlerBase::replyToCommand(ReturnValue_t status, uint32_t parameter) { -//Check if we reply to a raw command. + // Check if we reply to a raw command. if (cookieInfo.pendingCommand->first == RAW_COMMAND_ID) { if (status == NO_REPLY_EXPECTED) { status = RETURN_OK; } replyReturnvalueToCommand(status, parameter); - //Always delete data from a raw command. + // Always delete data from a raw command. IPCStore->deleteData(storedRawData); return; } -//Check if we were externally commanded. + // Check if we were externally commanded. if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) { MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo; if (status == NO_REPLY_EXPECTED) { @@ -580,15 +575,17 @@ void DeviceHandlerBase::replyToCommand(ReturnValue_t status, void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter, ReturnValue_t status) { -//No need to check if iter exists, as this is checked by callers. If someone else uses the method, add check. + // No need to check if iter exists, as this is checked by callers. + // If someone else uses the method, add check. if (iter->second.command == deviceCommandMap.end()) { //Is most likely periodic reply. Silent return. return; } -//Check if more replies are expected. If so, do nothing. + // Check if more replies are expected. If so, do nothing. DeviceCommandInfo* info = &(iter->second.command->second); if (--info->expectedReplies == 0) { - //Check if it was transition or internal command. Don't send any replies in that case. + // Check if it was transition or internal command. + // Don't send any replies in that case. if (info->sendReplyTo != NO_COMMANDER) { actionHelper.finish(info->sendReplyTo, iter->first, status); } @@ -605,7 +602,7 @@ void DeviceHandlerBase::doSendWrite() { if (result == RETURN_OK) { cookieInfo.state = COOKIE_WRITE_SENT; } else { - //always generate a failure event, so that FDIR knows what's up + // always generate a failure event, so that FDIR knows what's up triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, cookieInfo.pendingCommand->first); replyToCommand(result); @@ -720,10 +717,9 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData, case RETURN_OK: handleReply(receivedData, foundId, foundLen); if(foundLen == 0) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" - " Packet parsing will be stuck." << std::endl; -#endif + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "parseReply", ObjectManagerIF::CHILD_INIT_FAILED, + "Found length is one, parsing might be stuck"); } break; case APERIODIC_REPLY: { @@ -734,6 +730,9 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData, foundId); } if(foundLen == 0) { + printWarningOrError(sif::OutputTypes::OUT_ERROR, + "parseReply", ObjectManagerIF::CHILD_INIT_FAILED, + "Power switcher set but no valid object found."); #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "DeviceHandlerBase::parseReply: foundLen is 0!" " Packet parsing will be stuck." << std::endl; @@ -746,7 +745,8 @@ void DeviceHandlerBase::parseReply(const uint8_t* receivedData, case IGNORE_FULL_PACKET: return; default: - //We need to wait for timeout.. don't know what command failed and who sent it. + // We need to wait for timeout.. don't know what command failed + // and who sent it. replyRawReplyIfnotWiretapped(receivedData, foundLen); triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen); break; @@ -967,7 +967,8 @@ ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) { } Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) { -//only child action special modes are handled, as a child should never see any base action modes + // only child action special modes are handled, as a child should + // never see any base action modes if (transitionMode == _MODE_START_UP) { return _MODE_TO_ON; } @@ -1290,12 +1291,11 @@ void DeviceHandlerBase::buildInternalCommand(void) { if (mode == MODE_NORMAL) { result = buildNormalDeviceCommand(&deviceCommandId); if (result == BUSY) { - //so we can track misconfigurations -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << std::hex << getObjectId() - << ": DHB::buildInternalCommand: Busy" << std::dec - << std::endl; -#endif + // so we can track misconfigurations + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "buildInternalCommand", + HasReturnvaluesIF::RETURN_FAILED, + "Busy."); result = NOTHING_TO_SEND; //no need to report this } } @@ -1319,12 +1319,15 @@ void DeviceHandlerBase::buildInternalCommand(void) { if (iter == deviceCommandMap.end()) { result = COMMAND_NOT_SUPPORTED; } else if (iter->second.isExecuting) { - //so we can track misconfigurations -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << std::hex << getObjectId() - << ": DHB::buildInternalCommand: Command " - << deviceCommandId << " isExecuting" << std::dec - << std::endl; +#if FSFW_DISABLE_PRINTOUT == 0 + char output[36]; + sprintf(output, "Command 0x%08x is executing", + static_cast(deviceCommandId)); + // so we can track misconfigurations + printWarningOrError(sif::OutputTypes::OUT_WARNING, + "buildInternalCommand", + HasReturnvaluesIF::RETURN_FAILED, + output); #endif // this is an internal command, no need to report a failure here, // missed reply will track if a reply is too late, otherwise, it's ok @@ -1418,7 +1421,7 @@ void DeviceHandlerBase::performOperationHook() { } ReturnValue_t DeviceHandlerBase::initializeLocalDataPool( - LocalDataPool &localDataPoolMap, + localpool::DataPool &localDataPoolMap, LocalDataPoolManager& poolManager) { if(thermalSet != nullptr) { localDataPoolMap.emplace(thermalSet->thermalStatePoolId, @@ -1429,18 +1432,13 @@ ReturnValue_t DeviceHandlerBase::initializeLocalDataPool( return RETURN_OK; } -LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { - return &hkManager; -} - - ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { // In this function, the task handle should be valid if the task // was implemented correctly. We still check to be 1000 % sure :-) if(executingTask != nullptr) { pstIntervalMs = executingTask->getPeriodMs(); } - this->hkManager.initializeAfterTaskCreation(); + this->poolManager.initializeAfterTaskCreation(); if(setStartupImmediately) { startTransition(MODE_ON, SUBMODE_NONE); @@ -1484,3 +1482,56 @@ void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() { } } } + +AccessPoolManagerIF* DeviceHandlerBase::getAccessorHandle() { + return &poolManager; +} + +void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, + const char *functionName, ReturnValue_t errorCode, + const char *errorPrint) { + if(errorPrint == nullptr) { + if(errorCode == ObjectManagerIF::CHILD_INIT_FAILED) { + errorPrint = "Initialization error"; + } + if(errorCode == HasReturnvaluesIF::RETURN_FAILED) { + if(errorType == sif::OutputTypes::OUT_WARNING) { + errorPrint = "Generic Warning"; + } + else { + errorPrint = "Generic Error"; + } + } + else { + errorPrint = "Unknown error"; + } + } + + if(errorType == sif::OutputTypes::OUT_WARNING) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "DeviceHandlerBase::" << functionName << ": Object ID " + << std::hex << std::setw(8) << std::setfill('0') + << this->getObjectId() << " | " << errorPrint << std::dec + << std::setfill(' ') << std::endl; +#else + sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", + this->getObjectId(), errorPrint); +#endif + } + else if(errorType == sif::OutputTypes::OUT_ERROR) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "DeviceHandlerBase::" << functionName << ": Object ID " + << std::hex << std::setw(8) << std::setfill('0') + << this->getObjectId() << " | " << errorPrint << std::dec + << std::setfill(' ') << std::endl; +#else + sif::printError("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", + this->getObjectId(), errorPrint); +#endif + } + +} + +ProvidesDataPoolSubscriptionIF* DeviceHandlerBase::getSubscriptionInterface() { + return &poolManager; +} diff --git a/devicehandlers/DeviceHandlerBase.h b/devicehandlers/DeviceHandlerBase.h index 24ba0372..43f61897 100644 --- a/devicehandlers/DeviceHandlerBase.h +++ b/devicehandlers/DeviceHandlerBase.h @@ -6,6 +6,8 @@ #include "DeviceHandlerFailureIsolation.h" #include "DeviceHandlerThermalSet.h" +#include "../serviceinterface/ServiceInterface.h" +#include "../serviceinterface/serviceInterfaceDefintions.h" #include "../objectmanager/SystemObject.h" #include "../tasks/ExecutableObjectIF.h" #include "../returnvalues/HasReturnvaluesIF.h" @@ -512,11 +514,18 @@ protected: * @param localDataPoolMap * @return */ - virtual ReturnValue_t initializeLocalDataPool(LocalDataPool& localDataPoolMap, + virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; - /** Get the HK manager object handle */ - virtual LocalDataPoolManager* getHkManagerHandle() override; + /** + * Provides the subscription handle which can be used by classes like controllers + * to get messages on data updates. + * @return + */ + ProvidesDataPoolSubscriptionIF* getSubscriptionInterface() override; + + //! Accessor handle required for internal handling. + AccessPoolManagerIF* getAccessorHandle() override; /** * @brief Hook function for child handlers which is called once per @@ -646,7 +655,7 @@ protected: /** Action helper for HasActionsIF */ ActionHelper actionHelper; /** Housekeeping Manager */ - LocalDataPoolManager hkManager; + LocalDataPoolManager poolManager; /** * @brief Information about commands @@ -1111,7 +1120,7 @@ private: /** * @brief The mode the current transition originated from * - * This is private so the child can not change it and fuck up the timeouts + * This is private so the child can not change it and mess up the timeouts * * IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!! * (it is _MODE_POWER_DOWN during this modes) @@ -1190,7 +1199,8 @@ private: * Check if the RMAP sendWrite action was successful. * * Depending on the result, the following is done - * - if the device command was external commanded, a reply is sent indicating the result + * - if the device command was external commanded, a reply is sent + * indicating the result * - if the action was successful, the reply timout counter is initialized */ void doGetWrite(void); @@ -1206,9 +1216,9 @@ private: /** * Check the getRead reply and the contained data. * - * If data was received scanForReply() and, if successful, handleReply() are called. - * If the current mode is @c MODE_RAW, the received packet is sent to the commanding object - * via commandQueue. + * If data was received scanForReply() and, if successful, handleReply() + * are called. If the current mode is @c MODE_RAW, the received packet + * is sent to the commanding object via commandQueue. */ void doGetRead(void); @@ -1227,7 +1237,7 @@ private: uint32_t *len); /** - * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW NOTHING ELSE!!! + * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW, nothing else! */ void setTransition(Mode_t modeTo, Submode_t submodeTo); @@ -1247,6 +1257,11 @@ private: void handleTransitionToOnMode(Mode_t commandedMode, Submode_t commandedSubmode); + + void printWarningOrError(sif::OutputTypes errorType, + const char* functionName, + ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED, + const char* errorPrint = nullptr); }; #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */ diff --git a/devicehandlers/DeviceHandlerIF.h b/devicehandlers/DeviceHandlerIF.h index 865b38b3..bae68516 100644 --- a/devicehandlers/DeviceHandlerIF.h +++ b/devicehandlers/DeviceHandlerIF.h @@ -1,10 +1,10 @@ #ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ #define FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ +#include #include "DeviceHandlerMessage.h" #include "../action/HasActionsIF.h" -#include "../datapoollocal/locPoolDefinitions.h" #include "../events/Event.h" #include "../modes/HasModesIF.h" #include "../ipc/MessageQueueSenderIF.h" diff --git a/events/EventManager.cpp b/events/EventManager.cpp index 65e19d10..e25e574f 100644 --- a/events/EventManager.cpp +++ b/events/EventManager.cpp @@ -162,9 +162,15 @@ void EventManager::printEvent(EventMessage* message) { #endif void EventManager::lockMutex() { - mutex->lockMutex(MutexIF::BLOCKING); + mutex->lockMutex(timeoutType, timeoutMs); } void EventManager::unlockMutex() { mutex->unlockMutex(); } + +void EventManager::setMutexTimeout(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + this->timeoutType = timeoutType; + this->timeoutMs = timeoutMs; +} diff --git a/events/EventManager.h b/events/EventManager.h index c6bd07be..abce9b8b 100644 --- a/events/EventManager.h +++ b/events/EventManager.h @@ -29,6 +29,8 @@ public: EventManager(object_id_t setObjectId); virtual ~EventManager(); + void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs); + MessageQueueId_t getEventReportQueue(); ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false); @@ -51,6 +53,8 @@ protected: std::map listenerList; MutexIF* mutex = nullptr; + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; + uint32_t timeoutMs = 20; static const uint8_t N_POOLS = 3; LocalPool factoryBackend; diff --git a/fsfw.mk b/fsfw.mk index 3df63060..0d72fae1 100644 --- a/fsfw.mk +++ b/fsfw.mk @@ -10,6 +10,7 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/coordinates/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datalinklayer/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapool/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/datapoollocal/internal/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/housekeeping/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/devicehandlers/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/events/*.cpp) diff --git a/globalfunctions/arrayprinter.cpp b/globalfunctions/arrayprinter.cpp index c273b250..25d6fcf4 100644 --- a/globalfunctions/arrayprinter.cpp +++ b/globalfunctions/arrayprinter.cpp @@ -1,5 +1,5 @@ #include "arrayprinter.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" #include void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, @@ -9,6 +9,8 @@ void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, sif::info << "Printing data with size " << size << ": "; } sif::info << "["; +#else + sif::printInfo("Printing data with size %zu: [", size); #endif if(type == OutputType::HEX) { arrayprinter::printHex(data, size, maxCharPerLine); @@ -37,6 +39,8 @@ void arrayprinter::printHex(const uint8_t *data, size_t size, } sif::info << std::dec; sif::info << "]" << std::endl; +#else + // how much memory to reserve for printout? #endif } @@ -54,6 +58,8 @@ void arrayprinter::printDec(const uint8_t *data, size_t size, } } sif::info << "]" << std::endl; +#else + // how much memory to reserve for printout? #endif } @@ -65,5 +71,7 @@ void arrayprinter::printBin(const uint8_t *data, size_t size) { std::bitset<8>(data[i]) << ",\n" << std::flush; } sif::info << "]" << std::endl; +#else + // how much memory to reserve for printout? #endif } diff --git a/housekeeping/HousekeepingMessage.h b/housekeeping/HousekeepingMessage.h index 90bbe594..0c7680dc 100644 --- a/housekeeping/HousekeepingMessage.h +++ b/housekeeping/HousekeepingMessage.h @@ -1,7 +1,7 @@ #ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ #define FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ -#include "../datapoollocal/locPoolDefinitions.h" +#include "../datapoollocal/localPoolDefinitions.h" #include "../ipc/CommandMessage.h" #include "../ipc/FwMessageTypes.h" #include "../objectmanager/frameworkObjects.h" diff --git a/internalError/InternalErrorDataset.h b/internalError/InternalErrorDataset.h index fa91116d..bd9062ed 100644 --- a/internalError/InternalErrorDataset.h +++ b/internalError/InternalErrorDataset.h @@ -21,11 +21,11 @@ public: InternalErrorDataset(object_id_t objectId): StaticLocalDataSet(sid_t(objectId , ERROR_SET_ID)) {} - lp_var_t tmHits = lp_var_t(hkManager->getOwner(), + lp_var_t tmHits = lp_var_t(sid.objectId, TM_HITS, this); - lp_var_t queueHits = lp_var_t(hkManager->getOwner(), + lp_var_t queueHits = lp_var_t(sid.objectId, QUEUE_HITS, this); - lp_var_t storeHits = lp_var_t(hkManager->getOwner(), + lp_var_t storeHits = lp_var_t(sid.objectId, STORE_HITS, this); }; diff --git a/internalError/InternalErrorReporter.cpp b/internalError/InternalErrorReporter.cpp index 48b6f851..bc72ada2 100644 --- a/internalError/InternalErrorReporter.cpp +++ b/internalError/InternalErrorReporter.cpp @@ -2,7 +2,7 @@ #include "../ipc/QueueFactory.h" #include "../ipc/MutexFactory.h" -#include "../serviceinterface/ServiceInterfaceStream.h" +#include "../serviceinterface/ServiceInterface.h" InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth): SystemObject(setObjectId), @@ -23,13 +23,13 @@ void InternalErrorReporter::setDiagnosticPrintout(bool enable) { } ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { - internalErrorDataset.read(INTERNAL_ERROR_MUTEX_TIMEOUT); + internalErrorDataset.read(timeoutType, timeoutMs); uint32_t newQueueHits = getAndResetQueueHits(); uint32_t newTmHits = getAndResetTmHits(); uint32_t newStoreHits = getAndResetStoreHits(); -#if FSFW_ENHANCED_PRINTOUT == 1 +#if FSFW_VERBOSE_LEVEL == 1 if(diagnosticPrintout) { if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -38,6 +38,11 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { sif::debug << "Queue errors: " << newQueueHits << std::endl; sif::debug << "TM errors: " << newTmHits << std::endl; sif::debug << "Store errors: " << newStoreHits << std::endl; +#else + sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n"); + sif::printDebug("Queue errors: %lu\n", static_cast(newQueueHits)); + sif::printDebug("TM errors: %lu\n", static_cast(newTmHits)); + sif::printDebug("Store errors: %lu\n", static_cast(newStoreHits)); #endif } } @@ -46,8 +51,8 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) { internalErrorDataset.queueHits.value += newQueueHits; internalErrorDataset.storeHits.value += newStoreHits; internalErrorDataset.tmHits.value += newTmHits; - - internalErrorDataset.commit(INTERNAL_ERROR_MUTEX_TIMEOUT); + internalErrorDataset.setValidity(true, true); + internalErrorDataset.commit(timeoutType, timeoutMs); poolManager.performHkOperation(); @@ -69,7 +74,7 @@ void InternalErrorReporter::lostTm() { uint32_t InternalErrorReporter::getAndResetQueueHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = queueHits; queueHits = 0; mutex->unlockMutex(); @@ -78,21 +83,21 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() { uint32_t InternalErrorReporter::getQueueHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = queueHits; mutex->unlockMutex(); return value; } void InternalErrorReporter::incrementQueueHits() { - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); queueHits++; mutex->unlockMutex(); } uint32_t InternalErrorReporter::getAndResetTmHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = tmHits; tmHits = 0; mutex->unlockMutex(); @@ -101,14 +106,14 @@ uint32_t InternalErrorReporter::getAndResetTmHits() { uint32_t InternalErrorReporter::getTmHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = tmHits; mutex->unlockMutex(); return value; } void InternalErrorReporter::incrementTmHits() { - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); tmHits++; mutex->unlockMutex(); } @@ -119,7 +124,7 @@ void InternalErrorReporter::storeFull() { uint32_t InternalErrorReporter::getAndResetStoreHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = storeHits; storeHits = 0; mutex->unlockMutex(); @@ -128,14 +133,18 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() { uint32_t InternalErrorReporter::getStoreHits() { uint32_t value; - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); value = storeHits; mutex->unlockMutex(); return value; } +AccessPoolManagerIF* InternalErrorReporter::getAccessorHandle() { + return &poolManager; +} + void InternalErrorReporter::incrementStoreHits() { - mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT); + mutex->lockMutex(timeoutType, timeoutMs); storeHits++; mutex->unlockMutex(); } @@ -149,7 +158,7 @@ MessageQueueId_t InternalErrorReporter::getCommandQueue() const { } ReturnValue_t InternalErrorReporter::initializeLocalDataPool( - LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { + localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { localDataPoolMap.emplace(errorPoolIds::TM_HITS, new PoolEntry()); localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, @@ -162,10 +171,6 @@ ReturnValue_t InternalErrorReporter::initializeLocalDataPool( return HasReturnvaluesIF::RETURN_OK; } -LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() { - return &poolManager; -} - dur_millis_t InternalErrorReporter::getPeriodicOperationFrequency() const { return this->executingTask->getPeriodMs(); } @@ -190,3 +195,12 @@ ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() { return poolManager.initializeAfterTaskCreation(); } +void InternalErrorReporter::setMutexTimeout(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs) { + this->timeoutType = timeoutType; + this->timeoutMs = timeoutMs; +} + +ProvidesDataPoolSubscriptionIF* InternalErrorReporter::getSubscriptionInterface() { + return &poolManager; +} diff --git a/internalError/InternalErrorReporter.h b/internalError/InternalErrorReporter.h index 8d33c06e..ec9134d4 100644 --- a/internalError/InternalErrorReporter.h +++ b/internalError/InternalErrorReporter.h @@ -22,7 +22,6 @@ class InternalErrorReporter: public SystemObject, public InternalErrorReporterIF, public HasLocalDataPoolIF { public: - static constexpr uint8_t INTERNAL_ERROR_MUTEX_TIMEOUT = 20; InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth = 5); @@ -34,16 +33,20 @@ public: */ void setDiagnosticPrintout(bool enable); + void setMutexTimeout(MutexIF::TimeoutType timeoutType, + uint32_t timeoutMs); + virtual ~InternalErrorReporter(); virtual object_id_t getObjectId() const override; virtual MessageQueueId_t getCommandQueue() const override; virtual ReturnValue_t initializeLocalDataPool( - LocalDataPool& localDataPoolMap, + localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; - virtual LocalDataPoolManager* getHkManagerHandle() override; virtual dur_millis_t getPeriodicOperationFrequency() const override; virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; + ProvidesDataPoolSubscriptionIF* getSubscriptionInterface() override; + AccessPoolManagerIF* getAccessorHandle() override; virtual ReturnValue_t initialize() override; virtual ReturnValue_t initializeAfterTaskCreation() override; @@ -61,7 +64,11 @@ protected: LocalDataPoolManager poolManager; PeriodicTaskIF* executingTask = nullptr; + MutexIF* mutex = nullptr; + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; + uint32_t timeoutMs = 20; + sid_t internalErrorSid; InternalErrorDataset internalErrorDataset; diff --git a/ipc/MutexIF.h b/ipc/MutexIF.h index 5673e4d7..084b702b 100644 --- a/ipc/MutexIF.h +++ b/ipc/MutexIF.h @@ -14,7 +14,7 @@ public: /** * Different types of timeout for the mutex lock. */ - enum TimeoutType { + enum class TimeoutType { POLLING, //!< If mutex is not available, return immediately WAITING, //!< Wait a specified time for the mutex to become available BLOCKING //!< Block indefinitely until the mutex becomes available. diff --git a/monitoring/MonitorReporter.h b/monitoring/MonitorReporter.h index 9028e7e4..7ce110e5 100644 --- a/monitoring/MonitorReporter.h +++ b/monitoring/MonitorReporter.h @@ -5,7 +5,7 @@ #include "MonitoringIF.h" #include "MonitoringMessageContent.h" -#include "../datapoollocal/locPoolDefinitions.h" +#include "../datapoollocal/localPoolDefinitions.h" #include "../events/EventManagerIF.h" #include "../parameters/HasParametersIF.h" diff --git a/monitoring/MonitoringMessageContent.h b/monitoring/MonitoringMessageContent.h index 2822743a..d830e313 100644 --- a/monitoring/MonitoringMessageContent.h +++ b/monitoring/MonitoringMessageContent.h @@ -1,9 +1,10 @@ -#ifndef MONITORINGMESSAGECONTENT_H_ -#define MONITORINGMESSAGECONTENT_H_ +#ifndef FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_ +#define FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_ #include "HasMonitorsIF.h" #include "MonitoringIF.h" -#include "../datapoollocal/locPoolDefinitions.h" + +#include "../datapoollocal/localPoolDefinitions.h" #include "../objectmanager/ObjectManagerIF.h" #include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialFixedArrayListAdapter.h" @@ -85,4 +86,4 @@ private: template object_id_t MonitoringReportContent::timeStamperId = 0; -#endif /* MONITORINGMESSAGECONTENT_H_ */ +#endif /* FSFW_MONITORING_MONITORINGMESSAGECONTENT_H_ */ diff --git a/osal/FreeRTOS/Clock.cpp b/osal/FreeRTOS/Clock.cpp index d3f4e68e..9c0a0267 100644 --- a/osal/FreeRTOS/Clock.cpp +++ b/osal/FreeRTOS/Clock.cpp @@ -163,7 +163,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -178,7 +178,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { if (timeMutex == NULL) { return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } diff --git a/osal/host/Clock.cpp b/osal/host/Clock.cpp index 2bc78785..88bf51d2 100644 --- a/osal/host/Clock.cpp +++ b/osal/host/Clock.cpp @@ -202,7 +202,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -217,7 +217,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { if(timeMutex == nullptr){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } diff --git a/osal/host/Mutex.cpp b/osal/host/Mutex.cpp index ad8873df..892028b2 100644 --- a/osal/host/Mutex.cpp +++ b/osal/host/Mutex.cpp @@ -4,16 +4,16 @@ Mutex::Mutex() {} ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) { - if(timeoutType == MutexIF::BLOCKING) { + if(timeoutType == TimeoutType::BLOCKING) { mutex.lock(); return HasReturnvaluesIF::RETURN_OK; } - else if(timeoutType == MutexIF::POLLING) { + else if(timeoutType == TimeoutType::POLLING) { if(mutex.try_lock()) { return HasReturnvaluesIF::RETURN_OK; } } - else if(timeoutMs > MutexIF::POLLING){ + else if(timeoutType == TimeoutType::WAITING){ auto chronoMs = std::chrono::milliseconds(timeoutMs); if(mutex.try_lock_for(chronoMs)) { return HasReturnvaluesIF::RETURN_OK; diff --git a/osal/host/Mutex.h b/osal/host/Mutex.h index c0fa19b7..0bd93c8a 100644 --- a/osal/host/Mutex.h +++ b/osal/host/Mutex.h @@ -22,7 +22,6 @@ public: std::timed_mutex* getMutexHandle(); private: - //bool locked = false; std::timed_mutex mutex; }; diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp index 0a6bb29f..5716e560 100644 --- a/osal/linux/BinarySemaphore.cpp +++ b/osal/linux/BinarySemaphore.cpp @@ -1,10 +1,11 @@ #include "BinarySemaphore.h" +#include "../../serviceinterface/ServiceInterfacePrinter.h" #include "../../serviceinterface/ServiceInterfaceStream.h" -extern "C" { +#include #include #include -} + BinarySemaphore::BinarySemaphore() { // Using unnamed semaphores for now @@ -113,7 +114,8 @@ uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { } else if(result != 0 and errno == EINVAL) { // Could be called from interrupt, use lightweight printf - printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); + sif::printError("BinarySemaphore::getSemaphoreCounter: " + "Invalid semaphore\n"); return 0; } else { @@ -128,13 +130,17 @@ void BinarySemaphore::initSemaphore(uint8_t initCount) { switch(errno) { case(EINVAL): // Value exceeds SEM_VALUE_MAX - case(ENOSYS): - // System does not support process-shared semaphores + case(ENOSYS): { + // System does not support process-shared semaphores #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "BinarySemaphore: Init failed with" << strerror(errno) - << std::endl; + sif::error << "BinarySemaphore: Init failed with " + << strerror(errno) << std::endl; +#else + sif::printError("BinarySemaphore: Init failed with %s\n", + strerror(errno)); #endif } + } } } diff --git a/osal/linux/Clock.cpp b/osal/linux/Clock.cpp index 54dad839..35cbfae0 100644 --- a/osal/linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -182,7 +182,7 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -197,7 +197,7 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { if(timeMutex==NULL){ return HasReturnvaluesIF::RETURN_FAILED; } - ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); + ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -209,13 +209,13 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { } ReturnValue_t Clock::checkOrCreateClockMutex(){ - if(timeMutex==NULL){ + if(timeMutex == nullptr){ MutexFactory* mutexFactory = MutexFactory::instance(); - if (mutexFactory == NULL) { + if (mutexFactory == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } timeMutex = mutexFactory->createMutex(); - if (timeMutex == NULL) { + if (timeMutex == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } } diff --git a/osal/linux/CountingSemaphore.cpp b/osal/linux/CountingSemaphore.cpp index 0bb71831..07c52212 100644 --- a/osal/linux/CountingSemaphore.cpp +++ b/osal/linux/CountingSemaphore.cpp @@ -1,5 +1,7 @@ #include "../../osal/linux/CountingSemaphore.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" + +#include CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): maxCount(maxCount), initCount(initCount) { diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index e7b09b4f..60d15dee 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -1,5 +1,5 @@ #include "MessageQueue.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" #include "../../objectmanager/ObjectManagerIF.h" #include @@ -121,14 +121,16 @@ ReturnValue_t MessageQueue::handleError(mq_attr* attributes, break; } - default: + default: { // Failed either the first time or the second time #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex - << name << std::dec << " failed with status: " - << strerror(errno) << std::endl; + sif::error << "MessageQueue::MessageQueue: Creating Queue " << name + << " failed with status: " << strerror(errno) << std::endl; +#else + sif::printError("MessageQueue::MessageQueue: Creating Queue %s" + " failed with status: %s\n", name, strerror(errno)); #endif - + } } return HasReturnvaluesIF::RETURN_FAILED; diff --git a/osal/linux/PosixThread.cpp b/osal/linux/PosixThread.cpp index a0e540cf..2499b442 100644 --- a/osal/linux/PosixThread.cpp +++ b/osal/linux/PosixThread.cpp @@ -1,6 +1,6 @@ #include "PosixThread.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" #include #include @@ -146,16 +146,22 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { strerror(status) << std::endl; #endif if(errno == ENOMEM) { - uint64_t stackMb = stackSize/10e6; + size_t stackMb = stackSize/10e6; #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PosixThread::createTask: Insufficient memory for" " the requested " << stackMb << " MB" << std::endl; +#else + sif::printError("PosixThread::createTask: Insufficient memory for " + "the requested %zu MB\n", stackMb); #endif } else if(errno == EINVAL) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PosixThread::createTask: Wrong alignment argument!" << std::endl; +#else + sif::printError("PosixThread::createTask: " + "Wrong alignment argument!\n"); #endif } return; diff --git a/osal/linux/TcUnixUdpPollingTask.cpp b/osal/linux/TcUnixUdpPollingTask.cpp index a8387e87..11ed7fee 100644 --- a/osal/linux/TcUnixUdpPollingTask.cpp +++ b/osal/linux/TcUnixUdpPollingTask.cpp @@ -1,6 +1,8 @@ #include "TcUnixUdpPollingTask.h" #include "../../globalfunctions/arrayprinter.h" +#include + TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, size_t frameSize, double timeoutSeconds): SystemObject(objectId), diff --git a/osal/linux/TmTcUnixUdpBridge.cpp b/osal/linux/TmTcUnixUdpBridge.cpp index 1d318d3b..0af1fc68 100644 --- a/osal/linux/TmTcUnixUdpBridge.cpp +++ b/osal/linux/TmTcUnixUdpBridge.cpp @@ -1,5 +1,5 @@ #include "TmTcUnixUdpBridge.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" #include "../../ipc/MutexHelper.h" #include @@ -188,12 +188,16 @@ void TmTcUnixUdpBridge::handleBindError() { void TmTcUnixUdpBridge::handleSendError() { switch(errno) { - default: + default: { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "TmTcUnixBridge::handleSendError: " << strerror(errno) << std::endl; +#else + sif::printError("TmTcUnixBridge::handleSendError: %s\n", + strerror(errno)); #endif } + } } void TmTcUnixUdpBridge::setClientAddressToAny(bool ipAddrAnySet){ diff --git a/osal/rtems/Mutex.cpp b/osal/rtems/Mutex.cpp index 71c5782f..7dd512fa 100644 --- a/osal/rtems/Mutex.cpp +++ b/osal/rtems/Mutex.cpp @@ -30,11 +30,11 @@ Mutex::~Mutex() { ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType = TimeoutType::BLOCKING, uint32_t timeoutMs) { rtems_status_code status = RTEMS_INVALID_ID; - if(timeoutMs == MutexIF::TimeoutType::BLOCKING) { + if(timeoutType == MutexIF::TimeoutType::BLOCKING) { status = rtems_semaphore_obtain(mutexId, RTEMS_WAIT, RTEMS_NO_TIMEOUT); } - else if(timeoutMs == MutexIF::TimeoutType::POLLING) { + else if(timeoutType == MutexIF::TimeoutType::POLLING) { timeoutMs = RTEMS_NO_TIMEOUT; status = rtems_semaphore_obtain(mutexId, RTEMS_NO_WAIT, 0); diff --git a/power/Fuse.cpp b/power/Fuse.cpp index 1c30d83f..b6e0a7f1 100644 --- a/power/Fuse.cpp +++ b/power/Fuse.cpp @@ -65,8 +65,8 @@ ReturnValue_t Fuse::check() { set.read(); if (!healthHelper.healthTable->isHealthy(getObjectId())) { setAllMonitorsToUnchecked(); - set.commit(PoolVariableIF::INVALID); - return RETURN_OK; + set.setValidity(false, true); + return set.commit(); } ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; checkFuseState(); @@ -206,7 +206,8 @@ float Fuse::getPower() { void Fuse::setDataPoolEntriesInvalid() { set.read(); - set.commit(PoolVariableIF::INVALID); + set.setValidity(false, true); + set.commit(); } ReturnValue_t Fuse::getParameter(uint8_t domainId, uint16_t parameterId, diff --git a/power/PowerSensor.cpp b/power/PowerSensor.cpp index 1ef041e3..fb181d9f 100644 --- a/power/PowerSensor.cpp +++ b/power/PowerSensor.cpp @@ -97,7 +97,8 @@ void PowerSensor::checkCommandQueue() { void PowerSensor::setDataPoolEntriesInvalid() { powerSensorSet.read(); - powerSensorSet.commit(PoolVariableIF::INVALID); + powerSensorSet.setValidity(false, true); + powerSensorSet.commit(); } float PowerSensor::getPower() { diff --git a/unittest/internal/UnittDefinitions.cpp b/unittest/internal/UnittDefinitions.cpp index 7138e6c6..517f561a 100644 --- a/unittest/internal/UnittDefinitions.cpp +++ b/unittest/internal/UnittDefinitions.cpp @@ -3,7 +3,9 @@ ReturnValue_t unitt::put_error(std::string errorId) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Unit Tester error: Failed at test ID " - << errorId << "\n" << std::flush; -#endif + << errorId << std::endl; +#else + sif::printError("Unit Tester error: Failed at test ID 0x%08x", errorId); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/unittest/internal/UnittDefinitions.h b/unittest/internal/UnittDefinitions.h index ea36fea4..3e14fec5 100644 --- a/unittest/internal/UnittDefinitions.h +++ b/unittest/internal/UnittDefinitions.h @@ -2,9 +2,10 @@ #define UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ #include "../../returnvalues/HasReturnvaluesIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include "../../serviceinterface/ServiceInterface.h" #include #include +#include namespace tv { // POD test values diff --git a/unittest/internal/osal/IntTestMutex.cpp b/unittest/internal/osal/IntTestMutex.cpp index 3316de74..2a1584b8 100644 --- a/unittest/internal/osal/IntTestMutex.cpp +++ b/unittest/internal/osal/IntTestMutex.cpp @@ -13,7 +13,7 @@ void testmutex::testMutex() { std::string id = "[testMutex]"; MutexIF* mutex = MutexFactory::instance()->createMutex(); - auto result = mutex->lockMutex(MutexIF::POLLING); + auto result = mutex->lockMutex(MutexIF::TimeoutType::POLLING); if(result != HasReturnvaluesIF::RETURN_OK) { unitt::put_error(id); } diff --git a/unittest/tests/CMakeLists.txt b/unittest/tests/CMakeLists.txt index 97074417..180e1a51 100644 --- a/unittest/tests/CMakeLists.txt +++ b/unittest/tests/CMakeLists.txt @@ -2,5 +2,6 @@ add_subdirectory(action) add_subdirectory(container) add_subdirectory(osal) add_subdirectory(serialize) +add_subdirectory(datapoollocal) add_subdirectory(storagemanager) diff --git a/unittest/tests/action/TestActionHelper.cpp b/unittest/tests/action/TestActionHelper.cpp index 3109eba1..2493a6b8 100644 --- a/unittest/tests/action/TestActionHelper.cpp +++ b/unittest/tests/action/TestActionHelper.cpp @@ -4,9 +4,12 @@ #include #include +#include #include +#include + TEST_CASE( "Action Helper" , "[ActionHelper]") { ActionHelperOwnerMockBase testDhMock; diff --git a/unittest/tests/action/TestActionHelper.h b/unittest/tests/action/TestActionHelper.h index 610fb09e..641ea2c6 100644 --- a/unittest/tests/action/TestActionHelper.h +++ b/unittest/tests/action/TestActionHelper.h @@ -48,85 +48,4 @@ public: }; -class MessageQueueMockBase: public MessageQueueIF { -public: - MessageQueueId_t myQueueId = 0; - bool defaultDestSet = false; - bool messageSent = false; - - - - bool wasMessageSent() { - bool tempMessageSent = messageSent; - messageSent = false; - return tempMessageSent; - } - - virtual ReturnValue_t reply( MessageQueueMessageIF* message ) { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - }; - virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, - MessageQueueId_t *receivedFrom) { - (*message) = lastMessage; - lastMessage.clear(); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) { - memcpy(message->getBuffer(), lastMessage.getBuffer(), - message->getMessageSize()); - lastMessage.clear(); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t flush(uint32_t* count) { - return HasReturnvaluesIF::RETURN_OK; - } - virtual MessageQueueId_t getLastPartner() const { - return tconst::testQueueId; - } - virtual MessageQueueId_t getId() const { - return tconst::testQueueId; - } - virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, - MessageQueueMessageIF* message, MessageQueueId_t sentFrom, - bool ignoreFault = false ) { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, - MessageQueueMessageIF* message, bool ignoreFault = false ) override { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, - MessageQueueId_t sentFrom, bool ignoreFault = false ) { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - } - virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ) { - messageSent = true; - lastMessage = *(dynamic_cast(message)); - return HasReturnvaluesIF::RETURN_OK; - } - virtual void setDefaultDestination(MessageQueueId_t defaultDestination) { - myQueueId = defaultDestination; - defaultDestSet = true; - } - - virtual MessageQueueId_t getDefaultDestination() const { - return myQueueId; - } - virtual bool isDefaultDestinationSet() const { - return defaultDestSet; - } -private: - MessageQueueMessage lastMessage; - -}; - - #endif /* UNITTEST_TESTFW_NEWTESTS_TESTACTIONHELPER_H_ */ diff --git a/unittest/tests/container/TestPlacementFactory.cpp b/unittest/tests/container/TestPlacementFactory.cpp index 5edbb9d2..14cf8eb4 100644 --- a/unittest/tests/container/TestPlacementFactory.cpp +++ b/unittest/tests/container/TestPlacementFactory.cpp @@ -1,45 +1,48 @@ -//#include -//#include -//#include -//#include -// -//#include -//#include "../../core/CatchDefinitions.h" -// -//TEST_CASE( "PlacementFactory Tests", "[TestPlacementFactory]") { -// INFO("PlacementFactory Tests"); -// -// const uint16_t element_sizes[3] = {sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t)}; -// const uint16_t n_elements[3] = {1, 1, 1}; -// LocalPool<3> storagePool(0x1, element_sizes, n_elements, false, true); -// PlacementFactory factory(&storagePool); -// -// SECTION("Pool overload"){ -// store_address_t address; -// uint8_t* ptr = nullptr; -// REQUIRE(storagePool.getFreeElement(&address, sizeof(ArrayList), &ptr) -// == static_cast(StorageManagerIF::DATA_TOO_LARGE)); -// ArrayList* list2 = factory.generate >(80); -// REQUIRE(list2 == nullptr); -// } -// -// SECTION("Test generate and destroy"){ -// uint64_t* number = factory.generate(32000); -// REQUIRE(number != nullptr); -// REQUIRE(*number == 32000); -// store_address_t address; -// uint8_t* ptr = nullptr; -// REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) -// == static_cast(StorageManagerIF::DATA_TOO_LARGE)); -// uint64_t* number2 = factory.generate(12345); -// REQUIRE(number2 == nullptr); -// REQUIRE(factory.destroy(number) == static_cast(HasReturnvaluesIF::RETURN_OK)); -// REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) -// == static_cast(HasReturnvaluesIF::RETURN_OK)); -// REQUIRE(storagePool.deleteData(address) == static_cast(HasReturnvaluesIF::RETURN_OK)); -// -// //Check that PlacementFactory checks for nullptr -// ptr = nullptr; -// REQUIRE(factory.destroy(ptr) == static_cast(HasReturnvaluesIF::RETURN_FAILED)); -// } -//} +#include +#include +#include +#include + +#include +#include + +TEST_CASE( "PlacementFactory Tests", "[TestPlacementFactory]") { + INFO("PlacementFactory Tests"); + + LocalPool::LocalPoolConfig poolCfg= {{1, sizeof(uint16_t)}, + {1, sizeof(uint32_t)}, {1, sizeof(uint64_t)} + }; + //const uint16_t element_sizes[3] = {sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t)}; + //const uint16_t n_elements[3] = {1, 1, 1}; + LocalPool storagePool(0x1, poolCfg, false, true); + PlacementFactory factory(&storagePool); + + SECTION("Pool overload"){ + store_address_t address; + uint8_t* ptr = nullptr; + REQUIRE(storagePool.getFreeElement(&address, sizeof(ArrayList), &ptr) + == static_cast(StorageManagerIF::DATA_TOO_LARGE)); + ArrayList* list2 = factory.generate >(80); + REQUIRE(list2 == nullptr); + } + + SECTION("Test generate and destroy"){ + uint64_t* number = factory.generate(32000); + REQUIRE(number != nullptr); + REQUIRE(*number == 32000); + store_address_t address; + uint8_t* ptr = nullptr; + REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) + == static_cast(StorageManagerIF::DATA_TOO_LARGE)); + uint64_t* number2 = factory.generate(12345); + REQUIRE(number2 == nullptr); + REQUIRE(factory.destroy(number) == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr) + == static_cast(HasReturnvaluesIF::RETURN_OK)); + REQUIRE(storagePool.deleteData(address) == static_cast(HasReturnvaluesIF::RETURN_OK)); + + //Check that PlacementFactory checks for nullptr + ptr = nullptr; + REQUIRE(factory.destroy(ptr) == static_cast(HasReturnvaluesIF::RETURN_FAILED)); + } +} diff --git a/unittest/tests/datapoollocal/CMakeLists.txt b/unittest/tests/datapoollocal/CMakeLists.txt new file mode 100644 index 00000000..f196a080 --- /dev/null +++ b/unittest/tests/datapoollocal/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${TARGET_NAME} PRIVATE + LocalPoolVariableTest.cpp + LocalPoolVectorTest.cpp + DataSetTest.cpp + LocalPoolManagerTest.cpp +) diff --git a/unittest/tests/datapoollocal/DataSetTest.cpp b/unittest/tests/datapoollocal/DataSetTest.cpp new file mode 100644 index 00000000..968a0b3d --- /dev/null +++ b/unittest/tests/datapoollocal/DataSetTest.cpp @@ -0,0 +1,23 @@ +#include "LocalPoolOwnerBase.h" + +#include +#include +#include +#include + +TEST_CASE("LocalDataSet" , "[LocDataSetTest]") { + LocalPoolOwnerBase* poolOwner = objectManager-> + get(objects::TEST_LOCAL_POOL_OWNER_BASE); + REQUIRE(poolOwner != nullptr); + REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); + REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() + == retval::CATCH_OK); + const uint32_t setId = 0; + SECTION("BasicTest") { + StaticLocalDataSet<3> localSet = StaticLocalDataSet<3>( + sid_t(objects::TEST_LOCAL_POOL_OWNER_BASE, setId)); + } +} + + + diff --git a/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp b/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp new file mode 100644 index 00000000..f550582e --- /dev/null +++ b/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp @@ -0,0 +1,122 @@ +#include "LocalPoolOwnerBase.h" + +#include +#include +#include +#include +#include + + +TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { + LocalPoolOwnerBase* poolOwner = objectManager-> + get(objects::TEST_LOCAL_POOL_OWNER_BASE); + REQUIRE(poolOwner != nullptr); + REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); + REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() + == retval::CATCH_OK); + REQUIRE(poolOwner->dataset.assignPointers() == retval::CATCH_OK); + MessageQueueMockBase* mqMock = poolOwner->getMockQueueHandle(); + REQUIRE(mqMock != nullptr); + CommandMessage messageSent; + uint8_t messagesSent = 0; + + + SECTION("BasicTest") { + // Subscribe for message generation on update. + REQUIRE(poolOwner->subscribeWrapperSetUpdate() == retval::CATCH_OK); + // Subscribe for an update message. + poolOwner->dataset.setChanged(true); + // Now the update message should be generated. + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent() == true); + + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_SET)); + + // Should have been reset. + CHECK(poolOwner->dataset.hasChanged() == false); + // Set changed again, result should be the same. + poolOwner->dataset.setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_SET)); + + // now subscribe for set update HK as well. + REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK); + poolOwner->dataset.setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 2); + // first message sent should be the update notification, considering + // the internal list is a vector checked in insertion order. + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_SET)); + + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::HK_REPORT)); + // clear message to avoid memory leak, our mock won't do it for us (yet) + CommandMessageCleaner::clearCommandMessage(&messageSent); + } + + SECTION("AdvancedTests") { + // we need to reset the subscription list because the pool owner + // is a global object. + poolOwner->resetSubscriptionList(); + // Subscribe for variable update as well + REQUIRE(not poolOwner->dataset.hasChanged()); + REQUIRE(poolOwner->subscribeWrapperVariableUpdate(lpool::uint8VarId) == + retval::CATCH_OK); + lp_var_t* poolVar = dynamic_cast*>( + poolOwner->getPoolObjectHandle(lpool::uint8VarId)); + REQUIRE(poolVar != nullptr); + poolVar->setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + + // Check update notification was sent. + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 1); + // Should have been reset. + CHECK(poolVar->hasChanged() == false); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE)); + + // now subscribe for the dataset update (HK and update) again + REQUIRE(poolOwner->subscribeWrapperSetUpdate() == retval::CATCH_OK); + REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK); + + poolOwner->dataset.setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + // now two messages should be sent. + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 2); + mqMock->clearMessages(true); + + poolOwner->dataset.setChanged(true); + poolVar->setChanged(true); + REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); + // now three messages should be sent. + REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); + CHECK(messagesSent == 3); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE)); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_NOTIFICATION_SET)); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::HK_REPORT)); + CommandMessageCleaner::clearCommandMessage(&messageSent); + REQUIRE(mqMock->receiveMessage(&messageSent) == + static_cast(MessageQueueIF::EMPTY)); + } +} + diff --git a/unittest/tests/datapoollocal/LocalPoolOwnerBase.h b/unittest/tests/datapoollocal/LocalPoolOwnerBase.h new file mode 100644 index 00000000..aaccc90e --- /dev/null +++ b/unittest/tests/datapoollocal/LocalPoolOwnerBase.h @@ -0,0 +1,206 @@ +#ifndef FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ +#define FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lpool { +static constexpr lp_id_t uint8VarId = 0; +static constexpr lp_id_t floatVarId = 1; +static constexpr lp_id_t uint32VarId = 2; +static constexpr lp_id_t uint16Vec3Id = 3; +static constexpr lp_id_t int64Vec2Id = 4; + +static constexpr uint32_t testSetId = 0; +static constexpr uint8_t dataSetMaxVariables = 10; +static const sid_t testSid = sid_t(objects::TEST_LOCAL_POOL_OWNER_BASE, + testSetId); +} + + +class LocalPoolTestDataSet: public LocalDataSet { +public: + LocalPoolTestDataSet(HasLocalDataPoolIF* owner, uint32_t setId): + LocalDataSet(owner, setId, lpool::dataSetMaxVariables) { + } + + ReturnValue_t assignPointers() { + PoolVariableIF** rawVarArray = getContainer(); + localPoolVarUint8 = dynamic_cast*>(rawVarArray[0]); + localPoolVarFloat = dynamic_cast*>(rawVarArray[1]); + localPoolUint16Vec = dynamic_cast*>( + rawVarArray[2]); + if(localPoolVarUint8 == nullptr or localPoolVarFloat == nullptr or + localPoolUint16Vec == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + return HasReturnvaluesIF::RETURN_OK; + } + + lp_var_t* localPoolVarUint8 = nullptr; + lp_var_t* localPoolVarFloat = nullptr; + lp_vec_t* localPoolUint16Vec = nullptr; + +private: +}; + + +class LocalPoolOwnerBase: public SystemObject, public HasLocalDataPoolIF { +public: + LocalPoolOwnerBase( + object_id_t objectId = objects::TEST_LOCAL_POOL_OWNER_BASE): + SystemObject(objectId), hkManager(this, messageQueue), + dataset(this, lpool::testSetId) { + messageQueue = new MessageQueueMockBase(); + } + + ~LocalPoolOwnerBase() { + QueueFactory::instance()->deleteMessageQueue(messageQueue); + } + + object_id_t getObjectId() const override { + return SystemObject::getObjectId(); + } + + ReturnValue_t initializeHkManager() { + if(not initialized) { + initialized = true; + return hkManager.initialize(messageQueue); + } + return HasReturnvaluesIF::RETURN_OK; + } + + ReturnValue_t initializeHkManagerAfterTaskCreation() { + if(not initializedAfterTaskCreation) { + initializedAfterTaskCreation = true; + return hkManager.initializeAfterTaskCreation(); + } + return HasReturnvaluesIF::RETURN_OK; + } + + /** Command queue for housekeeping messages. */ + MessageQueueId_t getCommandQueue() const override { + return messageQueue->getId(); + } + + // This is called by initializeAfterTaskCreation of the HK manager. + virtual ReturnValue_t initializeLocalDataPool( + localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) { + // Default initialization empty for now. + localDataPoolMap.emplace(lpool::uint8VarId, + new PoolEntry({0})); + localDataPoolMap.emplace(lpool::floatVarId, + new PoolEntry({0})); + localDataPoolMap.emplace(lpool::uint32VarId, + new PoolEntry({0})); + + localDataPoolMap.emplace(lpool::uint16Vec3Id, + new PoolEntry({0, 0, 0})); + localDataPoolMap.emplace(lpool::int64Vec2Id, + new PoolEntry({0, 0})); + return HasReturnvaluesIF::RETURN_OK; + } + + /** + * This function can be used by data pool consumers to retrieve a handle + * which allows subscriptions to dataset and variable updates. + * @return + */ + virtual ProvidesDataPoolSubscriptionIF* getSubscriptionInterface() override { + return &hkManager; + } + + virtual AccessPoolManagerIF* getAccessorHandle() override { + return &hkManager; + } + + uint32_t getPeriodicOperationFrequency() const override { + return 0; + } + + /** + * This function is used by the pool manager to get a valid dataset + * from a SID + * @param sid Corresponding structure ID + * @return + */ + virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override { + return &dataset; + } + + virtual LocalPoolObjectBase* getPoolObjectHandle( + lp_id_t localPoolId) override { + if(localPoolId == lpool::uint8VarId) { + return &testUint8; + } + else if(localPoolId == lpool::uint16Vec3Id) { + return &testUint16Vec; + } + else if(localPoolId == lpool::floatVarId) { + return &testFloat; + } + else if(localPoolId == lpool::int64Vec2Id) { + return &testInt64Vec; + } + else if(localPoolId == lpool::uint32VarId) { + return &testUint32; + } + else { + return &testUint8; + } + } + + MessageQueueMockBase* getMockQueueHandle() const { + return dynamic_cast(messageQueue); + } + + ReturnValue_t subscribeWrapperSetUpdate() { + return hkManager.subscribeForSetUpdateMessages(lpool::testSetId, + objects::NO_OBJECT, MessageQueueIF::NO_QUEUE, false); + } + + ReturnValue_t subscribeWrapperSetUpdateHk(bool diagnostics = false) { + return hkManager.subscribeForUpdatePackets(lpool::testSid, diagnostics, + false, objects::HK_RECEIVER_MOCK); + } + + ReturnValue_t subscribeWrapperVariableUpdate(lp_id_t localPoolId) { + return hkManager.subscribeForVariableUpdateMessages(localPoolId, + MessageQueueIF::NO_QUEUE, objects::NO_OBJECT, false); + } + + void resetSubscriptionList() { + hkManager.clearReceiversList(); + } + + LocalDataPoolManager hkManager; + LocalPoolTestDataSet dataset; +private: + + lp_var_t testUint8 = lp_var_t(this, lpool::uint8VarId, + &dataset); + lp_var_t testFloat = lp_var_t(this, lpool::floatVarId, + &dataset); + lp_var_t testUint32 = lp_var_t(this, lpool::uint32VarId); + + lp_vec_t testUint16Vec = lp_vec_t(this, + lpool::uint16Vec3Id, &dataset); + lp_vec_t testInt64Vec = lp_vec_t(this, + lpool::int64Vec2Id); + + MessageQueueIF* messageQueue = nullptr; + + bool initialized = false; + bool initializedAfterTaskCreation = false; + +}; + +#endif /* FSFW_UNITTEST_TESTS_DATAPOOLLOCAL_LOCALPOOLOWNERBASE_H_ */ diff --git a/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp b/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp new file mode 100644 index 00000000..2e4cb7ec --- /dev/null +++ b/unittest/tests/datapoollocal/LocalPoolVariableTest.cpp @@ -0,0 +1,123 @@ +#include "LocalPoolOwnerBase.h" + +#include +#include +#include + + +TEST_CASE("LocalPoolVariable" , "[LocPoolVarTest]") { + LocalPoolOwnerBase* poolOwner = objectManager-> + get(objects::TEST_LOCAL_POOL_OWNER_BASE); + REQUIRE(poolOwner != nullptr); + REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); + REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() + == retval::CATCH_OK); + + SECTION("Basic Tests") { + // very basic test. + lp_var_t testVariable = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint8VarId); + REQUIRE(testVariable.read() == retval::CATCH_OK); + CHECK(testVariable.value == 0); + testVariable.value = 5; + REQUIRE(testVariable.commit() == retval::CATCH_OK); + REQUIRE(testVariable.read() == retval::CATCH_OK); + REQUIRE(testVariable.value == 5); + CHECK(not testVariable.isValid()); + testVariable.setValid(true); + CHECK(testVariable.isValid()); + CHECK(testVariable.commit(true) == retval::CATCH_OK); + + testVariable.setReadWriteMode(pool_rwm_t::VAR_READ); + CHECK(testVariable.getReadWriteMode() == pool_rwm_t::VAR_READ); + testVariable.setReadWriteMode(pool_rwm_t::VAR_READ_WRITE); + + testVariable.setDataPoolId(22); + CHECK(testVariable.getDataPoolId() == 22); + testVariable.setDataPoolId(lpool::uint8VarId); + + testVariable.setChanged(true); + CHECK(testVariable.hasChanged()); + testVariable.setChanged(false); + + gp_id_t globPoolId(objects::TEST_LOCAL_POOL_OWNER_BASE, + lpool::uint8VarId); + lp_var_t testVariable2 = lp_var_t(globPoolId); + REQUIRE(testVariable2.read() == retval::CATCH_OK); + CHECK(testVariable2 == 5); + CHECK(testVariable == testVariable2); + testVariable = 10; + CHECK(testVariable != 5); + //CHECK(not testVariable != testVariable2); + uint8_t variableRaw = 0; + uint8_t* varPtr = &variableRaw; + size_t maxSize = testVariable.getSerializedSize(); + CHECK(maxSize == 1); + size_t serSize = 0; + CHECK(testVariable.serialize(&varPtr, &serSize, maxSize, + SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + CHECK(variableRaw == 10); + const uint8_t* varConstPtr = &variableRaw; + testVariable = 5; + CHECK(testVariable.deSerialize(&varConstPtr, &serSize, + SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + CHECK(testVariable == 10); + CHECK(testVariable != testVariable2); + CHECK(testVariable2 < testVariable); + CHECK(testVariable2 < 10); + CHECK(testVariable > 5); + CHECK(testVariable > testVariable2); + variableRaw = static_cast(testVariable2); + CHECK(variableRaw == 5); + + CHECK(testVariable == 10); + testVariable = testVariable2; + CHECK(testVariable == 5); + } + + SECTION("ErrorHandling") { + + // not try to use a local pool variable which does not exist + lp_var_t invalidVariable = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, 0xffffffff); + REQUIRE(invalidVariable.read() == + static_cast(localpool::POOL_ENTRY_NOT_FOUND)); + + REQUIRE(invalidVariable.commit() == + static_cast(localpool::POOL_ENTRY_NOT_FOUND)); + // now try to access with wrong type + lp_var_t invalidVariable2 = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint8VarId); + REQUIRE(invalidVariable2.read() == + static_cast(localpool::POOL_ENTRY_TYPE_CONFLICT)); + + lp_var_t readOnlyVar = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint8VarId, + nullptr, pool_rwm_t::VAR_READ); + REQUIRE(readOnlyVar.commit() == + static_cast(PoolVariableIF::INVALID_READ_WRITE_MODE)); + lp_var_t writeOnlyVar = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint8VarId, + nullptr, pool_rwm_t::VAR_WRITE); + REQUIRE(writeOnlyVar.read() == static_cast( + PoolVariableIF::INVALID_READ_WRITE_MODE)); + + lp_var_t uint32tVar = lp_var_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint32VarId); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::info << "LocalPoolVariable printout: " < OK + lp_var_t invalidObjectVar = lp_var_t( + 0xffffffff, lpool::uint8VarId); + gp_id_t globPoolId(0xffffffff, + lpool::uint8VarId); + lp_var_t invalidObjectVar2 = lp_var_t(globPoolId); + lp_var_t invalidObjectVar3 = lp_var_t(nullptr, + lpool::uint8VarId); + } + +} + + diff --git a/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp b/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp new file mode 100644 index 00000000..7c309bbb --- /dev/null +++ b/unittest/tests/datapoollocal/LocalPoolVectorTest.cpp @@ -0,0 +1,120 @@ +#include "LocalPoolOwnerBase.h" + +#include +#include +#include + +TEST_CASE("LocalPoolVector" , "[LocPoolVecTest]") { + LocalPoolOwnerBase* poolOwner = objectManager-> + get(objects::TEST_LOCAL_POOL_OWNER_BASE); + REQUIRE(poolOwner != nullptr); + REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); + REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() + == retval::CATCH_OK); + + SECTION("BasicTest") { + // very basic test. + lp_vec_t testVector = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint16Vec3Id); + REQUIRE(testVector.read() == retval::CATCH_OK); + testVector.value[0] = 5; + testVector.value[1] = 232; + testVector.value[2] = 32023; + + REQUIRE(testVector.commit(true) == retval::CATCH_OK); + CHECK(testVector.isValid()); + + testVector.value[0] = 0; + testVector.value[1] = 0; + testVector.value[2] = 0; + + CHECK(testVector.read() == retval::CATCH_OK); + CHECK(testVector.value[0] == 5); + CHECK(testVector.value[1] == 232); + CHECK(testVector.value[2] == 32023); + + CHECK(testVector[0] == 5); + + // This is invalid access, so the last value will be set instead. + // (we can't throw exceptions) + testVector[4] = 12; + CHECK(testVector[2] == 12); + CHECK(testVector.commit() == retval::CATCH_OK); + + // Use read-only reference. + const lp_vec_t& roTestVec = testVector; + uint16_t valueOne = roTestVec[0]; + CHECK(valueOne == 5); + + uint16_t lastVal = roTestVec[25]; + CHECK(lastVal == 12); + + size_t maxSize = testVector.getSerializedSize(); + CHECK(maxSize == 6); + + uint16_t serializedVector[3]; + uint8_t* vecPtr = reinterpret_cast(serializedVector); + size_t serSize = 0; + REQUIRE(testVector.serialize(&vecPtr, &serSize, + maxSize, SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + + CHECK(serSize == 6); + CHECK(serializedVector[0] == 5); + CHECK(serializedVector[1] == 232); + CHECK(serializedVector[2] == 12); + + maxSize = 1; + REQUIRE(testVector.serialize(&vecPtr, &serSize, + maxSize, SerializeIF::Endianness::MACHINE) == + static_cast(SerializeIF::BUFFER_TOO_SHORT)); + + serializedVector[0] = 16; + serializedVector[1] = 7832; + serializedVector[2] = 39232; + + const uint8_t* constVecPtr = reinterpret_cast( + serializedVector); + REQUIRE(testVector.deSerialize(&constVecPtr, &serSize, + SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + CHECK(testVector[0] == 16); + CHECK(testVector[1] == 7832); + CHECK(testVector[2] == 39232); + + serSize = 1; + REQUIRE(testVector.deSerialize(&constVecPtr, &serSize, + SerializeIF::Endianness::MACHINE) == + static_cast(SerializeIF::STREAM_TOO_SHORT)); + } + + SECTION("ErrorHandling") { + // not try to use a local pool variable which does not exist + lp_vec_t invalidVector = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, 0xffffffff); + REQUIRE(invalidVector.read() == + static_cast(localpool::POOL_ENTRY_NOT_FOUND)); + REQUIRE(invalidVector.commit() == + static_cast(localpool::POOL_ENTRY_NOT_FOUND)); + + // now try to access with wrong type + lp_vec_t invalidVector2 = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint16Vec3Id); + REQUIRE(invalidVector2.read() == + static_cast(localpool::POOL_ENTRY_TYPE_CONFLICT)); + REQUIRE(invalidVector2.commit() == + static_cast(localpool::POOL_ENTRY_TYPE_CONFLICT)); + + lp_vec_t writeOnlyVec = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint16Vec3Id, + nullptr, pool_rwm_t::VAR_WRITE); + REQUIRE(writeOnlyVec.read() == + static_cast(PoolVariableIF::INVALID_READ_WRITE_MODE)); + + lp_vec_t readOnlyVec = lp_vec_t( + objects::TEST_LOCAL_POOL_OWNER_BASE, lpool::uint16Vec3Id, + nullptr, pool_rwm_t::VAR_READ); + REQUIRE(readOnlyVec.commit() == + static_cast(PoolVariableIF::INVALID_READ_WRITE_MODE)); + } +} + + diff --git a/unittest/tests/mocks/HkReceiverMock.h b/unittest/tests/mocks/HkReceiverMock.h new file mode 100644 index 00000000..e7509c59 --- /dev/null +++ b/unittest/tests/mocks/HkReceiverMock.h @@ -0,0 +1,20 @@ +#ifndef FSFW_UNITTEST_TESTS_MOCKS_HKRECEIVERMOCK_H_ +#define FSFW_UNITTEST_TESTS_MOCKS_HKRECEIVERMOCK_H_ + +#include +#include + +class HkReceiverMock: public SystemObject, public AcceptsHkPacketsIF { +public: + HkReceiverMock(object_id_t objectId): SystemObject(objectId) { + + } + + MessageQueueId_t getHkQueue() const { + return MessageQueueIF::NO_QUEUE; + } +}; + + + +#endif /* FSFW_UNITTEST_TESTS_MOCKS_HKRECEIVERMOCK_H_ */ diff --git a/unittest/tests/mocks/MessageQueueMockBase.h b/unittest/tests/mocks/MessageQueueMockBase.h new file mode 100644 index 00000000..7b810b41 --- /dev/null +++ b/unittest/tests/mocks/MessageQueueMockBase.h @@ -0,0 +1,121 @@ +#ifndef FSFW_UNITTEST_TESTS_MOCKS_MESSAGEQUEUEMOCKBASE_H_ +#define FSFW_UNITTEST_TESTS_MOCKS_MESSAGEQUEUEMOCKBASE_H_ + +#include +#include +#include +#include + +#include + +class MessageQueueMockBase: public MessageQueueIF { +public: + MessageQueueId_t myQueueId = tconst::testQueueId; + uint8_t messageSentCounter = 0; + bool defaultDestSet = false; + bool messageSent = false; + + + bool wasMessageSent(uint8_t* messageSentCounter = nullptr, + bool resetCounter = true) { + bool tempMessageSent = messageSent; + messageSent = false; + if(messageSentCounter != nullptr) { + *messageSentCounter = this->messageSentCounter; + } + if(resetCounter) { + this->messageSentCounter = 0; + } + return tempMessageSent; + } + + virtual ReturnValue_t reply( MessageQueueMessageIF* message ) { + //messageSent = true; + //lastMessage = *(dynamic_cast(message)); + return sendMessage(myQueueId, message); + return HasReturnvaluesIF::RETURN_OK; + }; + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message, + MessageQueueId_t *receivedFrom) { + return receiveMessage(message); + } + virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) { + if(messagesSentQueue.empty()) { + return MessageQueueIF::EMPTY; + } + + std::memcpy(message->getBuffer(), messagesSentQueue.front().getBuffer(), + message->getMessageSize()); + messagesSentQueue.pop(); + return HasReturnvaluesIF::RETURN_OK; + } + virtual ReturnValue_t flush(uint32_t* count) { + return HasReturnvaluesIF::RETURN_OK; + } + virtual MessageQueueId_t getLastPartner() const { + return myQueueId; + } + virtual MessageQueueId_t getId() const { + return myQueueId; + } + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, + MessageQueueMessageIF* message, MessageQueueId_t sentFrom, + bool ignoreFault = false ) { + //messageSent = true; + //lastMessage = *(dynamic_cast(message)); + //return HasReturnvaluesIF::RETURN_OK; + return sendMessage(sendTo, message); + } + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, + MessageQueueId_t sentFrom, bool ignoreFault = false ) { + //messageSent = true; + //lastMessage = *(dynamic_cast(message)); + //return HasReturnvaluesIF::RETURN_OK; + return sendMessage(myQueueId, message); + } + virtual ReturnValue_t sendToDefault( MessageQueueMessageIF* message ) { + //messageSent = true; + //lastMessage = *(dynamic_cast(message)); + return sendMessage(myQueueId, message); + } + virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo, + MessageQueueMessageIF* message, bool ignoreFault = false ) override { + messageSent = true; + messageSentCounter++; + MessageQueueMessage& messageRef = *( + dynamic_cast(message)); + messagesSentQueue.push(messageRef); + return HasReturnvaluesIF::RETURN_OK; + } + virtual void setDefaultDestination(MessageQueueId_t defaultDestination) { + myQueueId = defaultDestination; + defaultDestSet = true; + } + + virtual MessageQueueId_t getDefaultDestination() const { + return myQueueId; + } + virtual bool isDefaultDestinationSet() const { + return defaultDestSet; + } + + void clearMessages(bool clearCommandMessages = true) { + while(not messagesSentQueue.empty()) { + if(clearCommandMessages) { + CommandMessage message; + std::memcpy(message.getBuffer(), + messagesSentQueue.front().getBuffer(), + message.getMessageSize()); + message.clear(); + } + messagesSentQueue.pop(); + } + } + +private: + std::queue messagesSentQueue; + //MessageQueueMessage lastMessage; +}; + + +#endif /* FSFW_UNITTEST_TESTS_MOCKS_MESSAGEQUEUEMOCKBASE_H_ */ diff --git a/unittest/tests/storagemanager/TestNewAccessor.cpp b/unittest/tests/storagemanager/TestNewAccessor.cpp index 7bd0dee2..10d05c6b 100644 --- a/unittest/tests/storagemanager/TestNewAccessor.cpp +++ b/unittest/tests/storagemanager/TestNewAccessor.cpp @@ -1,161 +1,161 @@ -//#include -//#include -//#include "../../core/CatchDefinitions.h" -//#include -// -//TEST_CASE( "New Accessor" , "[NewAccessor]") { -// uint16_t numberOfElements[1] = {1}; -// uint16_t sizeofElements[1] = {10}; -// LocalPool<1> SimplePool = LocalPool<1>(0, sizeofElements, numberOfElements); -// std::array testDataArray; -// std::array receptionArray; -// store_address_t testStoreId; -// ReturnValue_t result = retval::CATCH_FAILED; -// -// for(size_t i = 0; i < testDataArray.size(); i++) { -// testDataArray[i] = i; -// } -// size_t size = 10; -// -// SECTION ("Simple tests getter functions") { -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// auto resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// resultPair.second.getDataCopy(receptionArray.data(), 20); -// CHECK(resultPair.second.getId() == testStoreId); -// CHECK(resultPair.second.size() == 10); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// -// std::copy(resultPair.second.data(), resultPair.second.data() + -// resultPair.second.size(), receptionArray.data()); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// -// { -// auto resultPairLoc = SimplePool.getData(testStoreId); -// REQUIRE(resultPairLoc.first == retval::CATCH_OK); -// // data should be deleted when accessor goes out of scope. -// } -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); -// -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// { -// ConstStorageAccessor constAccessor(testStoreId); -// result = SimplePool.getData(testStoreId, constAccessor); -// REQUIRE(result == retval::CATCH_OK); -// constAccessor.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// // likewise, data should be deleted when accessor gets out of scope. -// } -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); -// -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// { -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// resultPair.second.release(); -// // now data should not be deleted anymore -// } -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// resultPair.second.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// } -// -// -// SECTION("Simple tests modify functions") { -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// { -// StorageAccessor accessor(testStoreId); -// result = SimplePool.modifyData(testStoreId, accessor); -// REQUIRE(result == retval::CATCH_OK); -// CHECK(accessor.getId() == testStoreId); -// CHECK(accessor.size() == 10); -// accessor.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// std::copy(accessor.data(), accessor.data() + -// accessor.size(), receptionArray.data()); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// // data should be deleted when accessor goes out of scope -// } -// auto resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); -// -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// { -// auto resultPairLoc = SimplePool.modifyData(testStoreId); -// REQUIRE(resultPairLoc.first == retval::CATCH_OK); -// CHECK(resultPairLoc.second.getId() == testStoreId); -// CHECK(resultPairLoc.second.size() == 10); -// resultPairLoc.second.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// std::copy(resultPairLoc.second.data(), resultPairLoc.second.data() + -// resultPairLoc.second.size(), receptionArray.data()); -// for(size_t i = 0; i < size; i++) { -// CHECK(receptionArray[i] == i ); -// } -// resultPairLoc.second.release(); -// // data should not be deleted when accessor goes out of scope -// } -// resultPair = SimplePool.getData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// } -// -// -// SECTION("Write tests") { -// result = SimplePool.addData(&testStoreId, testDataArray.data(), size); -// REQUIRE(result == retval::CATCH_OK); -// { -// auto resultPair = SimplePool.modifyData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// testDataArray[9] = 42; -// resultPair.second.write(testDataArray.data(), 10, 0); -// // now data should not be deleted -// resultPair.second.release(); -// } -// auto resultConstPair = SimplePool.getData(testStoreId); -// REQUIRE(resultConstPair.first == retval::CATCH_OK); -// -// resultConstPair.second.getDataCopy(receptionArray.data(), 10); -// for(size_t i = 0; i < size-1; i++) { -// CHECK(receptionArray[i] == i ); -// } -// CHECK(receptionArray[9] == 42 ); -// -// auto resultPair = SimplePool.modifyData(testStoreId); -// REQUIRE(resultPair.first == retval::CATCH_OK); -// result = resultPair.second.write(testDataArray.data(), 20, 0); -// REQUIRE(result == retval::CATCH_FAILED); -// result = resultPair.second.write(testDataArray.data(), 10, 5); -// REQUIRE(result == retval::CATCH_FAILED); -// -// memset(testDataArray.data(), 42, 5); -// result = resultPair.second.write(testDataArray.data(), 5, 5); -// REQUIRE(result == retval::CATCH_OK); -// resultConstPair = SimplePool.getData(testStoreId); -// resultPair.second.getDataCopy(receptionArray.data(), 20); -// for(size_t i = 5; i < 10; i++) { -// CHECK(receptionArray[i] == 42 ); -// } -// -// } -//} +#include +#include +#include +#include +#include + +TEST_CASE( "New Accessor" , "[NewAccessor]") { + LocalPool::LocalPoolConfig poolCfg = {{1, 10}}; + LocalPool SimplePool = LocalPool(0, poolCfg); + std::array testDataArray; + std::array receptionArray; + store_address_t testStoreId; + ReturnValue_t result = retval::CATCH_FAILED; + + for(size_t i = 0; i < testDataArray.size(); i++) { + testDataArray[i] = i; + } + size_t size = 10; + + SECTION ("Simple tests getter functions") { + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + auto resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + resultPair.second.getDataCopy(receptionArray.data(), 20); + CHECK(resultPair.second.getId() == testStoreId); + CHECK(resultPair.second.size() == 10); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + + std::copy(resultPair.second.data(), resultPair.second.data() + + resultPair.second.size(), receptionArray.data()); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + + { + auto resultPairLoc = SimplePool.getData(testStoreId); + REQUIRE(resultPairLoc.first == retval::CATCH_OK); + // data should be deleted when accessor goes out of scope. + } + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); + + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + { + ConstStorageAccessor constAccessor(testStoreId); + result = SimplePool.getData(testStoreId, constAccessor); + REQUIRE(result == retval::CATCH_OK); + constAccessor.getDataCopy(receptionArray.data(), 20); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + // likewise, data should be deleted when accessor gets out of scope. + } + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); + + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + { + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + resultPair.second.release(); + // now data should not be deleted anymore + } + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + resultPair.second.getDataCopy(receptionArray.data(), 20); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + } + + + SECTION("Simple tests modify functions") { + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + { + StorageAccessor accessor(testStoreId); + result = SimplePool.modifyData(testStoreId, accessor); + REQUIRE(result == retval::CATCH_OK); + CHECK(accessor.getId() == testStoreId); + CHECK(accessor.size() == 10); + accessor.getDataCopy(receptionArray.data(), 20); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + std::copy(accessor.data(), accessor.data() + + accessor.size(), receptionArray.data()); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + // data should be deleted when accessor goes out of scope + } + auto resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST); + + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + { + auto resultPairLoc = SimplePool.modifyData(testStoreId); + REQUIRE(resultPairLoc.first == retval::CATCH_OK); + CHECK(resultPairLoc.second.getId() == testStoreId); + CHECK(resultPairLoc.second.size() == 10); + resultPairLoc.second.getDataCopy(receptionArray.data(), 20); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + std::copy(resultPairLoc.second.data(), resultPairLoc.second.data() + + resultPairLoc.second.size(), receptionArray.data()); + for(size_t i = 0; i < size; i++) { + CHECK(receptionArray[i] == i ); + } + resultPairLoc.second.release(); + // data should not be deleted when accessor goes out of scope + } + resultPair = SimplePool.getData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + } + + + SECTION("Write tests") { + result = SimplePool.addData(&testStoreId, testDataArray.data(), size); + REQUIRE(result == retval::CATCH_OK); + { + auto resultPair = SimplePool.modifyData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + testDataArray[9] = 42; + resultPair.second.write(testDataArray.data(), 10, 0); + // now data should not be deleted + resultPair.second.release(); + } + auto resultConstPair = SimplePool.getData(testStoreId); + REQUIRE(resultConstPair.first == retval::CATCH_OK); + + resultConstPair.second.getDataCopy(receptionArray.data(), 10); + for(size_t i = 0; i < size-1; i++) { + CHECK(receptionArray[i] == i ); + } + CHECK(receptionArray[9] == 42 ); + + auto resultPair = SimplePool.modifyData(testStoreId); + REQUIRE(resultPair.first == retval::CATCH_OK); + result = resultPair.second.write(testDataArray.data(), 20, 0); + REQUIRE(result == retval::CATCH_FAILED); + result = resultPair.second.write(testDataArray.data(), 10, 5); + REQUIRE(result == retval::CATCH_FAILED); + + std::memset(testDataArray.data(), 42, 5); + result = resultPair.second.write(testDataArray.data(), 5, 5); + REQUIRE(result == retval::CATCH_OK); + resultConstPair = SimplePool.getData(testStoreId); + resultPair.second.getDataCopy(receptionArray.data(), 20); + for(size_t i = 5; i < 10; i++) { + CHECK(receptionArray[i] == 42 ); + } + + } +} diff --git a/unittest/tests/storagemanager/TestPool.cpp b/unittest/tests/storagemanager/TestPool.cpp index dcfb6c03..50bde01a 100644 --- a/unittest/tests/storagemanager/TestPool.cpp +++ b/unittest/tests/storagemanager/TestPool.cpp @@ -8,8 +8,6 @@ TEST_CASE( "Local Pool Simple Tests [1 Pool]" , "[TestPool]") { -// uint16_t numberOfElements[1] = {1}; -// uint16_t sizeofElements[1] = {10}; LocalPool::LocalPoolConfig config = {{1, 10}}; LocalPool simplePool(0, config); std::array testDataArray; diff --git a/unittest/user/CMakeLists.txt b/unittest/user/CMakeLists.txt index 6ec314c3..722cc424 100644 --- a/unittest/user/CMakeLists.txt +++ b/unittest/user/CMakeLists.txt @@ -13,7 +13,19 @@ cmake_minimum_required(VERSION 3.13) # set(CMAKE_VERBOSE TRUE) -set(CMAKE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildsystem/cmake") +set(CMAKE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +option(TMTC_TEST "Build binary for manual or automatic TMTC tests" FALSE) +option(GENERATE_COVERAGE + "Specify whether coverage data is generated with GCOV" + TRUE +) + +if(TMTC_TEST) + set(LINK_CATCH2 FALSE) +else() + set(LINK_CATCH2 TRUE) +endif() # Tests can be built with the Host OSAL or with the Linux OSAL. if(NOT OS_FSFW) @@ -53,6 +65,7 @@ set(FSFW_PATH fsfw) set(CATCH2_PATH Catch2) set(FSFW_TESTS_PATH fsfw/unittest) set(TEST_SETUP_PATH unittest) +set(TMTC_TEST_PATH tests) # Analyse different OS and architecture/target options and # determine BSP_PATH @@ -71,6 +84,15 @@ else() endif() endif() +if(GENERATE_COVERAGE) + list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/cmake-modules) + if(CMAKE_COMPILER_IS_GNUCXX) + include(CodeCoverage) + # Add compile options on target base, we don't want coverage for Catch2 + # append_coverage_compiler_flags() + endif() +endif() + set(FSFW_CONFIG_PATH testcfg) ################################################################################ @@ -82,10 +104,16 @@ add_executable(${TARGET_NAME}) # Add subdirectories add_subdirectory(${FSFW_PATH}) -add_subdirectory(${CATCH2_PATH}) add_subdirectory(${FSFW_CONFIG_PATH}) -add_subdirectory(${FSFW_TESTS_PATH}) -add_subdirectory(${TEST_SETUP_PATH}) + +if(LINK_CATCH2) + add_subdirectory(${CATCH2_PATH}) + add_subdirectory(${FSFW_TESTS_PATH}) + add_subdirectory(${TEST_SETUP_PATH}) +else() + add_subdirectory(${TMTC_TEST_PATH}) +endif() + ################################################################################ # Post-Sources preparation @@ -94,9 +122,74 @@ add_subdirectory(${TEST_SETUP_PATH}) # Add libraries for all sources. target_link_libraries(${TARGET_NAME} PRIVATE ${LIB_FSFW_NAME} - ${CATCH2_TARGET} ) +if(LINK_CATCH2) + target_link_libraries(${TARGET_NAME} PRIVATE + ${CATCH2_TARGET} + ) +endif() + +if(GENERATE_COVERAGE) + if(CMAKE_COMPILER_IS_GNUCXX) + set(CODE_COVERAGE_VERBOSE TRUE) + include(CodeCoverage) + + # Remove quotes. + separate_arguments(COVERAGE_COMPILER_FLAGS + NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}" + ) + + # Add compile options manually, we don't want coverage for Catch2 + target_compile_options(${TARGET_NAME} PRIVATE + "${COVERAGE_COMPILER_FLAGS}" + ) + target_compile_options(${LIB_FSFW_NAME} PRIVATE + "${COVERAGE_COMPILER_FLAGS}" + ) + + # Exclude internal unittest from coverage for now. + if(WIN32) + set(GCOVR_ADDITIONAL_ARGS + "--exclude-throw-branches" + "--exclude-unreachable-branches" + ) + set(COVERAGE_EXCLUDES + "/c/msys64/mingw64/*" "Catch2" + "${CMAKE_CURRENT_SOURCE_DIR}/fsfw/unittest/internal" + ) + elseif(UNIX) + set(COVERAGE_EXCLUDES + "/usr/include/*" "/usr/bin/*" "Catch2/*" + "fsfw/unittest/internal/*" + ) + endif() + + target_link_options(${TARGET_NAME} PRIVATE + -fprofile-arcs + -ftest-coverage + ) + target_link_options(${LIB_FSFW_NAME} PRIVATE + -fprofile-arcs + -ftest-coverage + ) + + if(WIN32) + setup_target_for_coverage_gcovr_html( + NAME ${TARGET_NAME}_coverage + EXECUTABLE ${TARGET_NAME} + DEPENDENCIES ${TARGET_NAME} + ) + else() + setup_target_for_coverage_lcov( + NAME ${TARGET_NAME}_coverage + EXECUTABLE ${TARGET_NAME} + DEPENDENCIES ${TARGET_NAME} + ) + endif() + endif() +endif() + # Add include paths for all sources. target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} @@ -147,8 +240,7 @@ if(NOT CMAKE_SIZE) endif() endif() -add_custom_command( - TARGET ${TARGET_NAME} +add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND echo "Build directory: ${CMAKE_BINARY_DIR}" COMMAND echo "Target OSAL: ${OS_FSFW}" @@ -156,7 +248,7 @@ add_custom_command( COMMAND ${CMAKE_SIZE} ${TARGET_NAME}${FILE_SUFFIX} ) -include (${CMAKE_CURRENT_SOURCE_DIR}/buildsystem/cmake/BuildType.cmake) +include (${CMAKE_SCRIPT_PATH}/BuildType.cmake) set_build_type() diff --git a/unittest/user/testcfg/FSFWConfig.h b/unittest/user/testcfg/FSFWConfig.h index 6b0def90..ed86e6e1 100644 --- a/unittest/user/testcfg/FSFWConfig.h +++ b/unittest/user/testcfg/FSFWConfig.h @@ -4,16 +4,21 @@ #include #include -//! Used to determine whether C++ ostreams are used -//! Those can lead to code bloat. +//! Used to determine whether C++ ostreams are used which can increase +//! the binary size significantly. If this is disabled, +//! the C stdio functions can be used alternatively #define FSFW_CPP_OSTREAM_ENABLED 1 -//! Reduced printout to further decrease code size -//! Be careful, this also turns off most diagnostic prinouts! -#define FSFW_ENHANCED_PRINTOUT 0 +//! More FSFW related printouts depending on level. Useful for development. +#define FSFW_VERBOSE_LEVEL 1 -//! Can be used to enable additional debugging printouts for developing the FSFW -#define FSFW_PRINT_VERBOSITY_LEVEL 0 +//! Can be used to completely disable printouts, even the C stdio ones. +#if FSFW_CPP_OSTREAM_ENABLED == 0 && FSFW_VERBOSE_LEVEL == 0 + #define FSFW_DISABLE_PRINTOUT 0 +#endif + +//! Can be used to disable the ANSI color sequences for C stdio. +#define FSFW_COLORED_OUTPUT 1 //! If FSFW_OBJ_EVENT_TRANSLATION is set to one, //! additional output which requires the translation files translateObjects @@ -49,7 +54,9 @@ static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120; //! also determines how many commands a CSB service can handle in one cycle //! simulataneously. This will increase the required RAM for //! each CSB service ! -static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 3; +static constexpr uint8_t FSFW_CSB_FIFO_DEPTH = 6; + +static constexpr size_t FSFW_PRINT_BUFFER_SIZE = 124; } #endif /* CONFIG_FSFWCONFIG_H_ */ diff --git a/unittest/user/testcfg/objects/systemObjectList.h b/unittest/user/testcfg/objects/systemObjectList.h index 0e034aff..88b92131 100644 --- a/unittest/user/testcfg/objects/systemObjectList.h +++ b/unittest/user/testcfg/objects/systemObjectList.h @@ -9,7 +9,20 @@ namespace objects { enum sourceObjects: uint32_t { /* All addresses between start and end are reserved for the FSFW */ FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION, - FSFW_CONFIG_RESERVED_END = TM_STORE + FSFW_CONFIG_RESERVED_END = TM_STORE, + + CCSDS_DISTRIBUTOR = 10, + PUS_DISTRIBUTOR = 11, + TM_FUNNEL = 12, + + UDP_BRIDGE = 15, + UDP_POLLING_TASK = 16, + + TEST_ECHO_COM_IF = 20, + TEST_DEVICE = 21, + + HK_RECEIVER_MOCK = 22, + TEST_LOCAL_POOL_OWNER_BASE = 25 }; } diff --git a/unittest/user/unittest/CMakeLists.txt b/unittest/user/unittest/CMakeLists.txt new file mode 100644 index 00000000..ad6d4787 --- /dev/null +++ b/unittest/user/unittest/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(core) diff --git a/unittest/user/unittest/core/CMakeLists.txt b/unittest/user/unittest/core/CMakeLists.txt index d78f45f1..0989926c 100644 --- a/unittest/user/unittest/core/CMakeLists.txt +++ b/unittest/user/unittest/core/CMakeLists.txt @@ -5,3 +5,9 @@ target_sources(${TARGET_NAME} PRIVATE CatchSetup.cpp printChar.cpp ) + +if(CUSTOM_UNITTEST_RUNNER) + target_sources(${TARGET_NAME} PRIVATE + CatchRunner.cpp + ) +endif() \ No newline at end of file diff --git a/unittest/user/unittest/core/CatchDefinitions.cpp b/unittest/user/unittest/core/CatchDefinitions.cpp index 00daf015..bae02875 100644 --- a/unittest/user/unittest/core/CatchDefinitions.cpp +++ b/unittest/user/unittest/core/CatchDefinitions.cpp @@ -1,4 +1,5 @@ #include "CatchDefinitions.h" +#include #include StorageManagerIF* tglob::getIpcStoreHandle() { @@ -7,7 +8,9 @@ StorageManagerIF* tglob::getIpcStoreHandle() { } else { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "Global object manager uninitialized" << std::endl; -#endif +#else + sif::printError("Global object manager uninitialized\n\r"); +#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ return nullptr; } } diff --git a/unittest/user/unittest/core/CatchFactory.cpp b/unittest/user/unittest/core/CatchFactory.cpp index 3177212f..eabaa21d 100644 --- a/unittest/user/unittest/core/CatchFactory.cpp +++ b/unittest/user/unittest/core/CatchFactory.cpp @@ -1,11 +1,17 @@ +#include +#include #include "CatchFactory.h" #include #include - #include #include #include +#include +#include +#include +#include +#include /** * @brief Produces system objects. @@ -26,6 +32,9 @@ void Factory::produce(void) { new HealthTable(objects::HEALTH_TABLE); new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); + new LocalPoolOwnerBase (objects::TEST_LOCAL_POOL_OWNER_BASE); + new HkReceiverMock(objects::HK_RECEIVER_MOCK); + { PoolManager::LocalPoolConfig poolCfg = { {100, 16}, {50, 32}, {25, 64} , {15, 128}, {5, 1024} @@ -50,7 +59,23 @@ void Factory::produce(void) { } void Factory::setStaticFrameworkObjectIds() { + PusServiceBase::packetSource = objects::NO_OBJECT; + PusServiceBase::packetDestination = objects::NO_OBJECT; + CommandingServiceBase::defaultPacketSource = objects::NO_OBJECT; + CommandingServiceBase::defaultPacketDestination = objects::NO_OBJECT; + + VerificationReporter::messageReceiver = objects::PUS_SERVICE_1_VERIFICATION; + + DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT; + DeviceHandlerBase::rawDataReceiverId = objects::PUS_SERVICE_2_DEVICE_ACCESS; + + LocalDataPoolManager::defaultHkDestination = objects::HK_RECEIVER_MOCK; + + DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; + + TmPacketStored::timeStamperId = objects::NO_OBJECT; } + diff --git a/unittest/user/unittest/core/CatchRunner.cpp b/unittest/user/unittest/core/CatchRunner.cpp index 35c53cd4..886d641f 100644 --- a/unittest/user/unittest/core/CatchRunner.cpp +++ b/unittest/user/unittest/core/CatchRunner.cpp @@ -1,17 +1,16 @@ /** - * @file CatchSource.cpp + * @file CatchRunner.cpp * @brief Source file to compile catch framework. * @details All tests should be written in other files. * For eclipse console output, install ANSI Escape in Console * from the eclipse market place to get colored characters. */ -#ifndef NO_UNIT_TEST_FRAMEWORK +#include -#define CATCH_CONFIG_RUNNER -#include +#define CATCH_CONFIG_COLOUR_WINDOWS -#if CUSTOM_UNITTEST_RUNNER == 0 +#include extern int customSetup(); @@ -25,7 +24,3 @@ int main( int argc, char* argv[] ) { return result; } -#endif - - -#endif diff --git a/unittest/user/unittest/core/CatchSetup.cpp b/unittest/user/unittest/core/CatchSetup.cpp index c93cf032..bda31400 100644 --- a/unittest/user/unittest/core/CatchSetup.cpp +++ b/unittest/user/unittest/core/CatchSetup.cpp @@ -1,21 +1,20 @@ -#include +#include "CatchFactory.h" #include "CatchDefinitions.h" -#include #ifdef GCOV #include #endif -#include "../../objectmanager/ObjectManager.h" -#include "../../objectmanager/ObjectManagerIF.h" -#include "../../storagemanager/StorageManagerIF.h" -#include "../../serviceinterface/ServiceInterfaceStream.h" +#include +#include +#include +#include /* Global instantiations normally done in main.cpp */ /* Initialize Data Pool */ - +#if FSFW_CPP_OSTREAM_ENABLED == 1 namespace sif { /* Set up output streams */ ServiceInterfaceStream debug("DEBUG"); @@ -23,6 +22,7 @@ ServiceInterfaceStream info("INFO"); ServiceInterfaceStream error("ERROR"); ServiceInterfaceStream warning("WARNING"); } +#endif /* Global object manager */ ObjectManagerIF *objectManager; diff --git a/unittest/user/unittest/core/printChar.cpp b/unittest/user/unittest/core/printChar.cpp index 755a13b2..5d4f1b17 100644 --- a/unittest/user/unittest/core/printChar.cpp +++ b/unittest/user/unittest/core/printChar.cpp @@ -1,4 +1,4 @@ -#include +#include "printChar.h" #include void printChar(const char* character, bool errStream) {