diff --git a/datapoollocal/HasLocalDataPoolIF.h b/datapoollocal/HasLocalDataPoolIF.h index f8f4ef4c..7f1f202e 100644 --- a/datapoollocal/HasLocalDataPoolIF.h +++ b/datapoollocal/HasLocalDataPoolIF.h @@ -1,6 +1,8 @@ #ifndef FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ #define FSFW_DATAPOOLLOCAL_HASLOCALDATAPOOLIF_H_ +#include "locPoolDefinitions.h" + #include "../datapool/PoolEntryIF.h" #include "../ipc/MessageQueueSenderIF.h" #include "../housekeeping/HousekeepingMessage.h" @@ -9,11 +11,8 @@ class LocalDataPoolManager; class LocalPoolDataSetBase; +class LocalPoolObjectBase; -/** - * @brief Type definition for local pool entries. - */ -using lp_id_t = uint32_t; using LocalDataPool = std::map; using LocalDataPoolMapIter = LocalDataPool::iterator; @@ -44,7 +43,8 @@ public: virtual~ HasLocalDataPoolIF() {}; static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF; - static constexpr lp_id_t NO_POOL_ID = 0xffffffff; + + static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID; virtual object_id_t getObjectId() const = 0; @@ -78,6 +78,47 @@ public: */ virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) = 0; + /** + * Similar to the function above, but used to get a local pool variable + * handle. This is only needed for update notifications, so it is not + * defined as abstract. + * @param localPoolId + * @return + */ + virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) { + sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden" + << ". Returning nullptr!" << std::endl; + return nullptr; + } + + /** + * @brief This function will be called by the manager if an update + * notification is received. + * @details + * Can be overriden by the child class to handle changed datasets. + * @param sid + * @param storeId If a snapshot was requested, data will be located inside + * the IPC store with this store ID. + */ + virtual void handleChangedDataset(sid_t sid, + store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { + return; + } + + /** + * @brief This function will be called by the manager if an update + * notification is received. + * @details + * Can be overriden by the child class to handle changed pool IDs. + * @param sid + * @param storeId If a snapshot was requested, data will be located inside + * the IPC store with this store ID. + */ + virtual void handleChangedPoolVariable(lp_id_t poolId, + store_address_t storeId = storeId::INVALID_STORE_ADDRESS) { + return; + } + /* These function can be implemented by pool owner, as they are required * by the housekeeping message interface */ virtual ReturnValue_t addDataSet(sid_t sid) { diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp index c23f183b..f649a362 100644 --- a/datapoollocal/LocalDataPoolManager.cpp +++ b/datapoollocal/LocalDataPoolManager.cpp @@ -1,22 +1,25 @@ #include "LocalDataPoolManager.h" +#include "LocalPoolObjectBase.h" #include "LocalPoolDataSetBase.h" +#include "../housekeeping/HousekeepingPacketUpdate.h" #include "../housekeeping/HousekeepingSetPacket.h" #include "../housekeeping/AcceptsHkPacketsIF.h" + +#include "../timemanager/CCSDSTime.h" #include "../ipc/MutexFactory.h" #include "../ipc/MutexHelper.h" #include "../ipc/QueueFactory.h" -#include "../objectmanager/frameworkObjects.h" #include #include object_id_t LocalDataPoolManager::defaultHkDestination = - objects::PUS_SERVICE_3_HOUSEKEEPING; + objects::PUS_SERVICE_3_HOUSEKEEPING; LocalDataPoolManager::LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, bool appendValidityBuffer): - appendValidityBuffer(appendValidityBuffer) { + appendValidityBuffer(appendValidityBuffer) { if(owner == nullptr) { sif::error << "LocalDataPoolManager::LocalDataPoolManager: " << "Invalid supplied owner!" << std::endl; @@ -59,7 +62,7 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { } else { sif::error << "LocalDataPoolManager::LocalDataPoolManager: " - << "Default HK destination object is invalid!" << std::endl; + << "Default HK destination object is invalid!" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } } @@ -74,23 +77,22 @@ ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation( } ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() { - if(not mapInitialized) { - ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, - *this); - if(result == HasReturnvaluesIF::RETURN_OK) { - mapInitialized = true; - } - return result; - } - sif::warning << "HousekeepingManager: The map should only be initialized " - << "once!" << std::endl; - return HasReturnvaluesIF::RETURN_OK; + if(not mapInitialized) { + ReturnValue_t result = owner->initializeLocalDataPool(localPoolMap, + *this); + if(result == HasReturnvaluesIF::RETURN_OK) { + mapInitialized = true; + } + return result; + } + sif::warning << "HousekeepingManager: The map should only be initialized " + << "once!" << std::endl; + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::performHkOperation() { + ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; for(auto& receiver: hkReceiversMap) { - //HkReceiver* receiver = &hkReceiversIter.second; - switch(receiver.reportingType) { case(ReportingType::PERIODIC): { if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { @@ -100,8 +102,16 @@ ReturnValue_t LocalDataPoolManager::performHkOperation() { performPeriodicHkGeneration(receiver); break; } + case(ReportingType::UPDATE_HK): { + handleHkUpdate(receiver, status); + break; + } + case(ReportingType::UPDATE_NOTIFICATION): { + handleNotificationUpdate(receiver, status); + break; + } case(ReportingType::UPDATE_SNAPSHOT): { - // check whether data has changed and send messages in case it has. + handleNotificationSnapshot(receiver, status); break; } default: @@ -109,95 +119,441 @@ ReturnValue_t LocalDataPoolManager::performHkOperation() { return HasReturnvaluesIF::RETURN_FAILED; } } + resetHkUpdateResetHelper(); + return status; +} + +ReturnValue_t LocalDataPoolManager::handleHkUpdate(HkReceiver& receiver, + ReturnValue_t& status) { + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + // Update packets shall only be generated from datasets. + return HasReturnvaluesIF::RETURN_FAILED; + } + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( + receiver.dataId.sid); + if(dataSet->hasChanged()) { + // prepare and send update notification + ReturnValue_t result = generateHousekeepingPacket( + receiver.dataId.sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + } + handleChangeResetLogic(receiver.dataType, receiver.dataId, + dataSet); return HasReturnvaluesIF::RETURN_OK; } +ReturnValue_t LocalDataPoolManager::handleNotificationUpdate( + HkReceiver& receiver, ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle( + receiver.dataId.localPoolId); + if(poolObj == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(poolObj->hasChanged()) { + // prepare and send update notification. + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationVariableCommand( + ¬ification, receiver.dataId.localPoolId); + ReturnValue_t result = hkQueue->sendMessage( + receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } + + } + else { + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( + receiver.dataId.sid); + if(dataSet == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + if(dataSet->hasChanged()) { + // prepare and send update notification + CommandMessage notification; + HousekeepingMessage::setUpdateNotificationSetCommand( + ¬ification, receiver.dataId.sid); + ReturnValue_t result = hkQueue->sendMessage( + receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; + } + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, + receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot( + HkReceiver& receiver, ReturnValue_t& status) { + MarkChangedIF* toReset = nullptr; + // check whether data has changed and send messages in case it has. + if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { + LocalPoolObjectBase* poolObj = owner->getPoolObjectHandle( + receiver.dataId.localPoolId); + if(poolObj == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + if (not poolObj->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } + + // prepare and send update snapshot. + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + sizeof(cds), owner->getPoolObjectHandle( + receiver.dataId.localPoolId)); + + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotVariableCommand(¬ification, + receiver.dataId.localPoolId, storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, + ¬ification); + if (result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = poolObj; + } + else { + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle( + receiver.dataId.sid); + if(dataSet == nullptr) { + return HasReturnvaluesIF::RETURN_FAILED; + } + + if(not dataSet->hasChanged()) { + return HasReturnvaluesIF::RETURN_OK; + } + + // prepare and send update snapshot. + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::CDS_short cds; + CCSDSTime::convertToCcsds(&cds, &now); + HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + sizeof(cds), owner->getDataSetHandle(receiver.dataId.sid)); + + store_address_t storeId; + ReturnValue_t result = addUpdateToStore(updatePacket, storeId); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + CommandMessage notification; + HousekeepingMessage::setUpdateSnapshotSetCommand( + ¬ification, receiver.dataId.sid, storeId); + result = hkQueue->sendMessage(receiver.destinationQueue, ¬ification); + if(result != HasReturnvaluesIF::RETURN_OK) { + status = result; + } + toReset = dataSet; + + } + if(toReset != nullptr) { + handleChangeResetLogic(receiver.dataType, + receiver.dataId, toReset); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::addUpdateToStore( + HousekeepingPacketUpdate& updatePacket, store_address_t& storeId) { + size_t updatePacketSize = updatePacket.getSerializedSize(); + uint8_t *storePtr = nullptr; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + updatePacket.getSerializedSize(), &storePtr); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + size_t serializedSize = 0; + result = updatePacket.serialize(&storePtr, &serializedSize, + updatePacketSize, SerializeIF::Endianness::MACHINE); + return result;; +} + +void LocalDataPoolManager::handleChangeResetLogic( + DataType type, DataId dataId, MarkChangedIF* toReset) { + if(hkUpdateResetList == nullptr) { + // config error! + return; + } + + for(auto& changeInfo: *hkUpdateResetList) { + if(changeInfo.dataType != type) { + continue; + } + if((changeInfo.dataType == DataType::DATA_SET) and + (changeInfo.dataId.sid != dataId.sid)) { + continue; + } + if((changeInfo.dataType == DataType::LOCAL_POOL_VARIABLE) and + (changeInfo.dataId.localPoolId != dataId.localPoolId)) { + continue; + } + + if(changeInfo.updateCounter <= 1) { + toReset->setChanged(false); + } + if(changeInfo.currentUpdateCounter == 0) { + toReset->setChanged(false); + } + else { + changeInfo.currentUpdateCounter--; + } + return; + } +} + +void LocalDataPoolManager::resetHkUpdateResetHelper() { + if(hkUpdateResetList == nullptr) { + return; + } + + for(auto& changeInfo: *hkUpdateResetList) { + changeInfo.currentUpdateCounter = changeInfo.updateCounter; + } +} + ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid, - bool enableReporting, float collectionInterval, bool isDiagnostics, - object_id_t packetDestination) { - AcceptsHkPacketsIF* hkReceiverObject = - objectManager->get(packetDestination); - if(hkReceiverObject == nullptr) { - sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" - << " Invalid receiver!"<< std::endl; - return HasReturnvaluesIF::RETURN_OK; - } + bool enableReporting, float collectionInterval, bool isDiagnostics, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + objectManager->get(packetDestination); + if(hkReceiverObject == nullptr) { + sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" + << " Invalid receiver!"<< std::endl; + return HasReturnvaluesIF::RETURN_OK; + } - struct HkReceiver hkReceiver; - hkReceiver.dataId.sid = sid; - hkReceiver.reportingType = ReportingType::PERIODIC; - hkReceiver.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 = owner->getDataSetHandle(sid); + if(dataSet != nullptr) { + dataSet->setReportingEnabled(enableReporting); + dataSet->setDiagnostic(isDiagnostics); + dataSet->initializePeriodicHelper(collectionInterval, + owner->getPeriodicOperationFrequency(), isDiagnostics); + } - hkReceiversMap.push_back(hkReceiver); - return HasReturnvaluesIF::RETURN_OK; + hkReceiversMap.push_back(hkReceiver); + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t LocalDataPoolManager::subscribeForUpdatePackets(sid_t sid, + bool isDiagnostics, bool reportingEnabled, + object_id_t packetDestination) { + AcceptsHkPacketsIF* hkReceiverObject = + objectManager->get(packetDestination); + if(hkReceiverObject == nullptr) { + sif::error << "LocalDataPoolManager::subscribeForPeriodicPacket:" + << " Invalid receiver!"<< std::endl; + return HasReturnvaluesIF::RETURN_OK; + } + + struct HkReceiver hkReceiver; + hkReceiver.dataId.sid = sid; + hkReceiver.reportingType = ReportingType::UPDATE_HK; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.destinationQueue = hkReceiverObject->getHkQueue(); + + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(dataSet != nullptr) { + dataSet->setReportingEnabled(true); + dataSet->setDiagnostic(isDiagnostics); + } + + hkReceiversMap.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessages( + const uint32_t setId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::DATA_SET; + hkReceiver.dataId.sid = sid_t(this->getOwner()->getObjectId(), setId); + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } + + hkReceiversMap.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessages( + const lp_id_t localPoolId, object_id_t destinationObject, + MessageQueueId_t targetQueueId, bool generateSnapshot) { + struct HkReceiver hkReceiver; + hkReceiver.dataType = DataType::LOCAL_POOL_VARIABLE; + hkReceiver.dataId.localPoolId = localPoolId; + hkReceiver.destinationQueue = targetQueueId; + hkReceiver.objectId = destinationObject; + if(generateSnapshot) { + hkReceiver.reportingType = ReportingType::UPDATE_SNAPSHOT; + } + else { + hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; + } + + hkReceiversMap.push_back(hkReceiver); + + handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); + return HasReturnvaluesIF::RETURN_OK; +} + +void LocalDataPoolManager::handleHkUpdateResetListInsertion(DataType dataType, + DataId dataId) { + if(hkUpdateResetList == nullptr) { + hkUpdateResetList = new std::vector(); + } + + for(auto& updateResetStruct: *hkUpdateResetList) { + if(dataType == DataType::DATA_SET) { + if(updateResetStruct.dataId.sid == dataId.sid) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + else { + if(updateResetStruct.dataId.localPoolId == dataId.localPoolId) { + updateResetStruct.updateCounter++; + updateResetStruct.currentUpdateCounter++; + return; + } + } + + } + HkUpdateResetHelper hkUpdateResetHelper; + hkUpdateResetHelper.currentUpdateCounter = 1; + hkUpdateResetHelper.updateCounter = 1; + hkUpdateResetHelper.dataType = dataType; + if(dataType == DataType::DATA_SET) { + hkUpdateResetHelper.dataId.sid = dataId.sid; + } + else { + hkUpdateResetHelper.dataId.localPoolId = dataId.localPoolId; + } + hkUpdateResetList->push_back(hkUpdateResetHelper); } ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( - CommandMessage* message) { + 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; + result = togglePeriodicGeneration(sid, true, true); + break; } case(HousekeepingMessage::DISABLE_PERIODIC_DIAGNOSTICS_GENERATION): { - result = togglePeriodicGeneration(sid, false, true); - break; + result = togglePeriodicGeneration(sid, false, true); + break; } case(HousekeepingMessage::ENABLE_PERIODIC_HK_REPORT_GENERATION): { - result = togglePeriodicGeneration(sid, true, false); - break; + result = togglePeriodicGeneration(sid, true, false); + break; } case(HousekeepingMessage::DISABLE_PERIODIC_HK_REPORT_GENERATION): { - result = togglePeriodicGeneration(sid, false, false); - break; + result = togglePeriodicGeneration(sid, false, false); + break; } case(HousekeepingMessage::REPORT_DIAGNOSTICS_REPORT_STRUCTURES): - return generateSetStructurePacket(sid, true); + return generateSetStructurePacket(sid, true); case(HousekeepingMessage::REPORT_HK_REPORT_STRUCTURES): - return generateSetStructurePacket(sid, false); + 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; + float newCollIntvl = 0; + HousekeepingMessage::getCollectionIntervalModificationCommand(message, + &newCollIntvl); + if(command == HousekeepingMessage:: + MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) { + result = changeCollectionInterval(sid, newCollIntvl, true); + } + else { + result = changeCollectionInterval(sid, newCollIntvl, false); + } + break; } case(HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT): case(HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT): { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT - and dataSet->isDiagnostics()) { - return WRONG_HK_PACKET_TYPE; - } - else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT - and not dataSet->isDiagnostics()) { - return WRONG_HK_PACKET_TYPE; - } - return generateHousekeepingPacket(HousekeepingMessage::getSid(message), - dataSet, true); + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(command == HousekeepingMessage::GENERATE_ONE_PARAMETER_REPORT + and dataSet->isDiagnostics()) { + return WRONG_HK_PACKET_TYPE; + } + else if(command == HousekeepingMessage::GENERATE_ONE_DIAGNOSTICS_REPORT + and not dataSet->isDiagnostics()) { + return WRONG_HK_PACKET_TYPE; + } + return generateHousekeepingPacket(HousekeepingMessage::getSid(message), + dataSet, true); + } + + // Notification handling. + case(HousekeepingMessage::UPDATE_NOTIFICATION_SET): { + owner->handleChangedDataset(sid); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE): { + lp_id_t locPoolId = HousekeepingMessage:: + getUpdateNotificationVariableCommand(message); + owner->handleChangedPoolVariable(locPoolId); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_SET): { + store_address_t storeId; + HousekeepingMessage::getUpdateSnapshotSetCommand(message, &storeId); + owner->handleChangedDataset(sid, storeId); + return HasReturnvaluesIF::RETURN_OK; + } + case(HousekeepingMessage::UPDATE_SNAPSHOT_VARIABLE): { + store_address_t storeId; + lp_id_t localPoolId = HousekeepingMessage:: + getUpdateSnapshotVariableCommand(message, &storeId); + owner->handleChangedPoolVariable(localPoolId, storeId); + return HasReturnvaluesIF::RETURN_OK; } default: @@ -205,30 +561,30 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage( } CommandMessage reply; - if(result != HasReturnvaluesIF::RETURN_OK) { - HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); - } - else { - HousekeepingMessage::setHkRequestSuccessReply(&reply, sid); - } - hkQueue->sendMessage(hkDestinationId, &reply); - return result; + if(result != HasReturnvaluesIF::RETURN_OK) { + HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result); + } + else { + HousekeepingMessage::setHkRequestSuccessReply(&reply, sid); + } + hkQueue->sendMessage(hkDestinationId, &reply); + return result; } ReturnValue_t LocalDataPoolManager::printPoolEntry( - lp_id_t localPoolId) { - auto poolIter = localPoolMap.find(localPoolId); - if (poolIter == localPoolMap.end()) { - sif::debug << "HousekeepingManager::fechPoolEntry:" - << " Pool entry not found." << std::endl; - return POOL_ENTRY_NOT_FOUND; - } - poolIter->second->print(); - return HasReturnvaluesIF::RETURN_OK; + lp_id_t localPoolId) { + auto poolIter = localPoolMap.find(localPoolId); + if (poolIter == localPoolMap.end()) { + sif::debug << "HousekeepingManager::fechPoolEntry:" + << " Pool entry not found." << std::endl; + return POOL_ENTRY_NOT_FOUND; + } + poolIter->second->print(); + return HasReturnvaluesIF::RETURN_OK; } MutexIF* LocalDataPoolManager::getMutexHandle() { - return mutex; + return mutex; } HasLocalDataPoolIF* LocalDataPoolManager::getOwner() { @@ -236,51 +592,51 @@ HasLocalDataPoolIF* LocalDataPoolManager::getOwner() { } ReturnValue_t LocalDataPoolManager::generateHousekeepingPacket(sid_t sid, - LocalPoolDataSetBase* dataSet, bool forDownlink, - MessageQueueId_t destination) { - if(dataSet == nullptr) { - // Configuration error. - sif::warning << "HousekeepingManager::generateHousekeepingPacket:" - << " Set ID not found or dataset not assigned!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } + LocalPoolDataSetBase* dataSet, bool forDownlink, + MessageQueueId_t destination) { + if(dataSet == nullptr) { + // Configuration error. + sif::warning << "HousekeepingManager::generateHousekeepingPacket:" + << " Set ID not found or dataset not assigned!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } - store_address_t storeId; - HousekeepingPacketDownlink hkPacket(sid, dataSet); - size_t serializedSize = 0; - ReturnValue_t result = serializeHkPacketIntoStore(hkPacket, storeId, - forDownlink, &serializedSize); - if(result != HasReturnvaluesIF::RETURN_OK or serializedSize == 0) { - return result; - } + 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(dataSet->isDiagnostics()) { + HousekeepingMessage::setHkDiagnosticsReply(&hkMessage, sid, storeId); + } + else { + HousekeepingMessage::setHkReportReply(&hkMessage, sid, storeId); + } - if(hkQueue == nullptr) { - return QUEUE_OR_DESTINATION_NOT_SET; - } - if(destination == MessageQueueIF::NO_QUEUE) { - if(hkDestinationId == MessageQueueIF::NO_QUEUE) { - // error, all destinations invalid - return HasReturnvaluesIF::RETURN_FAILED; - } - destination = hkDestinationId; - } + if(hkQueue == nullptr) { + return QUEUE_OR_DESTINATION_NOT_SET; + } + if(destination == MessageQueueIF::NO_QUEUE) { + if(hkDestinationId == MessageQueueIF::NO_QUEUE) { + // error, all destinations invalid + return HasReturnvaluesIF::RETURN_FAILED; + } + destination = hkDestinationId; + } - return hkQueue->sendMessage(destination, &hkMessage); + return hkQueue->sendMessage(destination, &hkMessage); } ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( HousekeepingPacketDownlink& hkPacket, store_address_t& storeId, bool forDownlink, - size_t* serializedSize) { + size_t* serializedSize) { uint8_t* dataPtr = nullptr; const size_t maxSize = hkPacket.getSerializedSize(); ReturnValue_t result = ipcStore->getFreeElement(&storeId, @@ -290,8 +646,8 @@ ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore( } if(forDownlink) { - return hkPacket.serialize(&dataPtr, serializedSize, maxSize, - SerializeIF::Endianness::BIG); + return hkPacket.serialize(&dataPtr, serializedSize, maxSize, + SerializeIF::Endianness::BIG); } return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE); @@ -303,125 +659,124 @@ void LocalDataPoolManager::setNonDiagnosticIntervalFactor( } 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); + if(not dataSet->getReportingEnabled()) { + return; + } - if(dataSet->periodicHelper == nullptr) { - // Configuration error. - return; - } + if(dataSet->periodicHelper == nullptr) { + // Configuration error. + return; + } - if(not dataSet->periodicHelper->checkOpNecessary()) { - return; - } + if(not dataSet->periodicHelper->checkOpNecessary()) { + return; + } - ReturnValue_t result = generateHousekeepingPacket( - sid, dataSet, true); - if(result != HasReturnvaluesIF::RETURN_OK) { - // configuration error - sif::debug << "LocalDataPoolManager::performHkOperation:" - << "0x" << std::hex << std::setfill('0') << std::setw(8) - << owner->getObjectId() << " Error generating " - << "HK packet" << std::setfill(' ') << std::dec << std::endl; - } + ReturnValue_t result = generateHousekeepingPacket( + sid, dataSet, true); + if(result != HasReturnvaluesIF::RETURN_OK) { + // configuration error + sif::debug << "LocalDataPoolManager::performHkOperation:" + << "0x" << std::hex << std::setfill('0') << std::setw(8) + << owner->getObjectId() << " Error generating " + << "HK packet" << std::setfill(' ') << std::dec << std::endl; + } } ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, - bool enable, bool isDiagnostics) { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - if((dataSet->isDiagnostics() and not isDiagnostics) or - (not dataSet->isDiagnostics() and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } + bool enable, bool isDiagnostics) { + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if((dataSet->isDiagnostics() and not isDiagnostics) or + (not dataSet->isDiagnostics() and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } - if((dataSet->getReportingEnabled() and enable) or - (not dataSet->getReportingEnabled() and not enable)) { - return REPORTING_STATUS_UNCHANGED; - } + if((dataSet->getReportingEnabled() and enable) or + (not dataSet->getReportingEnabled() and not enable)) { + return REPORTING_STATUS_UNCHANGED; + } - dataSet->setReportingEnabled(enable); - return HasReturnvaluesIF::RETURN_OK; + dataSet->setReportingEnabled(enable); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, - float newCollectionInterval, bool isDiagnostics) { - LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); - bool targetIsDiagnostics = dataSet->isDiagnostics(); - if((targetIsDiagnostics and not isDiagnostics) or - (not targetIsDiagnostics and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } + float newCollectionInterval, bool isDiagnostics) { + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + bool targetIsDiagnostics = dataSet->isDiagnostics(); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } - if(dataSet->periodicHelper == nullptr) { - // config error - return PERIODIC_HELPER_INVALID; - } + if(dataSet->periodicHelper == nullptr) { + // config error + return PERIODIC_HELPER_INVALID; + } - dataSet->periodicHelper->changeCollectionInterval(newCollectionInterval); - return HasReturnvaluesIF::RETURN_OK; + dataSet->periodicHelper->changeCollectionInterval(newCollectionInterval); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, - bool isDiagnostics) { + bool isDiagnostics) { // Get and check dataset first. - LocalPoolDataSetBase* dataSet = dynamic_cast( - owner->getDataSetHandle(sid)); - if(dataSet == nullptr) { - sif::warning << "HousekeepingManager::generateHousekeepingPacket:" - << " Set ID not found" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } + LocalPoolDataSetBase* dataSet = owner->getDataSetHandle(sid); + if(dataSet == nullptr) { + sif::warning << "HousekeepingManager::generateHousekeepingPacket:" + << " Set ID not found" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } - bool targetIsDiagnostics = dataSet->isDiagnostics(); - if((targetIsDiagnostics and not isDiagnostics) or - (not targetIsDiagnostics and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } + bool targetIsDiagnostics = dataSet->isDiagnostics(); + if((targetIsDiagnostics and not isDiagnostics) or + (not targetIsDiagnostics and isDiagnostics)) { + return WRONG_HK_PACKET_TYPE; + } - bool valid = dataSet->isValid(); - bool reportingEnabled = dataSet->getReportingEnabled(); - float collectionInterval = - dataSet->periodicHelper->getCollectionIntervalInSeconds(); + bool valid = dataSet->isValid(); + bool reportingEnabled = dataSet->getReportingEnabled(); + float collectionInterval = + dataSet->periodicHelper->getCollectionIntervalInSeconds(); - // Generate set packet which can be serialized. - HousekeepingSetPacket setPacket = HousekeepingSetPacket(sid, - reportingEnabled, valid, collectionInterval, dataSet); - size_t expectedSize = setPacket.getSerializedSize(); - uint8_t* storePtr = nullptr; - store_address_t storeId; - ReturnValue_t result = ipcStore->getFreeElement(&storeId, - expectedSize,&storePtr); - if(result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "HousekeepingManager::generateHousekeepingPacket: " - << "Could not get free element from IPC store." << std::endl; - return result; - } + // Generate set packet which can be serialized. + HousekeepingSetPacket setPacket(sid, + reportingEnabled, valid, collectionInterval, dataSet); + size_t expectedSize = setPacket.getSerializedSize(); + uint8_t* storePtr = nullptr; + store_address_t storeId; + ReturnValue_t result = ipcStore->getFreeElement(&storeId, + expectedSize,&storePtr); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "HousekeepingManager::generateHousekeepingPacket: " + << "Could not get free element from IPC store." << std::endl; + return result; + } - // Serialize set packet into store. - size_t size = 0; - result = setPacket.serialize(&storePtr, &size, expectedSize, - SerializeIF::Endianness::BIG); - if(expectedSize != size) { - sif::error << "HousekeepingManager::generateSetStructurePacket: " - << "Expected size is not equal to serialized size" << std::endl; - } + // Serialize set packet into store. + size_t size = 0; + result = setPacket.serialize(&storePtr, &size, expectedSize, + SerializeIF::Endianness::BIG); + if(expectedSize != size) { + sif::error << "HousekeepingManager::generateSetStructurePacket: " + << "Expected size is not equal to serialized size" << std::endl; + } - // Send structure reporting reply. - CommandMessage reply; - if(isDiagnostics) { - HousekeepingMessage::setDiagnosticsStuctureReportReply(&reply, - sid, storeId); - } - else { - HousekeepingMessage::setHkStuctureReportReply(&reply, - sid, storeId); - } + // 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; } diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h index 779e3050..95d48303 100644 --- a/datapoollocal/LocalDataPoolManager.h +++ b/datapoollocal/LocalDataPoolManager.h @@ -20,16 +20,23 @@ namespace Factory { void setStaticFrameworkObjectIds(); } -class LocalDataSetBase; - +class LocalPoolDataSetBase; +class HousekeepingPacketUpdate; /** * @brief This class is the managing instance for the local data pool. * @details * The actual data pool structure is a member of this class. Any class which - * has a local data pool shall have this class as a member and implement + * has a local data pool shall have this manager class as a member and implement * the HasLocalDataPoolIF. * + * The manager offers some adaption points and functions which can be used + * by the owning class to simplify data handling significantly. + * + * Please ensure that both initialize and initializeAfterTaskCreation are + * called at some point by the owning class in the respective functions of the + * same name! + * * Users of the data pool use the helper classes LocalDataSet, * LocalPoolVariable and LocalPoolVector to access pool entries in * a thread-safe and efficient way. @@ -41,10 +48,8 @@ class LocalDataSetBase; * @author R. Mueller */ class LocalDataPoolManager { - template - friend class LocalPoolVar; - template - friend class LocalPoolVector; + template friend class LocalPoolVar; + template friend class LocalPoolVector; friend class LocalPoolDataSetBase; friend void (Factory::setStaticFrameworkObjectIds)(); public: @@ -67,14 +72,16 @@ public: * initialize() has to be called in any case before using the object! * @param owner * @param queueToUse - * @param appendValidityBuffer + * @param appendValidityBuffer Specify whether a buffer containing the + * validity state is generated when serializing or deserializing packets. */ LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, bool appendValidityBuffer = true); virtual~ LocalDataPoolManager(); /** - * Assigns the queue to use. + * Assigns the queue to use. Make sure to call this in the #initialize + * function of the owner. * @param queueToUse * @param nonDiagInvlFactor See #setNonDiagnosticIntervalFactor doc * @return @@ -84,27 +91,88 @@ public: /** * Initializes the map by calling the map initialization function and * setting the periodic factor for non-diagnostic packets. - * Don't forget to call this, otherwise the map will be invalid! + * Don't forget to call this in the #initializeAfterTaskCreation call of + * the owner, otherwise the map will be invalid! * @param nonDiagInvlFactor * @return */ - ReturnValue_t initializeAfterTaskCreation(uint8_t nonDiagInvlFactor = 5); + ReturnValue_t initializeAfterTaskCreation( + uint8_t nonDiagInvlFactor = 5); /** - * This should be called in the periodic handler of the owner. + * @brief This should be called in the periodic handler of the owner. + * @details + * This in generally called in the #performOperation function of the owner. * It performs all the periodic functionalities of the data pool manager, * for example generating periodic HK packets. + * Marked virtual as an adaption point for custom data pool managers. * @return */ - ReturnValue_t performHkOperation(); + virtual ReturnValue_t performHkOperation(); /** + * @brief Subscribe for the generation of periodic packets. + * @details + * This subscription mechanism will generally be used by the data creator + * to generate housekeeping packets which are downlinked directly. * @return */ ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting, float collectionInterval, bool isDiagnostics, object_id_t packetDestination = defaultHkDestination); + /** + * @brief Subscribe for the generation of packets if the dataset + * is marked as changed. + * @details + * This subscription mechanism will generally be used by the data creator. + * @param sid + * @param isDiagnostics + * @param packetDestination + * @return + */ + ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled, + bool isDiagnostics, + object_id_t packetDestination = defaultHkDestination); + + /** + * @brief Subscribe for a notification message which will be sent + * if a dataset has changed. + * @details + * This subscription mechanism will generally be used internally by + * other software components. + * @param setId Set ID of the set to receive update messages from. + * @param destinationObject + * @param targetQueueId + * @param generateSnapshot If this is set to true, a copy of the current + * data with a timestamp will be generated and sent via message. + * Otherwise, only an notification message is sent. + * @return + */ + ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId, + object_id_t destinationObject, + MessageQueueId_t targetQueueId, + bool generateSnapshot); + + /** + * @brief Subscribe for an notification message which will be sent if a + * pool variable has changed. + * @details + * This subscription mechanism will generally be used internally by + * other software components. + * @param localPoolId Pool ID of the pool variable + * @param destinationObject + * @param targetQueueId + * @param generateSnapshot If this is set to true, a copy of the current + * data with a timestamp will be generated and sent via message. + * Otherwise, only an notification message is sent. + * @return + */ + ReturnValue_t subscribeForVariableUpdateMessages(const lp_id_t localPoolId, + object_id_t destinationObject, + MessageQueueId_t targetQueueId, + bool generateSnapshot); + /** * Non-Diagnostics packets usually have a lower minimum sampling frequency * than diagnostic packets. @@ -116,6 +184,19 @@ public: */ void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor); + /** + * @brief The manager is also able to handle housekeeping messages. + * @details + * This most commonly is used to handle messages for the housekeeping + * interface, but the manager is also able to handle update notifications + * and calls a special function which can be overriden by a child class + * to handle data set or pool variable updates. This is relevant + * for classes like controllers which have their own local datapool + * but pull their data from other local datapools. + * @param message + * @return + */ + virtual ReturnValue_t handleHousekeepingMessage(CommandMessage* message); /** * Generate a housekeeping packet with a given SID. @@ -126,16 +207,6 @@ public: LocalPoolDataSetBase* dataSet, bool forDownlink, MessageQueueId_t destination = MessageQueueIF::NO_QUEUE); - ReturnValue_t handleHousekeepingMessage(CommandMessage* message); - - /** - * This function is used to fill the local data pool map with pool - * entries. It should only be called once by the pool owner. - * @param localDataPoolMap - * @return - */ - ReturnValue_t initializeHousekeepingPoolEntriesOnce(); - HasLocalDataPoolIF* getOwner(); ReturnValue_t printPoolEntry(lp_id_t localPoolId); @@ -194,17 +265,18 @@ private: static object_id_t defaultHkDestination; MessageQueueId_t hkDestinationId = MessageQueueIF::NO_QUEUE; + union DataId { + DataId(): sid() {}; + sid_t sid; + lp_id_t localPoolId; + }; + /** The data pool manager will keep an internal map of HK receivers. */ struct HkReceiver { /** Object ID of receiver */ object_id_t objectId = objects::NO_OBJECT; DataType dataType = DataType::DATA_SET; - union DataId { - DataId(): sid() {}; - sid_t sid; - lp_id_t localPoolId; - }; DataId dataId; ReportingType reportingType = ReportingType::PERIODIC; @@ -216,6 +288,17 @@ private: HkReceivers hkReceiversMap; + struct HkUpdateResetHelper { + DataType dataType = DataType::DATA_SET; + DataId dataId; + uint8_t updateCounter; + uint8_t currentUpdateCounter; + }; + + using HkUpdateResetList = std::vector; + // Will only be created when needed. + HkUpdateResetList* hkUpdateResetList = nullptr; + /** This is the map holding the actual data. Should only be initialized * once ! */ bool mapInitialized = false; @@ -234,7 +317,7 @@ private: StorageManagerIF* ipcStore = nullptr; /** * Get the pointer to the mutex. Can be used to lock the data pool - * eternally. Use with care and don't forget to unlock locked mutexes! + * externally. Use with care and don't forget to unlock locked mutexes! * For now, only friend classes can accss this function. * @return */ @@ -255,6 +338,14 @@ private: template ReturnValue_t fetchPoolEntry(lp_id_t localPoolId, PoolEntry **poolEntry); + /** + * This function is used to fill the local data pool map with pool + * entries. It should only be called once by the pool owner. + * @param localDataPoolMap + * @return + */ + ReturnValue_t initializeHousekeepingPoolEntriesOnce(); + ReturnValue_t serializeHkPacketIntoStore( HousekeepingPacketDownlink& hkPacket, store_address_t& storeId, bool forDownlink, size_t* serializedSize); @@ -265,6 +356,20 @@ private: ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval, bool isDiagnostics); ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics); + + void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId); + void handleChangeResetLogic(DataType type, + DataId dataId, MarkChangedIF* toReset); + void resetHkUpdateResetHelper(); + + ReturnValue_t handleHkUpdate(HkReceiver& hkReceiver, + ReturnValue_t& status); + ReturnValue_t handleNotificationUpdate(HkReceiver& hkReceiver, + ReturnValue_t& status); + ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver, + ReturnValue_t& status); + ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket, + store_address_t& storeId); }; diff --git a/datapoollocal/LocalPoolDataSetBase.cpp b/datapoollocal/LocalPoolDataSetBase.cpp index da0a86b2..640956db 100644 --- a/datapoollocal/LocalPoolDataSetBase.cpp +++ b/datapoollocal/LocalPoolDataSetBase.cpp @@ -7,22 +7,24 @@ #include LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner, - uint32_t setId, PoolVariableIF** registeredVariablesArray, - const size_t maxNumberOfVariables, bool noPeriodicHandling): - PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { - if(hkOwner == nullptr) { - // Configuration error. - sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " - << "invalid!" << std::endl; - return; - } + uint32_t setId, PoolVariableIF** registeredVariablesArray, + const size_t maxNumberOfVariables, bool noPeriodicHandling): + PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { + if(hkOwner == nullptr) { + // Configuration error. + sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " + << "invalid!" << std::endl; + return; + } hkManager = hkOwner->getHkManagerHandle(); this->sid.objectId = hkOwner->getObjectId(); this->sid.ownerSetId = setId; + mutex = MutexFactory::instance()->createMutex(); + // Data creators get a periodic helper for periodic HK data generation. if(not noPeriodicHandling) { - periodicHelper = new PeriodicHousekeepingHelper(this); + periodicHelper = new PeriodicHousekeepingHelper(this); } } @@ -33,21 +35,23 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, HasLocalDataPoolIF* hkOwner = objectManager->get( sid.objectId); if(hkOwner == nullptr) { - // Configuration error. + // Configuration error. sif::error << "LocalPoolDataSetBase::LocalPoolDataSetBase: Owner " - << "invalid!" << std::endl; + << "invalid!" << std::endl; return; } hkManager = hkOwner->getHkManagerHandle(); this->sid = sid; + + mutex = MutexFactory::instance()->createMutex(); } LocalPoolDataSetBase::~LocalPoolDataSetBase() { } ReturnValue_t LocalPoolDataSetBase::lockDataPool(uint32_t timeoutMs) { - MutexIF* mutex = hkManager->getMutexHandle(); - return mutex->lockMutex(MutexIF::TimeoutType::WAITING, timeoutMs); + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->lockMutex(MutexIF::TimeoutType::WAITING, timeoutMs); } ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer, @@ -77,6 +81,10 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer return result; } } + + if(*size + validityMaskSize > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } // copy validity buffer to end std::memcpy(*buffer, validityMask, validityMaskSize); *size += validityMaskSize; @@ -89,14 +97,18 @@ ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer( ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; for (uint16_t count = 0; count < fillCount; count++) { result = registeredVariables[count]->deSerialize(buffer, size, - streamEndianness); + streamEndianness); if(result != HasReturnvaluesIF::RETURN_OK) { return result; } } + + if(*size < std::ceil(static_cast(fillCount) / 8.0)) { + return SerializeIF::STREAM_TOO_SHORT; + } + uint8_t validBufferIndex = 0; uint8_t validBufferIndexBit = 0; - // could be made more efficient but make it work first for (uint16_t count = 0; count < fillCount; count++) { // set validity buffer here. bool nextVarValid = this->bitGetter(*buffer + @@ -113,9 +125,10 @@ ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer( } return result; } + ReturnValue_t LocalPoolDataSetBase::unlockDataPool() { - MutexIF* mutex = hkManager->getMutexHandle(); - return mutex->unlockMutex(); + MutexIF* mutex = hkManager->getMutexHandle(); + return mutex->unlockMutex(); } ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer, @@ -192,7 +205,7 @@ ReturnValue_t LocalPoolDataSetBase::serialize(uint8_t **buffer, size_t *size, void LocalPoolDataSetBase::bitSetter(uint8_t* byte, uint8_t position) const { if(position > 7) { sif::debug << "Pool Raw Access: Bit setting invalid position" - << std::endl; + << std::endl; return; } uint8_t shiftNumber = position + (7 - 2 * position); @@ -200,45 +213,49 @@ void LocalPoolDataSetBase::bitSetter(uint8_t* byte, uint8_t position) const { } void LocalPoolDataSetBase::setDiagnostic(bool isDiagnostics) { - this->diagnostic = isDiagnostics; + this->diagnostic = isDiagnostics; } bool LocalPoolDataSetBase::isDiagnostics() const { - return diagnostic; + return diagnostic; } void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) { - this->reportingEnabled = reportingEnabled; + this->reportingEnabled = reportingEnabled; } bool LocalPoolDataSetBase::getReportingEnabled() const { - return reportingEnabled; + return reportingEnabled; } void LocalPoolDataSetBase::initializePeriodicHelper( - float collectionInterval, dur_millis_t minimumPeriodicInterval, - bool isDiagnostics, uint8_t nonDiagIntervalFactor) { - periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, - isDiagnostics, nonDiagIntervalFactor); + float collectionInterval, dur_millis_t minimumPeriodicInterval, + bool isDiagnostics, uint8_t nonDiagIntervalFactor) { + periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, + isDiagnostics, nonDiagIntervalFactor); } void LocalPoolDataSetBase::setChanged(bool changed) { - this->changed = changed; + // TODO: Make this configurable? + MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); + this->changed = changed; } -bool LocalPoolDataSetBase::isChanged() const { - return changed; +bool LocalPoolDataSetBase::hasChanged() const { + // TODO: Make this configurable? + MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); + return changed; } sid_t LocalPoolDataSetBase::getSid() const { - return sid; + return sid; } bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte, - uint8_t position) const { + uint8_t position) const { if(position > 7) { sif::debug << "Pool Raw Access: Bit setting invalid position" - << std::endl; + << std::endl; return false; } uint8_t shiftNumber = position + (7 - 2 * position); @@ -246,14 +263,16 @@ 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) { - if(setEntriesRecursively) { - for(size_t idx = 0; idx < this->getFillCount(); idx++) { - registeredVariables[idx] -> setValid(valid); - } - } - this->valid = valid; + MutexHelper(mutex, MutexIF::TimeoutType::WAITING, 5); + if(setEntriesRecursively) { + for(size_t idx = 0; idx < this->getFillCount(); idx++) { + registeredVariables[idx] -> setValid(valid); + } + } + this->valid = valid; } diff --git a/datapoollocal/LocalPoolDataSetBase.h b/datapoollocal/LocalPoolDataSetBase.h index d00af992..aa155bf1 100644 --- a/datapoollocal/LocalPoolDataSetBase.h +++ b/datapoollocal/LocalPoolDataSetBase.h @@ -2,6 +2,8 @@ #define FSFW_DATAPOOLLOCAL_LOCALPOOLDATASETBASE_H_ #include "HasLocalDataPoolIF.h" +#include "MarkChangedIF.h" + #include "../datapool/DataSetIF.h" #include "../datapool/PoolDataSetBase.h" #include "../serialize/SerializeIF.h" @@ -39,7 +41,8 @@ class PeriodicHousekeepingHelper; * * @ingroup data_pool */ -class LocalPoolDataSetBase: public PoolDataSetBase { +class LocalPoolDataSetBase: public PoolDataSetBase, + public MarkChangedIF { friend class LocalDataPoolManager; friend class PeriodicHousekeepingHelper; public: @@ -109,18 +112,23 @@ public: uint8_t getLocalPoolIdsSerializedSize(bool serializeFillCount = true) const; /** - * Set the dataset valid or invalid + * Set the dataset valid or invalid. These calls are mutex protected. * @param setEntriesRecursively * If this is true, all contained datasets will also be set recursively. */ void setValidity(bool valid, bool setEntriesRecursively); bool isValid() const override; - void setChanged(bool changed); - bool isChanged() const; + /** + * These calls are mutex protected. + * @param changed + */ + void setChanged(bool changed) override; + bool hasChanged() const override; protected: sid_t sid; + MutexIF* mutex = nullptr; bool diagnostic = false; void setDiagnostic(bool diagnostics); diff --git a/datapoollocal/LocalPoolObjectBase.cpp b/datapoollocal/LocalPoolObjectBase.cpp new file mode 100644 index 00000000..b4d0e306 --- /dev/null +++ b/datapoollocal/LocalPoolObjectBase.cpp @@ -0,0 +1,73 @@ +#include "LocalPoolObjectBase.h" + +LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, + HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode): localPoolId(poolId), + readWriteMode(setReadWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " + << "which is the NO_PARAMETER value!" << std::endl; + } + if(hkOwner == nullptr) { + sif::error << "LocalPoolVar::LocalPoolVar: The supplied pool " + << "owner is a invalid!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + if (dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, + DataSetIF *dataSet, pool_rwm_t setReadWriteMode): localPoolId(poolId), + readWriteMode(setReadWriteMode) { + if(poolId == PoolVariableIF::NO_PARAMETER) { + sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " + << "which is the NO_PARAMETER value!" << std::endl; + } + HasLocalDataPoolIF* hkOwner = + objectManager->get(poolOwner); + if(hkOwner == nullptr) { + sif::error << "LocalPoolVariable: The supplied pool owner did not " + << "implement the correct interface" + << " HasLocalDataPoolIF!" << std::endl; + return; + } + hkManager = hkOwner->getHkManagerHandle(); + if(dataSet != nullptr) { + dataSet->registerVariable(this); + } +} + +pool_rwm_t LocalPoolObjectBase::getReadWriteMode() const { + return readWriteMode; +} + +bool LocalPoolObjectBase::isValid() const { + return valid; +} + +void LocalPoolObjectBase::setValid(bool valid) { + this->valid = valid; +} + +lp_id_t LocalPoolObjectBase::getDataPoolId() const { + return localPoolId; +} + +void LocalPoolObjectBase::setDataPoolId(lp_id_t poolId) { + this->localPoolId = poolId; +} + +void LocalPoolObjectBase::setChanged(bool changed) { + this->changed = changed; +} + +bool LocalPoolObjectBase::hasChanged() const { + return changed; +} + +void LocalPoolObjectBase::setReadWriteMode(pool_rwm_t newReadWriteMode) { + this->readWriteMode = newReadWriteMode; +} diff --git a/datapoollocal/LocalPoolObjectBase.h b/datapoollocal/LocalPoolObjectBase.h new file mode 100644 index 00000000..7165fc24 --- /dev/null +++ b/datapoollocal/LocalPoolObjectBase.h @@ -0,0 +1,63 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ + +#include "MarkChangedIF.h" +#include "../datapoollocal/LocalDataPoolManager.h" +#include "../datapool/PoolVariableIF.h" + + +class LocalPoolObjectBase: public PoolVariableIF, + public HasReturnvaluesIF, + public MarkChangedIF { +public: + LocalPoolObjectBase(lp_id_t poolId, + HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, + pool_rwm_t setReadWriteMode); + + LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + + void setReadWriteMode(pool_rwm_t newReadWriteMode); + pool_rwm_t getReadWriteMode() const; + + bool isValid() const override; + void setValid(bool valid) override; + + void setChanged(bool changed) override; + bool hasChanged() const override; + + lp_id_t getDataPoolId() const override; + void setDataPoolId(lp_id_t poolId); + +protected: + /** + * @brief To access the correct data pool entry on read and commit calls, + * the data pool id is stored. + */ + uint32_t localPoolId = PoolVariableIF::NO_PARAMETER; + /** + * @brief The valid information as it was stored in the data pool + * is copied to this attribute. + */ + bool valid = false; + + /** + * @brief A local pool variable can be marked as changed. + */ + bool changed = false; + + /** + * @brief The information whether the class is read-write or + * read-only is stored here. + */ + ReadWriteMode_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; + + //! @brief Pointer to the class which manages the HK pool. + LocalDataPoolManager* hkManager; + +}; + + + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLOBJECTBASE_H_ */ diff --git a/datapoollocal/LocalPoolVariable.h b/datapoollocal/LocalPoolVariable.h index ec5c8cd1..c18d5443 100644 --- a/datapoollocal/LocalPoolVariable.h +++ b/datapoollocal/LocalPoolVariable.h @@ -1,6 +1,7 @@ #ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ #define FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ +#include "LocalPoolObjectBase.h" #include "HasLocalDataPoolIF.h" #include "LocalDataPoolManager.h" @@ -21,7 +22,7 @@ * @ingroup data_pool */ template -class LocalPoolVar: public PoolVariableIF, HasReturnvaluesIF { +class LocalPoolVar: public LocalPoolObjectBase { public: //! Default ctor is forbidden. LocalPoolVar() = delete; @@ -42,7 +43,7 @@ public: * If nullptr, the variable is not registered. * @param setReadWriteMode Specify the read-write mode of the pool variable. */ - LocalPoolVar(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, + LocalPoolVar(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr, pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); @@ -63,9 +64,17 @@ public: * @param setReadWriteMode Specify the read-write mode of the pool variable. * */ - LocalPoolVar(lp_id_t poolId, object_id_t poolOwner, + LocalPoolVar(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr, pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * Variation which takes the global unique identifier of a pool variable. + * @param globalPoolId + * @param dataSet + * @param setReadWriteMode + */ + LocalPoolVar(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); virtual~ LocalPoolVar() {}; @@ -76,15 +85,6 @@ public: */ T value = 0; - pool_rwm_t getReadWriteMode() const override; - - lp_id_t getDataPoolId() const override; - void setDataPoolId(lp_id_t poolId); - - bool isValid() const override; - void setValid(bool validity) override; - uint8_t getValid() const; - ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, SerializeIF::Endianness streamEndianness) const override; virtual size_t getSerializedSize() const override; @@ -118,7 +118,25 @@ public: ReturnValue_t commit(dur_millis_t lockTimeout = MutexIF::BLOCKING) override; - LocalPoolVar &operator=(T newValue); + LocalPoolVar &operator=(const T& newValue); + LocalPoolVar &operator=(const LocalPoolVar& newPoolVariable); + + //! Explicit type conversion operator. Allows casting the class to + //! its template type to perform operations on value. + explicit operator T() const; + + bool operator==(const LocalPoolVar& other) const; + bool operator==(const T& other) const; + + bool operator!=(const LocalPoolVar& other) const; + bool operator!=(const T& other) const; + + bool operator<(const LocalPoolVar& other) const; + bool operator<(const T& other) const; + + bool operator>(const LocalPoolVar& other) const; + bool operator>(const T& other) const; + protected: /** * @brief Like #read, but without a lock protection of the global pool. @@ -145,15 +163,6 @@ protected: const LocalPoolVar &var); private: - //! @brief Pool ID of pool entry inside the used local pool. - lp_id_t localPoolId = PoolVariableIF::NO_PARAMETER; - //! @brief Read-write mode of the pool variable - pool_rwm_t readWriteMode = pool_rwm_t::VAR_READ_WRITE; - //! @brief Specifies whether the entry is valid or invalid. - bool valid = false; - - //! Pointer to the class which manages the HK pool. - LocalDataPoolManager* hkManager; }; #include "LocalPoolVariable.tpp" @@ -173,5 +182,4 @@ using lp_int64_t = LocalPoolVar; using lp_float_t = LocalPoolVar; using lp_double_t = LocalPoolVar; - #endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_H_ */ diff --git a/datapoollocal/LocalPoolVariable.tpp b/datapoollocal/LocalPoolVariable.tpp index b0bdd7b9..b9f7b906 100644 --- a/datapoollocal/LocalPoolVariable.tpp +++ b/datapoollocal/LocalPoolVariable.tpp @@ -6,46 +6,22 @@ #endif template -inline LocalPoolVar::LocalPoolVar(lp_id_t poolId, - HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, - pool_rwm_t setReadWriteMode): - localPoolId(poolId), readWriteMode(setReadWriteMode) { - if(poolId == PoolVariableIF::NO_PARAMETER) { - sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " - << "which is the NO_PARAMETER value!" << std::endl; - } - if(hkOwner == nullptr) { - sif::error << "LocalPoolVar::LocalPoolVar: The supplied pool " - << "owner is a invalid!" << std::endl; - return; - } - hkManager = hkOwner->getHkManagerHandle(); - if(dataSet != nullptr) { - dataSet->registerVariable(this); - } -} +inline LocalPoolVar::LocalPoolVar(HasLocalDataPoolIF* hkOwner, + lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} template -inline LocalPoolVar::LocalPoolVar(lp_id_t poolId, object_id_t poolOwner, +inline LocalPoolVar::LocalPoolVar(object_id_t poolOwner, lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): - localPoolId(poolId), readWriteMode(setReadWriteMode) { - if(poolId == PoolVariableIF::NO_PARAMETER) { - sif::warning << "LocalPoolVar::LocalPoolVar: 0 passed as pool ID, " - << "which is the NO_PARAMETER value!" << std::endl; - } - HasLocalDataPoolIF* hkOwner = - objectManager->get(poolOwner); - if(hkOwner == nullptr) { - sif::error << "LocalPoolVariable: The supplied pool owner did not " - << "implement the correct interface " - << "HasLocalDataPoolIF!" << std::endl; - return; - } - hkManager = hkOwner->getHkManagerHandle(); - if(dataSet != nullptr) { - dataSet->registerVariable(this); - } -} + LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} + + +template +inline LocalPoolVar::LocalPoolVar(gp_id_t globalPoolId, DataSetIF *dataSet, + pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, + dataSet, setReadWriteMode){} + template inline ReturnValue_t LocalPoolVar::read(dur_millis_t lockTimeout) { @@ -104,43 +80,6 @@ inline ReturnValue_t LocalPoolVar::commitWithoutLock() { return RETURN_OK; } -template -inline LocalPoolVar & LocalPoolVar::operator =(T newValue) { - value = newValue; - return *this; -} - - -template -inline pool_rwm_t LocalPoolVar::getReadWriteMode() const { - return readWriteMode; -} - -template -inline lp_id_t LocalPoolVar::getDataPoolId() const { - return localPoolId; -} - -template -inline void LocalPoolVar::setDataPoolId(lp_id_t poolId) { - this->localPoolId = poolId; -} - -template -inline bool LocalPoolVar::isValid() const { - return valid; -} - -template -inline void LocalPoolVar::setValid(bool validity) { - this->valid = validity; -} - -template -inline uint8_t LocalPoolVar::getValid() const { - return valid; -} - template inline ReturnValue_t LocalPoolVar::serialize(uint8_t** buffer, size_t* size, const size_t max_size, SerializeIF::Endianness streamEndianness) const { @@ -166,4 +105,65 @@ inline std::ostream& operator<< (std::ostream &out, return out; } -#endif +template +inline LocalPoolVar::operator T() const { + return value; +} + +template +inline LocalPoolVar & LocalPoolVar::operator=(const T& newValue) { + value = newValue; + return *this; +} + +template +inline LocalPoolVar& LocalPoolVar::operator =( + const LocalPoolVar& newPoolVariable) { + value = newPoolVariable.value; + return *this; +} + +template +inline bool LocalPoolVar::operator ==(const LocalPoolVar &other) const { + return this->value == other.value; +} + +template +inline bool LocalPoolVar::operator ==(const T &other) const { + return this->value == other; +} + + +template +inline bool LocalPoolVar::operator !=(const LocalPoolVar &other) const { + return not (*this == other); +} + +template +inline bool LocalPoolVar::operator !=(const T &other) const { + return not (*this == other); +} + + +template +inline bool LocalPoolVar::operator <(const LocalPoolVar &other) const { + return this->value < other.value; +} + +template +inline bool LocalPoolVar::operator <(const T &other) const { + return this->value < other; +} + + +template +inline bool LocalPoolVar::operator >(const LocalPoolVar &other) const { + return not (*this < other); +} + +template +inline bool LocalPoolVar::operator >(const T &other) const { + return not (*this < other); +} + +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVARIABLE_TPP_ */ diff --git a/datapoollocal/LocalPoolVector.h b/datapoollocal/LocalPoolVector.h index 57c4b90b..58face3c 100644 --- a/datapoollocal/LocalPoolVector.h +++ b/datapoollocal/LocalPoolVector.h @@ -1,6 +1,7 @@ -#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ -#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#include "LocalPoolObjectBase.h" #include "../datapool/DataSetIF.h" #include "../datapool/PoolEntry.h" #include "../datapool/PoolVariableIF.h" @@ -30,7 +31,7 @@ * @ingroup data_pool */ template -class LocalPoolVector: public PoolVariableIF, public HasReturnvaluesIF { +class LocalPoolVector: public LocalPoolObjectBase { public: LocalPoolVector() = delete; /** @@ -46,10 +47,9 @@ public: * @param dataSet The data set in which the variable shall register itself. * If nullptr, the variable is not registered. */ - LocalPoolVector(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, + LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE - ); + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); /** * This constructor is used by data users like controllers to have @@ -65,10 +65,19 @@ public: * @param dataSet The data set in which the variable shall register itself. * If nullptr, the variable is not registered. */ - LocalPoolVector(lp_id_t poolId, object_id_t poolOwner, + LocalPoolVector(object_id_t poolOwner, lp_id_t poolId, DataSetIF* dataSet = nullptr, - pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE - ); + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); + /** + * Variation which takes the unique global identifier of a local pool + * vector. + * @param globalPoolId + * @param dataSet + * @param setReadWriteMode + */ + LocalPoolVector(gp_id_t globalPoolId, + DataSetIF* dataSet = nullptr, + pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); /** * @brief This is the local copy of the data pool entry. @@ -91,27 +100,6 @@ public: return vectorSize; } - uint32_t getDataPoolId() const override; - /** - * @brief This operation sets the data pool ID of the variable. - * @details - * The method is necessary to set id's of data pool member variables - * with bad initialization. - */ - void setDataPoolId(uint32_t poolId); - - /** - * This method returns if the variable is write-only, read-write or read-only. - */ - pool_rwm_t getReadWriteMode() const; - - /** - * @brief With this call, the valid information of the variable is returned. - */ - bool isValid() const override; - void setValid(bool valid) override; - uint8_t getValid() const; - T& operator [](int i); const T &operator [](int i) const; @@ -168,23 +156,7 @@ protected: ReturnValue_t commitWithoutLock() override; private: - /** - * @brief To access the correct data pool entry on read and commit calls, - * the data pool id is stored. - */ - uint32_t localPoolId; - /** - * @brief The valid information as it was stored in the data pool - * is copied to this attribute. - */ - bool valid; - /** - * @brief The information whether the class is read-write or - * read-only is stored here. - */ - ReadWriteMode_t readWriteMode; - //! @brief Pointer to the class which manages the HK pool. - LocalDataPoolManager* hkManager; + // std::ostream is the type for object std::cout template @@ -199,4 +171,4 @@ private: template using lp_vec_t = LocalPoolVector; -#endif /* FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ */ +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ */ diff --git a/datapoollocal/LocalPoolVector.tpp b/datapoollocal/LocalPoolVector.tpp index 2aa6fbb5..46123ccc 100644 --- a/datapoollocal/LocalPoolVector.tpp +++ b/datapoollocal/LocalPoolVector.tpp @@ -1,47 +1,27 @@ -#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ -#define FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ +#define FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ -#ifndef FRAMEWORK_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ +#ifndef FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_H_ #error Include LocalPoolVector.h before LocalPoolVector.tpp! #endif template -inline LocalPoolVector::LocalPoolVector(lp_id_t poolId, - HasLocalDataPoolIF* hkOwner, DataSetIF* dataSet, +inline LocalPoolVector::LocalPoolVector( + HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode): - localPoolId(poolId), valid(false), readWriteMode(setReadWriteMode) { - if(poolId == PoolVariableIF::NO_PARAMETER) { - sif::warning << "LocalPoolVector: PoolVariableIF::NO_PARAMETER passed " - << "as pool ID, which is the NO_PARAMETER value!" << std::endl; - } - std::memset(this->value, 0, vectorSize * sizeof(T)); - hkManager = hkOwner->getHkManagerHandle(); - if (dataSet != nullptr) { - dataSet->registerVariable(this); - } -} + LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {} template -inline LocalPoolVector::LocalPoolVector(lp_id_t poolId, - object_id_t poolOwner, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): - readWriteMode(setReadWriteMode) { - if(poolId == PoolVariableIF::NO_PARAMETER) { - sif::warning << "LocalPoolVector: PoolVariableIF::NO_PARAMETER passed " - << "as pool ID, which is the NO_PARAMETER value!" << std::endl; - } - HasLocalDataPoolIF* hkOwner = - objectManager->get(poolOwner); - if(hkOwner == nullptr) { - sif::error << "LocalPoolVariable: The supplied pool owner did not " - << "implement the correct interface HasHkPoolParametersIF!" - << std::endl; - return; - } - hkManager = hkOwner->getHkManagerHandle(); - if(dataSet != nullptr) { - dataSet->registerVariable(this); - } -} +inline LocalPoolVector::LocalPoolVector(object_id_t poolOwner, + lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} + + +template +inline LocalPoolVector::LocalPoolVector(gp_id_t globalPoolId, + DataSetIF *dataSet, pool_rwm_t setReadWriteMode): + LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, + dataSet, setReadWriteMode) {} template inline ReturnValue_t LocalPoolVector::read(uint32_t lockTimeout) { @@ -161,37 +141,6 @@ inline ReturnValue_t LocalPoolVector::deSerialize( return result; } -template -inline pool_rwm_t LocalPoolVector::getReadWriteMode() const { - return this->readWriteMode; -} - - -template -inline uint32_t LocalPoolVector::getDataPoolId() const { - return localPoolId; -} - -template -inline void LocalPoolVector::setDataPoolId(uint32_t poolId) { - this->localPoolId = poolId; -} - -template -inline void LocalPoolVector::setValid(bool valid) { - this->valid = valid; -} - -template -inline uint8_t LocalPoolVector::getValid() const { - return valid; -} - -template -inline bool LocalPoolVector::isValid() const { - return valid; -} - template inline std::ostream& operator<< (std::ostream &out, const LocalPoolVector &var) { @@ -206,4 +155,4 @@ inline std::ostream& operator<< (std::ostream &out, return out; } -#endif +#endif /* FSFW_DATAPOOLLOCAL_LOCALPOOLVECTOR_TPP_ */ diff --git a/datapoollocal/MarkChangedIF.h b/datapoollocal/MarkChangedIF.h new file mode 100644 index 00000000..e575d1d3 --- /dev/null +++ b/datapoollocal/MarkChangedIF.h @@ -0,0 +1,17 @@ +#ifndef FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ +#define FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ + +/** + * Common interface for local pool entities which can be marked as changed. + */ +class MarkChangedIF { +public: + virtual~ MarkChangedIF() {}; + + virtual bool hasChanged() const = 0; + virtual void setChanged(bool changed) = 0; +}; + + + +#endif /* FSFW_DATAPOOLLOCAL_MARKCHANGEDIF_H_ */ diff --git a/datapoollocal/locPoolDefinitions.h b/datapoollocal/locPoolDefinitions.h new file mode 100644 index 00000000..6e74d349 --- /dev/null +++ b/datapoollocal/locPoolDefinitions.h @@ -0,0 +1,93 @@ +#ifndef FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ +#define FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ + +#include +#include "../objectmanager/SystemObjectIF.h" +#include "../objectmanager/frameworkObjects.h" + +/** + * @brief Type definition for local pool entries. + */ +using lp_id_t = uint32_t; + +namespace localpool { +static constexpr uint32_t INVALID_LPID = -1; +} + +/** + * Used as a unique identifier for data sets. + */ +union sid_t { + static constexpr uint64_t INVALID_SID = -1; + static constexpr uint32_t INVALID_OBJECT_ID = objects::NO_OBJECT; + static constexpr uint32_t INVALID_SET_ID = -1; + + + sid_t(): raw(INVALID_SID) {} + + sid_t(object_id_t objectId, uint32_t setId): + objectId(objectId), + ownerSetId(setId) {} + + struct { + object_id_t objectId ; + /** + * A generic 32 bit ID to identify unique HK packets for a single + * object. For example, the DeviceCommandId_t is used for + * DeviceHandlers + */ + uint32_t ownerSetId; + }; + /** + * Alternative access to the raw value. This is also the size of the type. + */ + uint64_t raw; + + bool notSet() const { + return raw == INVALID_SID; + } + + bool operator==(const sid_t& other) const { + return raw == other.raw; + } + + bool operator!=(const sid_t& other) const { + return not (raw == other.raw); + } +}; + +/** + * Used as a global unique identifier for local pool variables. + */ +union gp_id_t { + static constexpr uint64_t INVALID_GPID = -1; + static constexpr uint32_t INVALID_OBJECT_ID = objects::NO_OBJECT; + static constexpr uint32_t INVALID_LPID = localpool::INVALID_LPID; + + gp_id_t(): raw(INVALID_GPID) {} + + gp_id_t(object_id_t objectId, lp_id_t localPoolId): + objectId(objectId), + localPoolId(localPoolId) {} + + struct { + object_id_t objectId; + lp_id_t localPoolId; + }; + + uint64_t raw; + + bool notSet() const { + return raw == INVALID_GPID; + } + + bool operator==(const sid_t& other) const { + return raw == other.raw; + } + + bool operator!=(const sid_t& other) const { + return not (raw == other.raw); + } +}; + +#endif /* FSFW_DATAPOOLLOCAL_LOCPOOLDEFINITIONS_H_ */ diff --git a/housekeeping/AcceptsHkPacketsIF.h b/housekeeping/AcceptsHkPacketsIF.h index b3ba6e7c..6fa151b1 100644 --- a/housekeeping/AcceptsHkPacketsIF.h +++ b/housekeeping/AcceptsHkPacketsIF.h @@ -1,5 +1,6 @@ #ifndef FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ #define FRAMEWORK_HOUSEKEEPING_ACCEPTSHKPACKETSIF_H_ + #include "../ipc/MessageQueueMessageIF.h" class AcceptsHkPacketsIF { diff --git a/housekeeping/HousekeepingMessage.cpp b/housekeeping/HousekeepingMessage.cpp index d2ab546b..221f0a6f 100644 --- a/housekeeping/HousekeepingMessage.cpp +++ b/housekeeping/HousekeepingMessage.cpp @@ -1,5 +1,6 @@ -#include #include "HousekeepingMessage.h" + +#include "../objectmanager/ObjectManagerIF.h" #include HousekeepingMessage::~HousekeepingMessage() {} @@ -148,7 +149,7 @@ void HousekeepingMessage::clear(CommandMessage* message) { case(DIAGNOSTICS_REPORT): case(HK_DEFINITIONS_REPORT): case(DIAGNOSTICS_DEFINITION_REPORT): - case(UPDATE_SNAPSHOT): { + case(UPDATE_SNAPSHOT_SET): { store_address_t storeId; getHkDataReply(message, &storeId); StorageManagerIF *ipcStore = objectManager->get( @@ -160,3 +161,55 @@ void HousekeepingMessage::clear(CommandMessage* message) { } message->setCommand(CommandMessage::CMD_NONE); } + +void HousekeepingMessage::setUpdateNotificationSetCommand( + CommandMessage *command, sid_t sid) { + command->setCommand(UPDATE_NOTIFICATION_SET); + setSid(command, sid); +} + +void HousekeepingMessage::setUpdateNotificationVariableCommand( + CommandMessage *command, lp_id_t localPoolId) { + command->setCommand(UPDATE_NOTIFICATION_VARIABLE); + command->setParameter(localPoolId); +} + +void HousekeepingMessage::setUpdateSnapshotSetCommand(CommandMessage *command, + sid_t sid, store_address_t storeId) { + command->setCommand(UPDATE_SNAPSHOT_VARIABLE); + setSid(command, sid); + command->setParameter3(storeId.raw); +} + +void HousekeepingMessage::setUpdateSnapshotVariableCommand( + CommandMessage *command, lp_id_t localPoolId, store_address_t storeId) { + command->setCommand(UPDATE_SNAPSHOT_VARIABLE); + command->setParameter(localPoolId); + command->setParameter3(storeId.raw); +} + +sid_t HousekeepingMessage::getUpdateNotificationSetCommand( + const CommandMessage *command) { + return getSid(command); +} + +lp_id_t HousekeepingMessage::getUpdateNotificationVariableCommand( + const CommandMessage *command) { + return command->getParameter(); +} + +sid_t HousekeepingMessage::getUpdateSnapshotSetCommand( + const CommandMessage *command, store_address_t *storeId) { + if(storeId != nullptr) { + *storeId = command->getParameter3(); + } + return getSid(command); +} + +lp_id_t HousekeepingMessage::getUpdateSnapshotVariableCommand( + const CommandMessage *command, store_address_t *storeId) { + if(storeId != nullptr) { + *storeId = command->getParameter3(); + } + return command->getParameter(); +} diff --git a/housekeeping/HousekeepingMessage.h b/housekeeping/HousekeepingMessage.h index 6dc95f54..90bbe594 100644 --- a/housekeeping/HousekeepingMessage.h +++ b/housekeeping/HousekeepingMessage.h @@ -1,49 +1,12 @@ #ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ #define FSFW_HOUSEKEEPING_HOUSEKEEPINGMESSAGE_H_ +#include "../datapoollocal/locPoolDefinitions.h" #include "../ipc/CommandMessage.h" #include "../ipc/FwMessageTypes.h" #include "../objectmanager/frameworkObjects.h" -#include "../objectmanager/SystemObjectIF.h" #include "../storagemanager/StorageManagerIF.h" -union sid_t { - static constexpr uint64_t INVALID_SID = -1; - static constexpr uint32_t INVALID_SET_ID = -1; - static constexpr uint32_t INVALID_OBJECT_ID = objects::NO_OBJECT; - sid_t(): raw(INVALID_SID) {} - - sid_t(object_id_t objectId, uint32_t setId): - objectId(objectId), - ownerSetId(setId) {} - - struct { - object_id_t objectId ; - /** - * A generic 32 bit ID to identify unique HK packets for a single - * object. For example, the DeviceCommandId_t is used for - * DeviceHandlers - */ - uint32_t ownerSetId; - }; - /** - * Alternative access to the raw value. This is also the size of the type. - */ - uint64_t raw; - - bool notSet() const { - return raw == INVALID_SID; - } - - bool operator==(const sid_t& other) const { - return raw == other.raw; - } - - bool operator!=(const sid_t& other) const { - return not (raw == other.raw); - } -}; - /** * @brief Special command message type for housekeeping messages @@ -101,14 +64,20 @@ public: static constexpr Command_t HK_REQUEST_FAILURE = MAKE_COMMAND_ID(129); - static constexpr Command_t UPDATE_NOTIFICATION = MAKE_COMMAND_ID(130); - static constexpr Command_t UPDATE_SNAPSHOT = MAKE_COMMAND_ID(131); + static constexpr Command_t UPDATE_NOTIFICATION_SET = + MAKE_COMMAND_ID(130); + static constexpr Command_t UPDATE_NOTIFICATION_VARIABLE = + MAKE_COMMAND_ID(131); - static constexpr Command_t UPDATE_HK_REPORT = MAKE_COMMAND_ID(132); + static constexpr Command_t UPDATE_SNAPSHOT_SET = MAKE_COMMAND_ID(132); + static constexpr Command_t UPDATE_SNAPSHOT_VARIABLE = MAKE_COMMAND_ID(133); + + //static constexpr Command_t UPDATE_HK_REPORT = MAKE_COMMAND_ID(134); static sid_t getSid(const CommandMessage* message); - /** Setter functions */ + /* Housekeeping Interface Messages */ + static void setToggleReportingCommand(CommandMessage* command, sid_t sid, bool enableReporting, bool isDiagnostics); static void setStructureReportingCommand(CommandMessage* command, sid_t sid, @@ -148,6 +117,29 @@ public: static sid_t getCollectionIntervalModificationCommand( const CommandMessage* command, float* newCollectionInterval); + + /* Update Notification Messages */ + + static void setUpdateNotificationSetCommand(CommandMessage* command, + sid_t sid); + static void setUpdateNotificationVariableCommand(CommandMessage* command, + lp_id_t localPoolId); + + static void setUpdateSnapshotSetCommand(CommandMessage* command, sid_t sid, + store_address_t storeId); + static void setUpdateSnapshotVariableCommand(CommandMessage* command, + lp_id_t localPoolId, store_address_t storeId); + + static sid_t getUpdateNotificationSetCommand(const CommandMessage* command); + static lp_id_t getUpdateNotificationVariableCommand( + const CommandMessage* command); + + static sid_t getUpdateSnapshotSetCommand(const CommandMessage* command, + store_address_t* storeId); + static lp_id_t getUpdateSnapshotVariableCommand(const CommandMessage* command, + store_address_t* storeId); + + /** Utility */ static void clear(CommandMessage* message); private: static void setSid(CommandMessage* message, sid_t sid); diff --git a/housekeeping/HousekeepingPacketUpdate.h b/housekeeping/HousekeepingPacketUpdate.h index eebdc11c..43ec0619 100644 --- a/housekeeping/HousekeepingPacketUpdate.h +++ b/housekeeping/HousekeepingPacketUpdate.h @@ -1,5 +1,5 @@ -#ifndef FRAMEWORK_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ -#define FRAMEWORK_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ #include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialLinkedListAdapter.h" @@ -12,6 +12,7 @@ class HousekeepingPacketUpdate: public SerializeIF { public: /** + * Update packet constructor for datasets * @param timeStamp * @param timeStampSize * @param hkData @@ -19,8 +20,19 @@ public: */ HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, LocalPoolDataSetBase* dataSetPtr): - timeStamp(timeStamp), timeStampSize(timeStampSize), - dataSetPtr(dataSetPtr) {}; + timeStamp(timeStamp), timeStampSize(timeStampSize), + updateData(dataSetPtr) {}; + + /** + * Update packet constructor for pool variables. + * @param timeStamp + * @param timeStampSize + * @param dataSetPtr + */ + HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, + LocalPoolObjectBase* dataSetPtr): + timeStamp(timeStamp), timeStampSize(timeStampSize), + updateData(dataSetPtr) {}; virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, Endianness streamEndianness) const { @@ -31,43 +43,50 @@ public: *size += timeStampSize; *buffer += timeStampSize; } - if(dataSetPtr == nullptr) { + if(updateData == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } - return dataSetPtr->serialize(buffer, size, maxSize, streamEndianness); + return updateData->serialize(buffer, size, maxSize, streamEndianness); } virtual size_t getSerializedSize() const { - if(dataSetPtr == nullptr) { + if(updateData == nullptr) { return 0; } - return timeStampSize + dataSetPtr->getSerializedSize(); + return timeStampSize + updateData->getSerializedSize(); } virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, SerializeIF::Endianness streamEndianness) override { + if(*size < timeStampSize) { + return SerializeIF::STREAM_TOO_SHORT; + } + if(timeStamp != nullptr) { /* Endianness will always be MACHINE, so we can simply use memcpy here. */ std::memcpy(timeStamp, *buffer, timeStampSize); - *size += timeStampSize; + *size -= timeStampSize; *buffer += timeStampSize; } - if(dataSetPtr == nullptr) { + if(updateData == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } - return dataSetPtr->deSerialize(buffer, size, streamEndianness); + if(*size < updateData->getSerializedSize()) { + return SerializeIF::STREAM_TOO_SHORT; + } + + return updateData->deSerialize(buffer, size, streamEndianness); } private: - uint8_t* timeStamp; - size_t timeStampSize; + uint8_t* timeStamp = nullptr; + size_t timeStampSize = 0; - LocalPoolDataSetBase* dataSetPtr = nullptr; + SerializeIF* updateData = nullptr; }; - -#endif /* FRAMEWORK_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ */ +#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ */ diff --git a/housekeeping/PeriodicHousekeepingHelper.cpp b/housekeeping/PeriodicHousekeepingHelper.cpp index 37349f81..365f0004 100644 --- a/housekeeping/PeriodicHousekeepingHelper.cpp +++ b/housekeeping/PeriodicHousekeepingHelper.cpp @@ -1,5 +1,6 @@ -#include "../datapoollocal/LocalPoolDataSetBase.h" #include "PeriodicHousekeepingHelper.h" + +#include "../datapoollocal/LocalPoolDataSetBase.h" #include PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(