diff --git a/datapoollocal/LocalDataPoolManager.cpp b/datapoollocal/LocalDataPoolManager.cpp index 462ef17f..d2732582 100644 --- a/datapoollocal/LocalDataPoolManager.cpp +++ b/datapoollocal/LocalDataPoolManager.cpp @@ -5,8 +5,8 @@ #include "internal/LocalPoolDataSetAttorney.h" #include "internal/HasLocalDpIFManagerAttorney.h" -#include "../housekeeping/HousekeepingPacketUpdate.h" #include "../housekeeping/HousekeepingSetPacket.h" +#include "../housekeeping/HousekeepingSnapshot.h" #include "../housekeeping/AcceptsHkPacketsIF.h" #include "../timemanager/CCSDSTime.h" #include "../ipc/MutexFactory.h" @@ -226,7 +226,7 @@ ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot( Clock::getClock_timeval(&now); CCSDSTime::CDS_short cds; CCSDSTime::convertToCcsds(&cds, &now); - HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + HousekeepingSnapshot updatePacket(reinterpret_cast(&cds), sizeof(cds), HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, receiver.dataId.localPoolId)); @@ -264,7 +264,7 @@ ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot( Clock::getClock_timeval(&now); CCSDSTime::CDS_short cds; CCSDSTime::convertToCcsds(&cds, &now); - HousekeepingPacketUpdate updatePacket(reinterpret_cast(&cds), + HousekeepingSnapshot updatePacket(reinterpret_cast(&cds), sizeof(cds), HasLocalDpIFManagerAttorney::getDataSetHandle(owner, receiver.dataId.sid)); @@ -292,7 +292,7 @@ ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot( } ReturnValue_t LocalDataPoolManager::addUpdateToStore( - HousekeepingPacketUpdate& updatePacket, store_address_t& storeId) { + HousekeepingSnapshot& updatePacket, store_address_t& storeId) { size_t updatePacketSize = updatePacket.getSerializedSize(); uint8_t *storePtr = nullptr; ReturnValue_t result = ipcStore->getFreeElement(&storeId, diff --git a/datapoollocal/LocalDataPoolManager.h b/datapoollocal/LocalDataPoolManager.h index 580ac8b9..a72641b0 100644 --- a/datapoollocal/LocalDataPoolManager.h +++ b/datapoollocal/LocalDataPoolManager.h @@ -24,7 +24,7 @@ void setStaticFrameworkObjectIds(); } class LocalPoolDataSetBase; -class HousekeepingPacketUpdate; +class HousekeepingSnapshot; class HasLocalDataPoolIF; class LocalDataPool; @@ -386,7 +386,7 @@ private: ReturnValue_t& status); ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver, ReturnValue_t& status); - ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket, + ReturnValue_t addUpdateToStore(HousekeepingSnapshot& updatePacket, store_address_t& storeId); void printWarningOrError(sif::OutputTypes outputType, diff --git a/datapoollocal/LocalDataSet.h b/datapoollocal/LocalDataSet.h index b7f8f90f..92bad9b5 100644 --- a/datapoollocal/LocalDataSet.h +++ b/datapoollocal/LocalDataSet.h @@ -4,11 +4,26 @@ #include "LocalPoolDataSetBase.h" #include +/** + * @brief This dataset type can be used to group related pool variables if the number of + * variables should not be fixed. + * @details + * This will is the primary data structure to organize pool variables into + * sets which can be accessed via the housekeeping service interface or + * which can be sent to other software objects. + * + * It is recommended to read the documentation of the LocalPoolDataSetBase + * class for more information on how this class works and how to use it. + * @tparam capacity Capacity of the static dataset, which is usually known + * beforehand. + */ class LocalDataSet: public LocalPoolDataSetBase { public: LocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId, const size_t maxSize); + LocalDataSet(sid_t sid, const size_t maxSize); + virtual~ LocalDataSet(); //! Copying forbidden for now. diff --git a/datapoollocal/LocalPoolVector.h b/datapoollocal/LocalPoolVector.h index 593d26ab..591dd6f3 100644 --- a/datapoollocal/LocalPoolVector.h +++ b/datapoollocal/LocalPoolVector.h @@ -77,8 +77,7 @@ public: * @param dataSet * @param setReadWriteMode */ - LocalPoolVector(gp_id_t globalPoolId, - DataSetIF* dataSet = nullptr, + LocalPoolVector(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr, pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); /** @@ -87,7 +86,7 @@ public: * The user can work on this attribute just like he would on a local * array of this type. */ - T value[vectorSize]; + T value[vectorSize]= {}; /** * @brief The classes destructor is empty. * @details If commit() was not called, the local value is diff --git a/datapoollocal/LocalPoolVector.tpp b/datapoollocal/LocalPoolVector.tpp index 98eb27f9..5b2089b3 100644 --- a/datapoollocal/LocalPoolVector.tpp +++ b/datapoollocal/LocalPoolVector.tpp @@ -16,7 +16,6 @@ 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): diff --git a/datapoollocal/StaticLocalDataSet.h b/datapoollocal/StaticLocalDataSet.h index 0e51fb5b..4d1cc637 100644 --- a/datapoollocal/StaticLocalDataSet.h +++ b/datapoollocal/StaticLocalDataSet.h @@ -6,7 +6,8 @@ #include /** - * @brief This local dataset type is created on the stack. + * @brief This dataset type can be used to group related pool variables if the number of + * variables is fixed. * @details * This will is the primary data structure to organize pool variables into * sets which can be accessed via the housekeeping service interface or diff --git a/housekeeping/HousekeepingMessage.cpp b/housekeeping/HousekeepingMessage.cpp index 221f0a6f..5d732961 100644 --- a/housekeeping/HousekeepingMessage.cpp +++ b/housekeeping/HousekeepingMessage.cpp @@ -176,7 +176,7 @@ void HousekeepingMessage::setUpdateNotificationVariableCommand( void HousekeepingMessage::setUpdateSnapshotSetCommand(CommandMessage *command, sid_t sid, store_address_t storeId) { - command->setCommand(UPDATE_SNAPSHOT_VARIABLE); + command->setCommand(UPDATE_SNAPSHOT_SET); setSid(command, sid); command->setParameter3(storeId.raw); } diff --git a/housekeeping/HousekeepingPacketUpdate.h b/housekeeping/HousekeepingSnapshot.h similarity index 64% rename from housekeeping/HousekeepingPacketUpdate.h rename to housekeeping/HousekeepingSnapshot.h index 43ec0619..50afd4af 100644 --- a/housekeeping/HousekeepingPacketUpdate.h +++ b/housekeeping/HousekeepingSnapshot.h @@ -1,24 +1,37 @@ -#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ -#define FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ +#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGSNAPSHOT_H_ +#define FSFW_HOUSEKEEPING_HOUSEKEEPINGSNAPSHOT_H_ #include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialLinkedListAdapter.h" #include "../datapoollocal/LocalPoolDataSetBase.h" +#include "../datapoollocal/LocalPoolObjectBase.h" +#include "../timemanager/CCSDSTime.h" /** - * @brief This helper class will be used to serialize and deserialize - * update housekeeping packets into the store. + * @brief This helper class will be used to serialize and deserialize update housekeeping packets + * into the store. */ -class HousekeepingPacketUpdate: public SerializeIF { +class HousekeepingSnapshot: public SerializeIF { public: + /** - * Update packet constructor for datasets - * @param timeStamp - * @param timeStampSize - * @param hkData - * @param hkDataSize + * Update packet constructor for datasets. + * @param cdsShort If a CSD short timestamp is used, a reference should be + * supplied here + * @param dataSetPtr Pointer to the dataset instance to serialize or deserialize the + * data into */ - HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, + HousekeepingSnapshot(CCSDSTime::CDS_short* cdsShort, LocalPoolDataSetBase* dataSetPtr): + timeStamp(reinterpret_cast(cdsShort)), + timeStampSize(sizeof(CCSDSTime::CDS_short)), updateData(dataSetPtr) {}; + + /** + * Update packet constructor for datasets. + * @param timeStamp Pointer to the buffer where the timestamp will be stored. + * @param timeStampSize Size of the timestamp + * @param dataSetPtr Pointer to the dataset instance to deserialize the data into + */ + HousekeepingSnapshot(uint8_t* timeStamp, size_t timeStampSize, LocalPoolDataSetBase* dataSetPtr): timeStamp(timeStamp), timeStampSize(timeStampSize), updateData(dataSetPtr) {}; @@ -29,7 +42,7 @@ public: * @param timeStampSize * @param dataSetPtr */ - HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, + HousekeepingSnapshot(uint8_t* timeStamp, size_t timeStampSize, LocalPoolObjectBase* dataSetPtr): timeStamp(timeStamp), timeStampSize(timeStampSize), updateData(dataSetPtr) {}; @@ -89,4 +102,4 @@ private: }; -#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ */ +#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGSNAPSHOT_H_ */ diff --git a/osal/host/Clock.cpp b/osal/host/Clock.cpp index 88bf51d2..0b306349 100644 --- a/osal/host/Clock.cpp +++ b/osal/host/Clock.cpp @@ -53,8 +53,7 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { auto epoch = now.time_since_epoch(); time->tv_sec = std::chrono::duration_cast(epoch).count(); auto fraction = now - secondsChrono; - time->tv_usec = std::chrono::duration_cast( - fraction).count(); + time->tv_usec = std::chrono::duration_cast(fraction).count(); return HasReturnvaluesIF::RETURN_OK; #elif defined(LINUX) timespec timeUnix; @@ -67,7 +66,9 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { return HasReturnvaluesIF::RETURN_OK; #else #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; + sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl; +#else + sif::printWarning("Clock::getUptime: Not implemented for found OS!\n"); #endif return HasReturnvaluesIF::RETURN_FAILED; #endif diff --git a/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp b/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp index d43f3c80..b12d484f 100644 --- a/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp +++ b/unittest/tests/datapoollocal/LocalPoolManagerTest.cpp @@ -1,10 +1,16 @@ #include "LocalPoolOwnerBase.h" #include +#include + +#include #include #include +#include #include +#include #include +#include TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { @@ -14,7 +20,7 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() == retval::CATCH_OK); - REQUIRE(poolOwner->dataset.assignPointers() == retval::CATCH_OK); + //REQUIRE(poolOwner->dataset.assignPointers() == retval::CATCH_OK); MessageQueueMockBase* mqMock = poolOwner->getMockQueueHandle(); REQUIRE(mqMock != nullptr); CommandMessage messageSent; @@ -63,29 +69,76 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { HousekeepingMessage::HK_REPORT)); /* Clear message to avoid memory leak, our mock won't do it for us (yet) */ CommandMessageCleaner::clearCommandMessage(&messageSent); - /* we need to reset the subscription list because the pool owner - is a global object. */ - poolOwner->resetSubscriptionList(); + } SECTION("SnapshotUpdateTests") { - /* we need to reset the subscription list because the pool owner - is a global object. */ - poolOwner->resetSubscriptionList(); + /* Set the variables in the set to certain values. These are checked later. */ + { + PoolReadHelper readHelper(&poolOwner->dataset); + REQUIRE(readHelper.getReadResult() == retval::CATCH_OK); + poolOwner->dataset.localPoolVarUint8.value = 5; + poolOwner->dataset.localPoolVarFloat.value = -12.242; + poolOwner->dataset.localPoolUint16Vec.value[0] = 2; + poolOwner->dataset.localPoolUint16Vec.value[1] = 32; + poolOwner->dataset.localPoolUint16Vec.value[2] = 42932; + } /* Subscribe for snapshot generation on update. */ REQUIRE(poolOwner->subscribeWrapperSetUpdateSnapshot() == retval::CATCH_OK); poolOwner->dataset.setChanged(true); + + /* Store current time, we are going to check the (approximate) time equality later */ + CCSDSTime::CDS_short timeCdsNow; + timeval now; + Clock::getClock_timeval(&now); + CCSDSTime::convertToCcsds(&timeCdsNow, &now); + + /* Trigger generation of snapshot */ REQUIRE(poolOwner->poolManager.performHkOperation() == retval::CATCH_OK); REQUIRE(mqMock->wasMessageSent(&messagesSent) == true); CHECK(messagesSent == 1); + REQUIRE(mqMock->receiveMessage(&messageSent) == retval::CATCH_OK); + /* Check that snapshot was generated */ + CHECK(messageSent.getCommand() == static_cast( + HousekeepingMessage::UPDATE_SNAPSHOT_SET)); + /* Now we deserialize the snapshot into a new dataset instance */ + CCSDSTime::CDS_short cdsShort; + LocalPoolTestDataSet newSet; + HousekeepingSnapshot snapshot(&cdsShort, &newSet); + store_address_t storeId; + HousekeepingMessage::getUpdateSnapshotSetCommand(&messageSent, &storeId); + ConstAccessorPair accessorPair = tglob::getIpcStoreHandle()->getData(storeId); + REQUIRE(accessorPair.first == retval::CATCH_OK); + const uint8_t* readOnlyPtr = accessorPair.second.data(); + size_t sizeToDeserialize = accessorPair.second.size(); + CHECK(newSet.localPoolVarFloat.value == 0); + CHECK(newSet.localPoolVarUint8 == 0); + CHECK(newSet.localPoolUint16Vec.value[0] == 0); + CHECK(newSet.localPoolUint16Vec.value[1] == 0); + CHECK(newSet.localPoolUint16Vec.value[2] == 0); + /* Fill the dataset and timestamp */ + REQUIRE(snapshot.deSerialize(&readOnlyPtr, &sizeToDeserialize, + SerializeIF::Endianness::MACHINE) == retval::CATCH_OK); + /* Now we check that the snapshot is actually correct */ + CHECK(newSet.localPoolVarFloat.value == Catch::Approx(-12.242)); + CHECK(newSet.localPoolVarUint8 == 5); + CHECK(newSet.localPoolUint16Vec.value[0] == 2); + CHECK(newSet.localPoolUint16Vec.value[1] == 32); + CHECK(newSet.localPoolUint16Vec.value[2] == 42932); + /* Now we check that both times are equal */ + CHECK(cdsShort.pField == timeCdsNow.pField); + CHECK(cdsShort.dayLSB == Catch::Approx(timeCdsNow.dayLSB).margin(1)); + CHECK(cdsShort.dayMSB == Catch::Approx(timeCdsNow.dayMSB).margin(1)); + CHECK(cdsShort.msDay_h == Catch::Approx(timeCdsNow.msDay_h).margin(1)); + CHECK(cdsShort.msDay_hh == Catch::Approx(timeCdsNow.msDay_hh).margin(1)); + CHECK(cdsShort.msDay_l == Catch::Approx(timeCdsNow.msDay_l).margin(1)); + CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(1)); } SECTION("AdvancedTests") { - - /* Subscribe for variable update as well */ - REQUIRE(not poolOwner->dataset.hasChanged()); + /* Subscribe for variable update */ REQUIRE(poolOwner->subscribeWrapperVariableUpdate(lpool::uint8VarId) == retval::CATCH_OK); lp_var_t* poolVar = dynamic_cast*>( @@ -102,7 +155,6 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { 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); @@ -133,5 +185,10 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") { REQUIRE(mqMock->receiveMessage(&messageSent) == static_cast(MessageQueueIF::EMPTY)); } + + /* we need to reset the subscription list because the pool owner + is a global object. */ + poolOwner->resetSubscriptionList(); + mqMock->clearMessages(true); } diff --git a/unittest/tests/datapoollocal/LocalPoolOwnerBase.h b/unittest/tests/datapoollocal/LocalPoolOwnerBase.h index 353f7b4d..876ae5f5 100644 --- a/unittest/tests/datapoollocal/LocalPoolOwnerBase.h +++ b/unittest/tests/datapoollocal/LocalPoolOwnerBase.h @@ -20,33 +20,43 @@ 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); + +static const sid_t testSid = sid_t(objects::TEST_LOCAL_POOL_OWNER_BASE, testSetId); + +static const gp_id_t uint8VarGpid = gp_id_t(objects::TEST_LOCAL_POOL_OWNER_BASE, uint8VarId); +static const gp_id_t floatVarGpid = gp_id_t(objects::TEST_LOCAL_POOL_OWNER_BASE, floatVarId); +static const gp_id_t uint32Gpid = gp_id_t(objects::TEST_LOCAL_POOL_OWNER_BASE, uint32VarId); +static const gp_id_t uint16Vec3Gpid = gp_id_t(objects::TEST_LOCAL_POOL_OWNER_BASE, uint16Vec3Id); +static const gp_id_t uint64Vec2Id = gp_id_t(objects::TEST_LOCAL_POOL_OWNER_BASE, int64Vec2Id); } class LocalPoolTestDataSet: public LocalDataSet { public: + LocalPoolTestDataSet(): + LocalDataSet(lpool::testSid, lpool::dataSetMaxVariables) { + } + 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; - } +// 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; + lp_var_t localPoolVarUint8 = lp_var_t(lpool::uint8VarGpid, this); + lp_var_t localPoolVarFloat = lp_var_t(lpool::floatVarGpid, this); + lp_vec_t localPoolUint16Vec = lp_vec_t(lpool::uint16Vec3Gpid, this); private: }; @@ -170,7 +180,7 @@ public: ReturnValue_t subscribeWrapperVariableUpdate(lp_id_t localPoolId) { return poolManager.subscribeForVariableUpdateMessages(localPoolId, - MessageQueueIF::NO_QUEUE, objects::NO_OBJECT, false); + MessageQueueIF::NO_QUEUE, objects::HK_RECEIVER_MOCK, false); } void resetSubscriptionList() {