diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index e9c63b78060a66d19fee0b59c83f59e4fa916454..2afbb623502a0f027af9f76d921738bd98747e05 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -11,15 +11,15 @@ <option name="SPACE_BEFORE_REFERENCE_IN_DECLARATION" value="false" /> <option name="SPACE_AFTER_REFERENCE_IN_DECLARATION" value="true" /> </Objective-C> - <Objective-C-extensions> + <clangFormatSettings> + <option name="ENABLED" value="true" /> + </clangFormatSettings> + <files> <extensions> <pair source="cpp" header="hpp" fileNamingConvention="PASCAL_CASE" /> <pair source="c" header="h" fileNamingConvention="NONE" /> </extensions> - </Objective-C-extensions> - <clangFormatSettings> - <option name="ENABLED" value="true" /> - </clangFormatSettings> + </files> <codeStyleSettings language="ObjectiveC"> <option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" /> <option name="ALIGN_MULTILINE_FOR" value="false" /> diff --git a/CMakeLists.txt b/CMakeLists.txt index 37310bc340db176e5788eafbd34689ae763630d1..3e5c2dee5446dfbb812365dd96086ae1574fbfd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ add_library(common OBJECT src/MessageParser.cpp src/ServicePool.cpp src/Helpers/CRCHelper.cpp + src/Helpers/PacketStore.cpp src/Time/UTCTimestamp.cpp src/Services/EventReportService.cpp src/Services/MemoryManagementService.cpp @@ -39,6 +40,7 @@ add_library(common OBJECT src/Services/EventActionService.cpp src/Services/TimeBasedSchedulingService.cpp src/Services/FunctionManagementService.cpp + src/Services/StorageAndRetrievalService.cpp src/Services/HousekeepingService.cpp src/Services/ParameterStatisticsService.cpp src/Services/OnBoardMonitoringService.cpp diff --git a/inc/ECSS_Definitions.hpp b/inc/ECSS_Definitions.hpp index e5df0e60eca65475428e28b60c79df2e350dfc67..01fc74b1db03fab7a40ea7d22c3a58d5c46a4429 100644 --- a/inc/ECSS_Definitions.hpp +++ b/inc/ECSS_Definitions.hpp @@ -1,7 +1,7 @@ #ifndef ECSS_SERVICES_ECSS_DEFINITIONS_H #define ECSS_SERVICES_ECSS_DEFINITIONS_H -#include <stdint.h> +#include <cstdint> /** * @defgroup ECSSDefinitions ECSS Defined Constants * @@ -159,16 +159,43 @@ inline const uint8_t ECSSMaxStatisticParameters = 4; */ inline const bool SupportsStandardDeviation = true; +/** + * @brief the max number of bytes allowed for a packet store to handle in ST[15]. + */ +inline const uint16_t ECSSMaxPacketStoreSizeInBytes = 1000; + +/** + * @brief the max number of TM packets that a packet store in ST[15] can store + */ +inline const uint16_t ECSSMaxPacketStoreSize = 20; + +/** + * @brief the max number of packet stores that a packet selection subservice can handle in ST[15] + */ +inline const uint16_t ECSSMaxPacketStores = 4; + +/** + * @brief each packet store's id is an etl::string. So this defines the max size of a packet store ID in ST[15] + */ +inline const uint16_t ECSSPacketStoreIdSize = 15; /** * @brief Defines the max number of housekeeping structs that the housekeeping service can contain */ inline const uint8_t ECSSMaxHousekeepingStructures = 10; +/** + * Limits noting the minimum and maximum valid Virtual Channels used by the Storage and Retrieval subservice + */ +inline struct { + uint8_t min = 1; + uint8_t max = 10; +} VirtualChannelLimits; + /** * Maximum number of ST[12] Parameter Monitoring Definitions. */ inline const uint8_t ECSSMaxMonitoringDefinitions = 4; -/** @} */ +/** @} */ #endif // ECSS_SERVICES_ECSS_DEFINITIONS_H diff --git a/inc/ErrorHandler.hpp b/inc/ErrorHandler.hpp index 32d7f33308943e8649989ddf6f9cf5f1eb033880..bffa26ddb99f9bfc607acf557c2f111329a00a5f 100644 --- a/inc/ErrorHandler.hpp +++ b/inc/ErrorHandler.hpp @@ -77,18 +77,22 @@ public: * A Message that is included within another message is too large */ NestedMessageTooLarge = 11, + /** + * Request to copy packets in a time window, whose type is not recognized (ST(15)). + */ + InvalidTimeWindowType = 12, /** * A request to access a non existing housekeeping structure in ST[03] */ - NonExistentHousekeeping = 12, + NonExistentHousekeeping = 13, /** * Attempt to access an invalid parameter in ST[03] */ - NonExistentParameter = 13, + NonExistentParameter = 14, /** * Invalid TimeStamp parameters at creation */ - InvalidTimeStampInput = 14 + InvalidTimeStampInput = 15, }; /** @@ -156,99 +160,170 @@ public: */ GetNonExistingParameter = 8, /** - * Attempt to add definition to the struct map but its already full. (ST[19]) + * Attempt to access a packet store that does not exist (ST[15]) + */ + NonExistingPacketStore = 9, + /** + * Attempt to change the start time tag of a packet store, whose open retrieval status is in progress (ST[15]) + */ + SetPacketStoreWithOpenRetrievalInProgress = 10, + /** + * Attempt to resume open retrieval of a packet store, whose by-time-range retrieval is enabled (ST[15]) */ - EventActionDefinitionsMapIsFull = 9, + SetPacketStoreWithByTimeRangeRetrieval = 11, + /** + * Attempt to access a packet with by-time range retrieval enabled (ST[15]) + */ + GetPacketStoreWithByTimeRangeRetrieval = 12, + /** + * Attempt to start the by-time-range retrieval of packet store, whose open retrieval is in progress (ST[15]) + */ + GetPacketStoreWithOpenRetrievalInProgress = 13, + /** + * Attempt to start by-time-range retrieval when its already enabled (ST[15]) + */ + ByTimeRangeRetrievalAlreadyEnabled = 14, + /** + * Attempt to create packet store, whose ID already exists (ST[15]) + */ + AlreadyExistingPacketStore = 15, + /** + * Attempt to create packet store, when the max number of packet stores is already reached (ST[15]) + */ + MaxNumberOfPacketStoresReached = 16, + /** + * Attempt to access a packet store with the storage status enabled (ST[15]) + */ + GetPacketStoreWithStorageStatusEnabled = 17, + /** + * Attempt to delete a packet whose by time range retrieval status is enabled (ST[15]) + */ + DeletionOfPacketWithByTimeRangeRetrieval = 18, + /** + * Attempt to delete a packet whose open retrieval status is in progress (ST[15]) + */ + DeletionOfPacketWithOpenRetrievalInProgress = 19, + /** + * Requested a time window where the start time is larger than the end time (ST[15]) + */ + InvalidTimeWindow = 20, + /** + * Attempt to copy a packet store to a destination packet store that is not empty (ST[15]) + */ + DestinationPacketStoreNotEmtpy = 21, + /** + * Attempt to set a reporting rate which is smaller than the parameter sampling rate. + * ST[04] + */ + InvalidReportingRateError = 22, + /** + * Attempt to add definition to the struct map but its already full.(ST[19]) + */ + EventActionDefinitionsMapIsFull = 23, /** * Attempt to report/delete non existing housekeeping structure (ST[03]) */ - RequestedNonExistingStructure = 10, + RequestedNonExistingStructure = 24, /** * Attempt to create already created structure (ST[03]) */ - RequestedAlreadyExistingStructure = 11, + RequestedAlreadyExistingStructure = 25, /** * Attempt to delete structure which has the periodic reporting status enabled (ST[03]) as per 6.3.3.5.2(d-2) */ - RequestedDeletionOfEnabledHousekeeping = 12, + RequestedDeletionOfEnabledHousekeeping = 26, /** * Attempt to append a new parameter ID to a housekeeping structure, but the ID is already in the structure * (ST[03]) */ - AlreadyExistingParameter = 13, + AlreadyExistingParameter = 27, /** * Attempt to append a new parameter id to a housekeeping structure, but the periodic generation status is * enabled (ST[03]) */ - RequestedAppendToEnabledHousekeeping = 14, + RequestedAppendToEnabledHousekeeping = 28, /** * Attempt to create a new housekeeping structure in Housekeeping Service, when the maximum number of * housekeeping structures is already reached (ST[03]) */ - ExceededMaxNumberOfHousekeepingStructures = 15, + ExceededMaxNumberOfHousekeepingStructures = 29, /** * Attempt to add a new simply commutated parameter in a specific housekeeping structure, but the maximum * number of simply commutated parameters for this structure is already reached (ST[03]) */ - ExceededMaxNumberOfSimplyCommutatedParameters = 16, - /* Attempt to set a reporting rate which is smaller than the parameter sampling rate. - * ST[04] - */ - InvalidReportingRateError = 17, + ExceededMaxNumberOfSimplyCommutatedParameters = 30, /** - * Attempt to set a sampling rate which is greater than the parameter reporting rate. + * Attempt to set a reporting rate which is smaller than the parameter sampling rate. * ST[04] */ - InvalidSamplingRateError = 18, + InvalidSamplingRateError = 31, /** * Attempt to add new statistic definition but the maximum number is already reached (ST[04]) */ - MaxStatisticDefinitionsReached = 19, + MaxStatisticDefinitionsReached = 32, + /** + * Attempt to set the virtual channel of a packet store to a invalid value (ST[15]) + */ + InvalidVirtualChannel = 33, + /** + * Attempt to delete a packet store, whose storage status is enabled (ST[15]) + */ + DeletionOfPacketStoreWithStorageStatusEnabled = 34, + /** + * Attempt to copy packets from a packet store to another, but either no packet timestamp falls inside the + * specified timestamp, or more than one boolean argument were given as true in the 'copyPacketsTo' function + * (ST[15]) + */ + CopyOfPacketsFailed = 35, + /** + * Attempt to set a packet store size to a value that the available memory cannot handle (ST[15]). + */ + UnableToHandlePacketStoreSize = 36, /** * Attempt to delete all parameter monitoring definitions but the Parameter Monitoring Function Status is * enabled. */ - InvalidRequestToDeleteAllParameterMonitoringDefinitions = 20, + InvalidRequestToDeleteAllParameterMonitoringDefinitions = 37, /** * Attempt to delete one parameter monitoring definition but its Parameter Monitoring Status is * enabled. */ - InvalidRequestToDeleteParameterMonitoringDefinition = 21, + InvalidRequestToDeleteParameterMonitoringDefinition = 38, /** * Attempt to add a parameter that already exists to the Parameter Monitoring List. */ - AddAlreadyExistingParameter = 22, + AddAlreadyExistingParameter = 39, /** * Attempt to add a parameter in the Parameter Monitoring List but it's full */ - ParameterMonitoringListIsFull = 23, + ParameterMonitoringListIsFull = 40, /** * Attempt to add or modify a limit check parameter monitoring definition, but the high limit is lower than * the low limit. */ - HighLimitIsLowerThanLowLimit = 24, + HighLimitIsLowerThanLowLimit = 41, /** * Attempt to add or modify a delta check parameter monitoring definition, but the high threshold is lower than * the low threshold. */ - HighThresholdIsLowerThanLowThreshold = 25, + HighThresholdIsLowerThanLowThreshold = 42, /** * Attempt to modify a non existent Parameter Monitoring definition. */ - ModifyParameterNotInTheParameterMonitoringList = 26, + ModifyParameterNotInTheParameterMonitoringList = 43, /** * Attempt to modify a parameter monitoring definition, but the instruction refers to a monitored parameter * that is not the one used in that parameter monitoring definition. */ - DifferentParameterMonitoringDefinitionAndMonitoredParameter = 27, + DifferentParameterMonitoringDefinitionAndMonitoredParameter = 44, /** * Attempt to get a parameter monitoring definition that does not exist. */ - GetNonExistingParameterMonitoringDefinition = 28, + GetNonExistingParameterMonitoringDefinition = 45, /** * Request to report a non existent parameter monitoring definition. */ - ReportParameterNotInTheParameterMonitoringList = 29 + ReportParameterNotInTheParameterMonitoringList = 46 }; /** diff --git a/inc/Helpers/PacketStore.hpp b/inc/Helpers/PacketStore.hpp new file mode 100644 index 0000000000000000000000000000000000000000..37c2fdeca0d29796682f2dab0525659bab050f5d --- /dev/null +++ b/inc/Helpers/PacketStore.hpp @@ -0,0 +1,82 @@ +#ifndef ECSS_SERVICES_PACKETSTORE_HPP +#define ECSS_SERVICES_PACKETSTORE_HPP + +#include "ECSS_Definitions.hpp" +#include "ErrorHandler.hpp" +#include "etl/deque.h" +#include "Message.hpp" + +/** + * This is the Packet Store class, needed for the Storage-Retrieval Service. The purpose of the packet-store is to + * store all the TM packets transmitted by the other Services. + */ +class PacketStore { +public: + /** + * The virtual channel used to transmit the packet store to the ground station. There is an upper and a lower + * bound for the virtual channels, defined in 'ECSSDefinitions' file. + */ + uint8_t virtualChannel; + /** + * The time-tag that defines the starting point of the open retrieval process, meaning that we retrieve packets, + * starting from the open-retrieval-start-time-tag until the latest packet. + */ + uint32_t openRetrievalStartTimeTag = 0; + /** + * The start time of a by-time-range retrieval process, i.e. retrieval of packets between two specified time-tags. + */ + uint32_t retrievalStartTime = 0; + /** + * The end time of a by-time-range retrieval process, i.e. retrieval of packets between two specified time-tags. + */ + uint32_t retrievalEndTime = 0; + /** + * The maximum size of the packet store, in bytes. + * + * @todo: add a way of defining each packets store's size in bytes + */ + uint64_t sizeInBytes; + + /** + * Whether the insertion of packets stores in the packet-store should cyclically overwrite older packets, or be + * suspended when the packet-store is full. + */ + enum PacketStoreType : uint8_t { Circular = 0, Bounded = 1 }; + + /** + * Whether the open retrieval status of the packet-store is in progress or not. + */ + enum PacketStoreOpenRetrievalStatus : bool { Suspended = false, InProgress = true }; + + /** ++ * Whether the storage of TM packets is enabled for this packet store + */ + bool storageStatus = false; + + /** + * Whether the by-time-range retrieval of packet stores is enabled for this packet-store. + */ + bool byTimeRangeRetrievalStatus = false; + PacketStoreType packetStoreType; + PacketStoreOpenRetrievalStatus openRetrievalStatus; + + PacketStore() = default; + + /** + * A queue containing the TM messages stored by the packet store. Every TM is accompanied by its timestamp. + * + * @note A convention is made that this should be filled out using `push_back` and NOT `push_front`, dictating that + * earlier packets are placed in the front position. So removing the earlier packets is done with `pop_front`. + * + * old packets <----------> new packets + * [][][][][][][][][][][][][][][][][][][] <--- deque + */ + etl::deque<std::pair<uint32_t, Message>, ECSSMaxPacketStoreSize> storedTelemetryPackets; + + /** + * Returns the sum of the sizes of the packets stored in this PacketStore, in bytes. + */ + uint16_t calculateSizeInBytes(); +}; + +#endif diff --git a/inc/Platform/x86/ECSS_Configuration.hpp b/inc/Platform/x86/ECSS_Configuration.hpp index c03814e5ad812c932c576df81c0d21917ca659dd..3b27fecf53cd2ad67e162144c2f9f1c5d6bd3774 100644 --- a/inc/Platform/x86/ECSS_Configuration.hpp +++ b/inc/Platform/x86/ECSS_Configuration.hpp @@ -31,9 +31,10 @@ #define SERVICE_PARAMETER ///< Compile ST[20] parameter management #define SERVICE_PARAMETERSTATISTICS ///< Compile ST[04] parameter statistics #define SERVICE_REQUESTVERIFICATION ///< Compile ST[01] request verification -#define SERVICE_TEST ///< Compile ST[17] test -#define SERVICE_TIME ///< Compile ST[09] time management -#define SERVICE_TIMESCHEDULING ///< Compile ST[11] time-based scheduling +#define SERVICE_STORAGEANDRETRIEVAL ///< Compile ST[15] storage-and-retrieval of tm packets +#define SERVICE_TEST ///< Compile ST[17] test +#define SERVICE_TIME ///< Compile ST[09] time management +#define SERVICE_TIMESCHEDULING ///< Compile ST[11] time-based scheduling #endif /** @} */ diff --git a/inc/ServicePool.hpp b/inc/ServicePool.hpp index a916cb82cee3e93b7560c4c7d07ec1b9d51239a0..9dbb533a2640a1d96abed2543d33129edf5b5314 100644 --- a/inc/ServicePool.hpp +++ b/inc/ServicePool.hpp @@ -11,6 +11,7 @@ #include "Services/TestService.hpp" #include "Services/MemoryManagementService.hpp" #include "Services/FunctionManagementService.hpp" +#include "Services/StorageAndRetrievalService.hpp" #include "Services/HousekeepingService.hpp" #include "Services/ParameterStatisticsService.hpp" #include "Services/OnBoardMonitoringService.hpp" @@ -77,6 +78,10 @@ public: RequestVerificationService requestVerification; #endif +#ifdef SERVICE_STORAGEANDRETRIEVAL + StorageAndRetrievalService storageAndRetrieval; +#endif + #ifdef SERVICE_TEST TestService testService; #endif diff --git a/inc/Services/StorageAndRetrievalService.hpp b/inc/Services/StorageAndRetrievalService.hpp new file mode 100644 index 0000000000000000000000000000000000000000..95142327f8d73d2e272de7cd5d192dec4252d33d --- /dev/null +++ b/inc/Services/StorageAndRetrievalService.hpp @@ -0,0 +1,353 @@ +#ifndef ECSS_SERVICES_STORAGEANDRETRIEVALSERVICE_HPP +#define ECSS_SERVICES_STORAGEANDRETRIEVALSERVICE_HPP + +#include "ECSS_Definitions.hpp" +#include "Service.hpp" +#include "ErrorHandler.hpp" +#include "Helpers/PacketStore.hpp" +#include "etl/map.h" + +/** + * Implementation of ST[15] Storage and Retrieval Service, as defined in ECSS-E-ST-70-41C. + * + * This Service: + * - provides the capability to select reports generated by other services and store them into packet stores. + * - allows the ground system to manage the reports in the packet stores and request their downlink. + * + * @author Konstantinos Petridis <petridkon@gmail.com> + */ +class StorageAndRetrievalService : public Service { +public: + /** + * The type of timestamps that the Storage and Retrieval Subservice assigns to each incoming packet. + */ + enum TimeStampType : uint8_t { StorageBased = 0, PacketBased = 1 }; + + /** + * Different types of packet retrieval from a packet store, relative to a specified time-tag. + */ + enum TimeWindowType : uint8_t { FromTagToTag = 0, AfterTimeTag = 1, BeforeTimeTag = 2 }; + + /** + * The type of timestamps that the subservice sets to each incoming telemetry packet. + */ + const TimeStampType timeStamping = PacketBased; + +private: + typedef String<ECSSPacketStoreIdSize> packetStoreId; + + /** + * All packet stores, held by the Storage and Retrieval Service. Each packet store has its ID as key. + */ + etl::map<packetStoreId, PacketStore, ECSSMaxPacketStores> packetStores; + + /** + * Helper function that reads the packet store ID string from a TM[15] message + */ + static inline String<ECSSPacketStoreIdSize> readPacketStoreId(Message& message); + + /** + * Helper function that, given a time-limit, deletes every packet stored in the specified packet-store, up to the + * requested time. + * + * @param packetStoreId required to access the correct packet store. + * @param timeLimit the limit until which, packets are deleted. + */ + void deleteContentUntil(const String<ECSSPacketStoreIdSize>& packetStoreId, uint32_t timeLimit); + + /** + * Copies all TM packets from source packet store to the target packet-store, that fall between the two specified + * time-tags as per 6.15.3.8.4.d(1) of the standard. + * + * @param request used to read the time-tags, the packet store IDs and to raise errors. + */ + void copyFromTagToTag(Message& request); + + /** + * Copies all TM packets from source packet store to the target packet-store, whose time-stamp is after the + * specified time-tag as per 6.15.3.8.4.d(2) of the standard. + * + * @param request used to read the time-tag, the packet store IDs and to raise errors. + */ + void copyAfterTimeTag(Message& request); + + /** + * Copies all TM packets from source packet store to the target packet-store, whose time-stamp is before the + * specified time-tag as per 6.15.3.8.4.d(3) of the standard. + * + * @param request used to raise errors. + */ + void copyBeforeTimeTag(Message& request); + + /** + * Checks if the two requested packet stores exist. + * + * @param fromPacketStoreId the source packet store, whose content is to be copied. + * @param toPacketStoreId the target packet store, which is going to receive the new content. + * @param request used to raise errors. + * @return true if an error has occurred. + */ + bool checkPacketStores(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + const String<ECSSPacketStoreIdSize>& toPacketStoreId, Message& request); + + /** + * Checks whether the time window makes logical sense (end time should be after the start time) + * + * @param request used to raise errors. + */ + static bool checkTimeWindow(uint32_t startTime, uint32_t endTime, Message& request); + + /** + * Checks if the destination packet store is empty, in order to proceed with the copying of packets. + * + * @param toPacketStoreId the target packet store, which is going to receive the new content. Needed for error + * checking. + * @param request used to raise errors. + */ + bool checkDestinationPacketStore(const String<ECSSPacketStoreIdSize>& toPacketStoreId, Message& request); + + /** + * Checks if there are no stored timestamps that fall between the two specified time-tags. + * + * @param fromPacketStoreId the source packet store, whose content is to be copied. Needed for error checking. + * @param request used to raise errors. + * + * @note + * This function assumes that `startTime` and `endTime` are valid at this point, so any necessary error checking + * regarding these variables, should have already occurred. + */ + bool noTimestampInTimeWindow(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, uint32_t startTime, + uint32_t endTime, Message& request); + + /** + * Checks if there are no stored timestamps that fall between the two specified time-tags. + * + * @param isAfterTimeTag true indicates that we are examining the case of AfterTimeTag. Otherwise, we are referring + * to the case of BeforeTimeTag. + * @param request used to raise errors. + * @param fromPacketStoreId the source packet store, whose content is to be copied. + */ + bool noTimestampInTimeWindow(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, uint32_t timeTag, + Message& request, bool isAfterTimeTag); + + /** + * Performs all the necessary error checking for the case of FromTagToTag copying of packets. + * + * @param fromPacketStoreId the source packet store, whose content is to be copied. + * @param toPacketStoreId the target packet store, which is going to receive the new content. + * @param request used to raise errors. + * @return true if an error has occurred. + */ + bool failedFromTagToTag(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + const String<ECSSPacketStoreIdSize>& toPacketStoreId, uint32_t startTime, + uint32_t endTime, Message& request); + + /** + * Performs all the necessary error checking for the case of AfterTimeTag copying of packets. + * + * @param fromPacketStoreId the source packet store, whose content is to be copied. + * @param toPacketStoreId the target packet store, which is going to receive the new content. + * @param request used to raise errors. + * @return true if an error has occurred. + */ + bool failedAfterTimeTag(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + const String<ECSSPacketStoreIdSize>& toPacketStoreId, uint32_t startTime, + Message& request); + + /** + * Performs all the necessary error checking for the case of BeforeTimeTag copying of packets. + * + * @param fromPacketStoreId the source packet store, whose content is to be copied. + * @param toPacketStoreId the target packet store, which is going to receive the new content. + * @param request used to raise errors. + * @return true if an error has occurred. + */ + bool failedBeforeTimeTag(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + const String<ECSSPacketStoreIdSize>& toPacketStoreId, uint32_t endTime, + Message& request); + + /** + * Performs the necessary error checking for a request to start the by-time-range retrieval process. + * + * @param request used to raise errors. + * @return true if an error has occurred. + */ + bool failedStartOfByTimeRangeRetrieval(const String<ECSSPacketStoreIdSize>& packetStoreId, Message& request); + + /** + * Forms the content summary of the specified packet-store and appends it to a report message. + */ + void createContentSummary(Message& report, const String<ECSSPacketStoreIdSize>& packetStoreId); + +public: + inline static const uint8_t ServiceType = 15; + + enum MessageType : uint8_t { + EnableStorageInPacketStores = 1, + DisableStorageInPacketStores = 2, + StartByTimeRangeRetrieval = 9, + DeletePacketStoreContent = 11, + ReportContentSummaryOfPacketStores = 12, + PacketStoreContentSummaryReport = 13, + ChangeOpenRetrievalStartingTime = 14, + ResumeOpenRetrievalOfPacketStores = 15, + SuspendOpenRetrievalOfPacketStores = 16, + AbortByTimeRangeRetrieval = 17, + ReportStatusOfPacketStores = 18, + PacketStoresStatusReport = 19, + CreatePacketStores = 20, + DeletePacketStores = 21, + ReportConfigurationOfPacketStores = 22, + PacketStoreConfigurationReport = 23, + CopyPacketsInTimeWindow = 24, + ResizePacketStores = 25, + ChangeTypeToCircular = 26, + ChangeTypeToBounded = 27, + ChangeVirtualChannel = 28 + }; + + StorageAndRetrievalService() = default; + + /** + * Adds new packet store into packet stores. + */ + void addPacketStore(const String<ECSSPacketStoreIdSize>& packetStoreId, const PacketStore& packetStore); + + /** + * Adds telemetry to the specified packet store and timestamps it. + */ + void addTelemetryToPacketStore(const String<ECSSPacketStoreIdSize>& packetStoreId, uint32_t timestamp); + + /** + * Deletes the content from all the packet stores. + */ + void resetPacketStores(); + + /** + * Returns the number of existing packet stores. + */ + uint16_t currentNumberOfPacketStores(); + + /** + * Returns the packet store with the specified packet store ID. + */ + PacketStore& getPacketStore(const String<ECSSPacketStoreIdSize>& packetStoreId); + + /** + * Returns true if the specified packet store is present in packet stores. + */ + bool packetStoreExists(const String<ECSSPacketStoreIdSize>& packetStoreId); + + /** + * Given a request that contains a number N, followed by N packet store IDs, this method calls function on every + * packet store. Implemented to reduce duplication. If N = 0, then function is applied to all packet stores. + * Incorrect packet store IDs are ignored and generate an error. + + * @param function the job to be done after the error checking. + */ + void executeOnPacketStores(Message& request, const std::function<void(PacketStore&)>& function); + + /** + * TC[15,1] request to enable the packet stores' storage function + */ + void enableStorageFunction(Message& request); + + /** + * TC[15,2] request to disable the packet stores' storage function + */ + void disableStorageFunction(Message& request); + + /** + * TC[15,9] start the by-time-range retrieval of packet stores + */ + void startByTimeRangeRetrieval(Message& request); + + /** + * TC[15,11] delete the packet store content up to the specified time + */ + void deletePacketStoreContent(Message& request); + + /** + * This function takes a TC[15,12] 'report the packet store content summary' as argument and responds with a TM[15, + * 13] 'packet store content summary report' report message. + */ + void packetStoreContentSummaryReport(Message& request); + + /** + * TC[15,14] change the open retrieval start time tag + */ + void changeOpenRetrievalStartTimeTag(Message& request); + + /** + * TC[15,15] resume the open retrieval of packet stores + */ + void resumeOpenRetrievalOfPacketStores(Message& request); + + /** + * TC[15,16] suspend the open retrieval of packet stores + */ + void suspendOpenRetrievalOfPacketStores(Message& request); + + /** + * TC[15,17] abort the by-time-range retrieval of packet stores + */ + void abortByTimeRangeRetrieval(Message& request); + + /** + * This function takes a TC[15,18] 'report the status of packet stores' request as argument and responds with a + * TM[15,19] 'packet stores status' report message. + */ + void packetStoresStatusReport(Message& request); + + /** + * TC[15,20] create packet stores + */ + void createPacketStores(Message& request); + + /** + * TC[15,21] delete packet stores + */ + void deletePacketStores(Message& request); + + /** + * This function takes a TC[15,22] 'report the packet store configuration' as argument and responds with a TM[15, + * 23] 'packet store configuration report' report message. + */ + void packetStoreConfigurationReport(Message& request); + + /** + * TC[15,24] copy the packets contained into a packet store, selected by the time window + */ + void copyPacketsInTimeWindow(Message& request); + + /** + * TC[15,25] resize packet stores + */ + void resizePacketStores(Message& request); + + /** + * TC[15,26] change the packet store type to circular + */ + void changeTypeToCircular(Message& request); + + /** + * TC[15,27] change the packet store type to bounded + */ + void changeTypeToBounded(Message& request); + + /** + * TC[15,28] change the virtual channel used by a packet store + */ + void changeVirtualChannel(Message& request); + + /** + * It is responsible to call the suitable function that executes a telecommand packet. The source of that packet + * is the ground station. + * + * @note This function is called from the main execute() that is defined in the file MessageParser.hpp + * @param request Contains the necessary parameters to call the suitable subservice + */ + void execute(Message& request); +}; + +#endif diff --git a/src/Helpers/PacketStore.cpp b/src/Helpers/PacketStore.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96a0ad6137664293d1ac5d8bc5008ec3a947a560 --- /dev/null +++ b/src/Helpers/PacketStore.cpp @@ -0,0 +1,9 @@ +#include "Helpers/PacketStore.hpp" + +uint16_t PacketStore::calculateSizeInBytes() { + uint16_t size = 0; + for (auto& tmPacket : storedTelemetryPackets) { + size += tmPacket.second.dataSize; + } + return size; +} diff --git a/src/MessageParser.cpp b/src/MessageParser.cpp index b34fc13d3c874609fa593718f9285c2c0e010a0f..d756549295a1750a7a45cc0c3d628a50af055a97 100644 --- a/src/MessageParser.cpp +++ b/src/MessageParser.cpp @@ -1,9 +1,10 @@ +#include "MessageParser.hpp" #include <ServicePool.hpp> +#include <iostream> #include "ErrorHandler.hpp" -#include "MessageParser.hpp" -#include "macros.hpp" -#include "Services/RequestVerificationService.hpp" #include "Helpers/CRCHelper.hpp" +#include "Services/RequestVerificationService.hpp" +#include "macros.hpp" void MessageParser::execute(Message& message) { switch (message.serviceType) { @@ -44,6 +45,11 @@ void MessageParser::execute(Message& message) { break; #endif +#ifdef SERVICE_STORAGEANDRETRIEVAL + case StorageAndRetrievalService::ServiceType: + Services.storageAndRetrieval.execute(message); +#endif + #ifdef SERVICE_ONBOARDMONITORING case OnBoardMonitoringService::ServiceType: Services.onBoardMonitoringService.execute(message); @@ -188,7 +194,7 @@ String<CCSDSMaxMessageSize> MessageParser::compose(const Message& message) { // Parts of the header uint16_t packetId = message.applicationId; - packetId |= (1U << 11U); // Secondary header flag + packetId |= (1U << 11U); // Secondary header flag packetId |= (message.packetType == Message::TC) ? (1U << 12U) : (0U); // Ignore-MISRA uint16_t packetSequenceControl = message.packetSequenceCount | (3U << 14U); uint16_t packetDataLength = ecssMessage.size(); diff --git a/src/Services/StorageAndRetrievalService.cpp b/src/Services/StorageAndRetrievalService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23f06f48b380f5359ed367787e32a95a057ab27c --- /dev/null +++ b/src/Services/StorageAndRetrievalService.cpp @@ -0,0 +1,810 @@ +#include "Services/StorageAndRetrievalService.hpp" + +String<ECSSPacketStoreIdSize> StorageAndRetrievalService::readPacketStoreId(Message& message) { + uint8_t packetStoreId[ECSSPacketStoreIdSize]; + message.readString(packetStoreId, ECSSPacketStoreIdSize); + return packetStoreId; +} + +void StorageAndRetrievalService::deleteContentUntil(const String<ECSSPacketStoreIdSize>& packetStoreId, + uint32_t timeLimit) { + auto& telemetryPackets = packetStores[packetStoreId].storedTelemetryPackets; + while (not telemetryPackets.empty() and telemetryPackets.front().first <= timeLimit) { + telemetryPackets.pop_front(); + } +} + +void StorageAndRetrievalService::copyFromTagToTag(Message& request) { + uint32_t startTime = request.readUint32(); + uint32_t endTime = request.readUint32(); + + auto fromPacketStoreId = readPacketStoreId(request); + auto toPacketStoreId = readPacketStoreId(request); + + if (failedFromTagToTag(fromPacketStoreId, toPacketStoreId, startTime, endTime, request)) { + return; + } + + for (auto& packet : packetStores[fromPacketStoreId].storedTelemetryPackets) { + if (packet.first < startTime) { + continue; + } + if (packet.first > endTime) { + break; + } + packetStores[toPacketStoreId].storedTelemetryPackets.push_back(packet); + } +} + +void StorageAndRetrievalService::copyAfterTimeTag(Message& request) { + uint32_t startTime = request.readUint32(); + + auto fromPacketStoreId = readPacketStoreId(request); + auto toPacketStoreId = readPacketStoreId(request); + + if (failedAfterTimeTag(fromPacketStoreId, toPacketStoreId, startTime, request)) { + return; + } + + for (auto& packet : packetStores[fromPacketStoreId].storedTelemetryPackets) { + if (packet.first < startTime) { + continue; + } + packetStores[toPacketStoreId].storedTelemetryPackets.push_back(packet); + } +} + +void StorageAndRetrievalService::copyBeforeTimeTag(Message& request) { + uint32_t endTime = request.readUint32(); + + auto fromPacketStoreId = readPacketStoreId(request); + auto toPacketStoreId = readPacketStoreId(request); + + if (failedBeforeTimeTag(fromPacketStoreId, toPacketStoreId, endTime, request)) { + return; + } + + for (auto& packet : packetStores[fromPacketStoreId].storedTelemetryPackets) { + if (packet.first > endTime) { + break; + } + packetStores[toPacketStoreId].storedTelemetryPackets.push_back(packet); + } +} + +bool StorageAndRetrievalService::checkPacketStores(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + const String<ECSSPacketStoreIdSize>& toPacketStoreId, + Message& request) { + if (packetStores.find(fromPacketStoreId) == packetStores.end() or + packetStores.find(toPacketStoreId) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + return false; + } + return true; +} + +bool StorageAndRetrievalService::checkTimeWindow(uint32_t startTime, uint32_t endTime, Message& request) { + if (startTime >= endTime) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::InvalidTimeWindow); + return true; + } + return false; +} + +bool StorageAndRetrievalService::checkDestinationPacketStore(const String<ECSSPacketStoreIdSize>& toPacketStoreId, + Message& request) { + if (not packetStores[toPacketStoreId].storedTelemetryPackets.empty()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::DestinationPacketStoreNotEmtpy); + return true; + } + return false; +} + +bool StorageAndRetrievalService::noTimestampInTimeWindow(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + uint32_t startTime, uint32_t endTime, Message& request) { + if (endTime < packetStores[fromPacketStoreId].storedTelemetryPackets.front().first || + startTime > packetStores[fromPacketStoreId].storedTelemetryPackets.back().first) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::CopyOfPacketsFailed); + return true; + } + return false; +} + +bool StorageAndRetrievalService::noTimestampInTimeWindow(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + uint32_t timeTag, Message& request, bool isAfterTimeTag) { + if (isAfterTimeTag) { + if (timeTag > packetStores[fromPacketStoreId].storedTelemetryPackets.back().first) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::CopyOfPacketsFailed); + return true; + } + return false; + } else if (timeTag < packetStores[fromPacketStoreId].storedTelemetryPackets.front().first) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::CopyOfPacketsFailed); + return true; + } + return false; +} + +bool StorageAndRetrievalService::failedFromTagToTag(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + const String<ECSSPacketStoreIdSize>& toPacketStoreId, + uint32_t startTime, uint32_t endTime, Message& request) { + return (not checkPacketStores(fromPacketStoreId, toPacketStoreId, request) or + checkTimeWindow(startTime, endTime, request) or checkDestinationPacketStore(toPacketStoreId, request) or + noTimestampInTimeWindow(fromPacketStoreId, startTime, endTime, request)); +} + +bool StorageAndRetrievalService::failedAfterTimeTag(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + const String<ECSSPacketStoreIdSize>& toPacketStoreId, + uint32_t startTime, Message& request) { + return (not checkPacketStores(fromPacketStoreId, toPacketStoreId, request) or + checkDestinationPacketStore(toPacketStoreId, request) or + noTimestampInTimeWindow(fromPacketStoreId, startTime, request, true)); +} + +bool StorageAndRetrievalService::failedBeforeTimeTag(const String<ECSSPacketStoreIdSize>& fromPacketStoreId, + const String<ECSSPacketStoreIdSize>& toPacketStoreId, + uint32_t endTime, Message& request) { + return (not checkPacketStores(fromPacketStoreId, toPacketStoreId, request) or + checkDestinationPacketStore(toPacketStoreId, request) or + noTimestampInTimeWindow(fromPacketStoreId, endTime, request, false)); +} + +void StorageAndRetrievalService::createContentSummary(Message& report, + const String<ECSSPacketStoreIdSize>& packetStoreId) { + uint32_t oldestStoredPacketTime = packetStores[packetStoreId].storedTelemetryPackets.front().first; + report.appendUint32(oldestStoredPacketTime); + + uint32_t newestStoredPacketTime = packetStores[packetStoreId].storedTelemetryPackets.back().first; + report.appendUint32(newestStoredPacketTime); + + report.appendUint32(packetStores[packetStoreId].openRetrievalStartTimeTag); + + auto filledPercentage1 = static_cast<uint16_t>(packetStores[packetStoreId].storedTelemetryPackets.size() * 100.0f / + ECSSMaxPacketStoreSize); + report.appendUint16(filledPercentage1); + + uint16_t numOfPacketsToBeTransferred = 0; + numOfPacketsToBeTransferred = std::count_if( + std::begin(packetStores[packetStoreId].storedTelemetryPackets), + std::end(packetStores[packetStoreId].storedTelemetryPackets), [this, &packetStoreId](auto packet) { + return packet.first >= packetStores[packetStoreId].openRetrievalStartTimeTag; + }); + auto filledPercentage2 = static_cast<uint16_t>(numOfPacketsToBeTransferred * 100.0f / ECSSMaxPacketStoreSize); + report.appendUint16(filledPercentage2); +} + +bool StorageAndRetrievalService::failedStartOfByTimeRangeRetrieval( + const String<ECSSPacketStoreIdSize>& packetStoreId, Message& request) { + bool errorFlag = false; + + if (packetStores.find(packetStoreId) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + errorFlag = true; + } else if (packetStores[packetStoreId].openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithOpenRetrievalInProgress); + errorFlag = true; + } else if (packetStores[packetStoreId].byTimeRangeRetrievalStatus) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::ByTimeRangeRetrievalAlreadyEnabled); + errorFlag = true; + } + if (errorFlag) { + uint16_t numberOfBytesToSkip = 8; + request.skipBytes(numberOfBytesToSkip); + return true; + } + return false; +} + +void StorageAndRetrievalService::addPacketStore(const String<ECSSPacketStoreIdSize>& packetStoreId, + const PacketStore& packetStore) { + packetStores.insert({packetStoreId, packetStore}); +} + +void StorageAndRetrievalService::addTelemetryToPacketStore(const String<ECSSPacketStoreIdSize>& packetStoreId, + uint32_t timestamp) { + Message tmPacket; + packetStores[packetStoreId].storedTelemetryPackets.push_back({timestamp, tmPacket}); +} + +void StorageAndRetrievalService::resetPacketStores() { + packetStores.clear(); +} + +uint16_t StorageAndRetrievalService::currentNumberOfPacketStores() { + return packetStores.size(); +} + +PacketStore& StorageAndRetrievalService::getPacketStore(const String<ECSSPacketStoreIdSize>& packetStoreId) { + auto packetStore = packetStores.find(packetStoreId); + if (packetStore == packetStores.end()) { + assert(ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + } + return packetStore->second; +} + +bool StorageAndRetrievalService::packetStoreExists(const String<ECSSPacketStoreIdSize>& packetStoreId) { + return packetStores.find(packetStoreId) != packetStores.end(); +} + +void StorageAndRetrievalService::executeOnPacketStores(Message& request, + const std::function<void(PacketStore&)>& function) { + uint16_t numOfPacketStores = request.readUint16(); + if (numOfPacketStores == 0) { + for (auto& packetStore : packetStores) { + function(packetStore.second); + } + return; + } + + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + auto packetStore = packetStores.find(packetStoreId); + if (packetStore == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + continue; + } + function(packetStores[packetStoreId]); + } +} + +void StorageAndRetrievalService::enableStorageFunction(Message& request) { + request.assertTC(ServiceType, MessageType::EnableStorageInPacketStores); + + executeOnPacketStores(request, [](PacketStore& p) { p.storageStatus = true; }); +} + +void StorageAndRetrievalService::disableStorageFunction(Message& request) { + request.assertTC(ServiceType, MessageType::DisableStorageInPacketStores); + + executeOnPacketStores(request, [](PacketStore& p) { p.storageStatus = false; }); +} + +void StorageAndRetrievalService::startByTimeRangeRetrieval(Message& request) { + request.assertTC(ServiceType, MessageType::StartByTimeRangeRetrieval); + + uint16_t numOfPacketStores = request.readUint16(); + bool errorFlag = false; + + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + if (failedStartOfByTimeRangeRetrieval(packetStoreId, request)) { + continue; + } + uint32_t retrievalStartTime = request.readUint32(); + uint32_t retrievalEndTime = request.readUint32(); + + if (retrievalStartTime >= retrievalEndTime) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::InvalidTimeWindow); + continue; + } + + // todo: 6.15.3.5.2.d(4), actually count the current time + + auto& packetStore = packetStores[packetStoreId]; + packetStore.byTimeRangeRetrievalStatus = true; + packetStore.retrievalStartTime = retrievalStartTime; + packetStore.retrievalEndTime = retrievalEndTime; + // todo: start the by-time-range retrieval process according to the priority policy + } +} + +void StorageAndRetrievalService::deletePacketStoreContent(Message& request) { + request.assertTC(ServiceType, MessageType::DeletePacketStoreContent); + + uint32_t timeLimit = request.readUint32(); // todo: decide the time-format + uint16_t numOfPacketStores = request.readUint16(); + + if (numOfPacketStores == 0) { + for (auto& packetStore : packetStores) { + if (packetStore.second.byTimeRangeRetrievalStatus) { + ErrorHandler::reportError( + request, ErrorHandler::ExecutionStartErrorType::SetPacketStoreWithByTimeRangeRetrieval); + continue; + } + if (packetStore.second.openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError( + request, ErrorHandler::ExecutionStartErrorType::SetPacketStoreWithOpenRetrievalInProgress); + continue; + } + deleteContentUntil(packetStore.first, timeLimit); + } + return; + } + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + if (packetStores.find(packetStoreId) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + continue; + } + if (packetStores[packetStoreId].byTimeRangeRetrievalStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::SetPacketStoreWithByTimeRangeRetrieval); + continue; + } + if (packetStores[packetStoreId].openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::SetPacketStoreWithOpenRetrievalInProgress); + continue; + } + deleteContentUntil(packetStoreId, timeLimit); + } +} + +void StorageAndRetrievalService::packetStoreContentSummaryReport(Message& request) { + request.assertTC(ServiceType, MessageType::ReportContentSummaryOfPacketStores); + + Message report(ServiceType, MessageType::PacketStoreContentSummaryReport, Message::TM, 1); + uint16_t numOfPacketStores = request.readUint16(); + + if (numOfPacketStores == 0) { + report.appendUint16(packetStores.size()); + for (auto& packetStore : packetStores) { + auto packetStoreId = packetStore.first; + report.appendString(packetStoreId); + createContentSummary(report, packetStoreId); + } + storeMessage(report); + return; + } + uint16_t numOfValidPacketStores = 0; + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + if (packetStores.find(packetStoreId) != packetStores.end()) { + numOfValidPacketStores++; + } + } + report.appendUint16(numOfValidPacketStores); + request.resetRead(); + numOfPacketStores = request.readUint16(); + + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + if (packetStores.find(packetStoreId) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + continue; + } + report.appendString(packetStoreId); + createContentSummary(report, packetStoreId); + } + storeMessage(report); +} + +void StorageAndRetrievalService::changeOpenRetrievalStartTimeTag(Message& request) { + request.assertTC(ServiceType, MessageType::ChangeOpenRetrievalStartingTime); + + uint32_t newStartTimeTag = request.readUint32(); + /** + * @todo: check if newStartTimeTag is in the future + */ + uint16_t numOfPacketStores = request.readUint16(); + if (numOfPacketStores == 0) { + for (auto& packetStore : packetStores) { + if (packetStore.second.openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError( + request, ErrorHandler::ExecutionStartErrorType::SetPacketStoreWithOpenRetrievalInProgress); + continue; + } + packetStore.second.openRetrievalStartTimeTag = newStartTimeTag; + } + return; + } + + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + if (packetStores.find(packetStoreId) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + continue; + } + if (packetStores[packetStoreId].openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::SetPacketStoreWithOpenRetrievalInProgress); + continue; + } + packetStores[packetStoreId].openRetrievalStartTimeTag = newStartTimeTag; + } +} + +void StorageAndRetrievalService::resumeOpenRetrievalOfPacketStores(Message& request) { + request.assertTC(ServiceType, MessageType::ResumeOpenRetrievalOfPacketStores); + + uint16_t numOfPacketStores = request.readUint16(); + if (numOfPacketStores == 0) { + for (auto& packetStore : packetStores) { + if (packetStore.second.byTimeRangeRetrievalStatus) { + ErrorHandler::reportError( + request, ErrorHandler::ExecutionStartErrorType::SetPacketStoreWithByTimeRangeRetrieval); + continue; + } + packetStore.second.openRetrievalStatus = PacketStore::InProgress; + } + return; + } + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + if (packetStores.find(packetStoreId) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + continue; + } + auto& packetStore = packetStores[packetStoreId]; + if (packetStore.byTimeRangeRetrievalStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::SetPacketStoreWithByTimeRangeRetrieval); + continue; + } + packetStore.openRetrievalStatus = PacketStore::InProgress; + } +} + +void StorageAndRetrievalService::suspendOpenRetrievalOfPacketStores(Message& request) { + request.assertTC(ServiceType, MessageType::SuspendOpenRetrievalOfPacketStores); + + uint16_t numOfPacketStores = request.readUint16(); + if (numOfPacketStores == 0) { + for (auto& packetStore : packetStores) { + packetStore.second.openRetrievalStatus = PacketStore::Suspended; + } + return; + } + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + if (packetStores.find(packetStoreId) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + continue; + } + packetStores[packetStoreId].openRetrievalStatus = PacketStore::Suspended; + } +} + +void StorageAndRetrievalService::abortByTimeRangeRetrieval(Message& request) { + request.assertTC(ServiceType, MessageType::AbortByTimeRangeRetrieval); + + uint16_t numOfPacketStores = request.readUint16(); + if (numOfPacketStores == 0) { + for (auto& packetStore : packetStores) { + packetStore.second.byTimeRangeRetrievalStatus = false; + } + return; + } + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + if (packetStores.find(packetStoreId) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + continue; + } + packetStores[packetStoreId].byTimeRangeRetrievalStatus = false; + } +} + +void StorageAndRetrievalService::packetStoresStatusReport(Message& request) { + request.assertTC(ServiceType, MessageType::ReportStatusOfPacketStores); + + Message report(ServiceType, MessageType::PacketStoresStatusReport, Message::TM, 1); + report.appendUint16(packetStores.size()); + for (auto& packetStore : packetStores) { + auto packetStoreId = packetStore.first; + report.appendString(packetStoreId); + report.appendBoolean(packetStore.second.storageStatus); + report.appendEnum8(packetStore.second.openRetrievalStatus); + report.appendBoolean(packetStore.second.byTimeRangeRetrievalStatus); + } + storeMessage(report); +} + +void StorageAndRetrievalService::createPacketStores(Message& request) { + request.assertTC(ServiceType, MessageType::CreatePacketStores); + + uint16_t numOfPacketStores = request.readUint16(); + for (uint16_t i = 0; i < numOfPacketStores; i++) { + if (packetStores.size() >= ECSSMaxPacketStores) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::MaxNumberOfPacketStoresReached); + return; + } + auto idToCreate = readPacketStoreId(request); + + if (packetStores.find(idToCreate) != packetStores.end()) { + uint16_t numberOfBytesToSkip = 4; + request.skipBytes(numberOfBytesToSkip); + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::AlreadyExistingPacketStore); + continue; + } + uint16_t packetStoreSize = request.readUint16(); + uint8_t typeCode = request.readUint8(); + PacketStore::PacketStoreType packetStoreType = (typeCode == 0) ? PacketStore::Circular : PacketStore::Bounded; + uint8_t virtualChannel = request.readUint8(); + + if (virtualChannel < VirtualChannelLimits.min or virtualChannel > VirtualChannelLimits.max) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::InvalidVirtualChannel); + continue; + } + PacketStore newPacketStore; + newPacketStore.sizeInBytes = packetStoreSize; + newPacketStore.packetStoreType = packetStoreType; + newPacketStore.storageStatus = false; + newPacketStore.byTimeRangeRetrievalStatus = false; + newPacketStore.openRetrievalStatus = PacketStore::Suspended; + newPacketStore.virtualChannel = virtualChannel; + packetStores.insert({idToCreate, newPacketStore}); + } +} + +void StorageAndRetrievalService::deletePacketStores(Message& request) { + request.assertTC(ServiceType, MessageType::DeletePacketStores); + + uint16_t numOfPacketStores = request.readUint16(); + if (numOfPacketStores == 0) { + int numOfPacketStoresToDelete = 0; + etl::string<ECSSPacketStoreIdSize> packetStoresToDelete[packetStores.size()]; + for (auto& packetStore : packetStores) { + if (packetStore.second.storageStatus) { + ErrorHandler::reportError( + request, ErrorHandler::ExecutionStartErrorType::DeletionOfPacketStoreWithStorageStatusEnabled); + continue; + } + if (packetStore.second.byTimeRangeRetrievalStatus) { + ErrorHandler::reportError( + request, ErrorHandler::ExecutionStartErrorType::DeletionOfPacketWithByTimeRangeRetrieval); + continue; + } + if (packetStore.second.openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError( + request, ErrorHandler::ExecutionStartErrorType::DeletionOfPacketWithOpenRetrievalInProgress); + continue; + } + packetStoresToDelete[numOfPacketStoresToDelete] = packetStore.first; + numOfPacketStoresToDelete++; + } + for (uint16_t l = 0; l < numOfPacketStoresToDelete; l++) { + uint8_t data[ECSSPacketStoreIdSize]; + etl::string<ECSSPacketStoreIdSize> idToDelete = packetStoresToDelete[l]; + std::copy(idToDelete.begin(), idToDelete.end(), data); + String<ECSSPacketStoreIdSize> key(data); + packetStores.erase(key); + } + return; + } + + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto idToDelete = readPacketStoreId(request); + if (packetStores.find(idToDelete) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + continue; + } + auto& packetStore = packetStores[idToDelete]; + + if (packetStore.storageStatus) { + ErrorHandler::reportError( + request, ErrorHandler::ExecutionStartErrorType::DeletionOfPacketStoreWithStorageStatusEnabled); + continue; + } + if (packetStore.byTimeRangeRetrievalStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::DeletionOfPacketWithByTimeRangeRetrieval); + continue; + } + if (packetStore.openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError( + request, ErrorHandler::ExecutionStartErrorType::DeletionOfPacketWithOpenRetrievalInProgress); + continue; + } + packetStores.erase(idToDelete); + } +} + +void StorageAndRetrievalService::packetStoreConfigurationReport(Message& request) { + request.assertTC(ServiceType, MessageType::ReportConfigurationOfPacketStores); + + Message report(ServiceType, MessageType::PacketStoreConfigurationReport, Message::TM, 1); + report.appendUint16(packetStores.size()); + for (auto& packetStore : packetStores) { + auto packetStoreId = packetStore.first; + report.appendString(packetStoreId); + report.appendUint16(packetStore.second.sizeInBytes); + uint8_t typeCode = (packetStore.second.packetStoreType == PacketStore::Circular) ? 0 : 1; + report.appendUint8(typeCode); + report.appendUint8(packetStore.second.virtualChannel); + } + storeMessage(report); +} + +void StorageAndRetrievalService::copyPacketsInTimeWindow(Message& request) { + request.assertTC(ServiceType, MessageType::CopyPacketsInTimeWindow); + + uint8_t typeOfTimeWindow = request.readEnum8(); + switch (typeOfTimeWindow) { + case FromTagToTag: + copyFromTagToTag(request); + break; + case AfterTimeTag: + copyAfterTimeTag(request); + break; + case BeforeTimeTag: + copyBeforeTimeTag(request); + break; + default: + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::InvalidTimeWindow); + break; + } +} + +void StorageAndRetrievalService::resizePacketStores(Message& request) { + request.assertTC(ServiceType, MessageType::ResizePacketStores); + + uint16_t numOfPacketStores = request.readUint16(); + for (uint16_t i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = readPacketStoreId(request); + uint16_t packetStoreSize = request.readUint16(); // In bytes + if (packetStores.find(packetStoreId) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + continue; + } + auto& packetStore = packetStores[packetStoreId]; + + if (packetStoreSize >= ECSSMaxPacketStoreSizeInBytes) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::UnableToHandlePacketStoreSize); + continue; + } + if (packetStore.storageStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithStorageStatusEnabled); + continue; + } + if (packetStore.openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithOpenRetrievalInProgress); + continue; + } + if (packetStore.byTimeRangeRetrievalStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithByTimeRangeRetrieval); + continue; + } + packetStore.sizeInBytes = packetStoreSize; + } +} + +void StorageAndRetrievalService::changeTypeToCircular(Message& request) { + request.assertTC(ServiceType, MessageType::ChangeTypeToCircular); + + auto idToChange = readPacketStoreId(request); + if (packetStores.find(idToChange) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + return; + } + auto& packetStore = packetStores[idToChange]; + + if (packetStore.storageStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithStorageStatusEnabled); + return; + } + if (packetStore.byTimeRangeRetrievalStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithByTimeRangeRetrieval); + return; + } + if (packetStore.openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithOpenRetrievalInProgress); + return; + } + packetStore.packetStoreType = PacketStore::Circular; +} + +void StorageAndRetrievalService::changeTypeToBounded(Message& request) { + request.assertTC(ServiceType, MessageType::ChangeTypeToBounded); + + auto idToChange = readPacketStoreId(request); + if (packetStores.find(idToChange) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + return; + } + auto& packetStore = packetStores[idToChange]; + + if (packetStore.storageStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithStorageStatusEnabled); + return; + } + if (packetStore.byTimeRangeRetrievalStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithByTimeRangeRetrieval); + return; + } + if (packetStore.openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithOpenRetrievalInProgress); + return; + } + packetStore.packetStoreType = PacketStore::Bounded; +} + +void StorageAndRetrievalService::changeVirtualChannel(Message& request) { + request.assertTC(ServiceType, MessageType::ChangeVirtualChannel); + + auto idToChange = readPacketStoreId(request); + uint8_t virtualChannel = request.readUint8(); + if (packetStores.find(idToChange) == packetStores.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore); + return; + } + auto& packetStore = packetStores[idToChange]; + + if (virtualChannel < VirtualChannelLimits.min or virtualChannel > VirtualChannelLimits.max) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::InvalidVirtualChannel); + return; + } + if (packetStore.byTimeRangeRetrievalStatus) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithByTimeRangeRetrieval); + return; + } + if (packetStore.openRetrievalStatus == PacketStore::InProgress) { + ErrorHandler::reportError(request, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithOpenRetrievalInProgress); + return; + } + packetStore.virtualChannel = virtualChannel; +} + +void StorageAndRetrievalService::execute(Message& request) { + switch (request.messageType) { + case EnableStorageInPacketStores: + enableStorageFunction(request); + break; + case DisableStorageInPacketStores: + disableStorageFunction(request); + break; + case StartByTimeRangeRetrieval: + startByTimeRangeRetrieval(request); + break; + case DeletePacketStoreContent: + deletePacketStoreContent(request); + break; + case ReportContentSummaryOfPacketStores: + packetStoreContentSummaryReport(request); + break; + case ChangeOpenRetrievalStartingTime: + changeOpenRetrievalStartTimeTag(request); + break; + case ResumeOpenRetrievalOfPacketStores: + resumeOpenRetrievalOfPacketStores(request); + break; + case SuspendOpenRetrievalOfPacketStores: + suspendOpenRetrievalOfPacketStores(request); + break; + case AbortByTimeRangeRetrieval: + abortByTimeRangeRetrieval(request); + break; + case ReportStatusOfPacketStores: + packetStoresStatusReport(request); + break; + case CreatePacketStores: + createPacketStores(request); + break; + case DeletePacketStores: + deletePacketStores(request); + break; + case ReportConfigurationOfPacketStores: + packetStoreConfigurationReport(request); + break; + case CopyPacketsInTimeWindow: + copyPacketsInTimeWindow(request); + break; + case ResizePacketStores: + resizePacketStores(request); + break; + case ChangeTypeToCircular: + changeTypeToCircular(request); + break; + case ChangeTypeToBounded: + changeTypeToBounded(request); + break; + case ChangeVirtualChannel: + changeVirtualChannel(request); + break; + default: + ErrorHandler::reportInternalError(ErrorHandler::OtherMessageType); + break; + } +} diff --git a/test/Helpers/PacketStore.cpp b/test/Helpers/PacketStore.cpp new file mode 100644 index 0000000000000000000000000000000000000000..072303a5b3d8a4c5e92316eb3a446b9ff6e5eb21 --- /dev/null +++ b/test/Helpers/PacketStore.cpp @@ -0,0 +1,37 @@ +#include "Helpers/PacketStore.hpp" +#include "catch2/catch.hpp" + +TEST_CASE("Counting a packet store's size in bytes") { + SECTION("Correct counting of size in bytes") { + Message tm1; + tm1.appendUint8(4); + tm1.appendFloat(5.6); + + PacketStore packetStore; + packetStore.storedTelemetryPackets.push_back({2, tm1}); + + REQUIRE(packetStore.storedTelemetryPackets.size() == 1); + REQUIRE(packetStore.calculateSizeInBytes() == 5); + + Message tm2; + tm2.appendBoolean(true); + tm2.appendUint16(45); + tm2.appendUint8(3); + tm2.appendUint32(55); + + packetStore.storedTelemetryPackets.push_back({2, tm2}); + + REQUIRE(packetStore.storedTelemetryPackets.size() == 2); + REQUIRE(packetStore.calculateSizeInBytes() == 13); + + Message tm3; + tm3.appendUint64(743); + tm3.appendUint8(3); + tm3.appendUint32(55); + + packetStore.storedTelemetryPackets.push_back({3, tm3}); + + REQUIRE(packetStore.storedTelemetryPackets.size() == 3); + REQUIRE(packetStore.calculateSizeInBytes() == 26); + } +} \ No newline at end of file diff --git a/test/Services/StorageAndRetrievalService.cpp b/test/Services/StorageAndRetrievalService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd7020db5c5f9deb294b670be75474fd0a45099b --- /dev/null +++ b/test/Services/StorageAndRetrievalService.cpp @@ -0,0 +1,2755 @@ +#include <iostream> +#include "catch2/catch.hpp" +#include "Message.hpp" +#include "ServiceTests.hpp" +#include "Services/StorageAndRetrievalService.hpp" + +StorageAndRetrievalService& storageAndRetrieval = Services.storageAndRetrieval; + +uint32_t timestamps1[6] = {2, 4, 5, 7, 9, 11}; +uint32_t timestamps2[5] = {0, 1, 4, 15, 22}; +uint32_t timestamps3[4] = {4, 7, 9, 14}; +uint32_t timestamps4[8] = {4, 6, 34, 40, 44, 51, 52, 58}; + +void initializePacketStores() { + uint16_t numOfPacketStores = 4; + uint8_t concatenatedPacketStoreNames[] = "ps2ps25ps799ps5555"; + uint16_t offsets[5] = {0, 3, 7, 12, 18}; + uint16_t sizes[4] = {100, 200, 550, 340}; + uint8_t virtualChannels[4] = {4, 6, 1, 2}; + + for (int i = 0; i < numOfPacketStores; i++) { + uint8_t packetStoreData[ECSSPacketStoreIdSize]; + std::fill(std::begin(packetStoreData), std::end(packetStoreData), 0); + std::copy(concatenatedPacketStoreNames + offsets[i], concatenatedPacketStoreNames + offsets[i + 1], + packetStoreData); + + String<ECSSPacketStoreIdSize> packetStoreId(packetStoreData); + PacketStore newPacketStore; + newPacketStore.sizeInBytes = sizes[i]; + newPacketStore.packetStoreType = ((i % 2) == 0) ? PacketStore::Circular : PacketStore::Bounded; + newPacketStore.virtualChannel = virtualChannels[i]; + storageAndRetrieval.addPacketStore(packetStoreId, newPacketStore); + } +} + +void validPacketStoreCreationRequest(Message& request) { + uint16_t numOfPacketStores = 4; + request.appendUint16(numOfPacketStores); + uint8_t concatenatedPacketStoreNames[] = "ps2ps25ps799ps5555"; + uint16_t offsets[5] = {0, 3, 7, 12, 18}; + uint16_t sizes[4] = {100, 200, 550, 340}; + uint8_t virtualChannels[4] = {4, 6, 1, 2}; + uint8_t packetStoreTypeCode[2] = {0, 1}; + + for (int i = 0; i < numOfPacketStores; i++) { + uint8_t packetStoreData[ECSSPacketStoreIdSize]; + std::fill(std::begin(packetStoreData), std::end(packetStoreData), 0); + std::copy(concatenatedPacketStoreNames + offsets[i], concatenatedPacketStoreNames + offsets[i + 1], + packetStoreData); + + String<ECSSPacketStoreIdSize> packetStoreId(packetStoreData); + request.appendString(packetStoreId); + request.appendUint16(sizes[i]); + if ((i % 2) == 0) { + request.appendUint8(packetStoreTypeCode[0]); + } else { + request.appendUint8(packetStoreTypeCode[1]); + } + request.appendUint8(virtualChannels[i]); + } +} + +void invalidPacketStoreCreationRequest(Message& request) { + uint16_t numOfPacketStores = 5; + request.appendUint16(numOfPacketStores); + uint8_t concatenatedPacketStoreNames[] = "ps2ps1ps2ps44ps0000"; + uint16_t offsets[6] = {0, 3, 6, 9, 13, 19}; + uint16_t sizes[5] = {33, 55, 66, 77, 99}; + uint8_t invalidChannel1 = VirtualChannelLimits.min - 1; + uint8_t invalidChannel2 = VirtualChannelLimits.max + 1; + uint8_t virtualChannels[5] = {5, invalidChannel1, 1, invalidChannel2, 2}; + uint8_t packetStoreTypeCode[2] = {0, 1}; + + for (int i = 0; i < numOfPacketStores; i++) { + uint8_t packetStoreData[ECSSPacketStoreIdSize]; + std::fill(std::begin(packetStoreData), std::end(packetStoreData), 0); + std::copy(concatenatedPacketStoreNames + offsets[i], concatenatedPacketStoreNames + offsets[i + 1], + packetStoreData); + + String<ECSSPacketStoreIdSize> packetStoreId(packetStoreData); + request.appendString(packetStoreId); + request.appendUint16(sizes[i]); + if ((i % 2) == 0) { + request.appendUint8(packetStoreTypeCode[0]); + } else { + request.appendUint8(packetStoreTypeCode[1]); + } + request.appendUint8(virtualChannels[i]); + } +} + +etl::array<String<ECSSPacketStoreIdSize>, 4> validPacketStoreIds() { + uint8_t packetStoreData[ECSSPacketStoreIdSize] = "ps2"; + uint8_t packetStoreData2[ECSSPacketStoreIdSize] = "ps25"; + uint8_t packetStoreData3[ECSSPacketStoreIdSize] = "ps799"; + uint8_t packetStoreData4[ECSSPacketStoreIdSize] = "ps5555"; + + String<ECSSPacketStoreIdSize> id(packetStoreData); + String<ECSSPacketStoreIdSize> id2(packetStoreData2); + String<ECSSPacketStoreIdSize> id3(packetStoreData3); + String<ECSSPacketStoreIdSize> id4(packetStoreData4); + + etl::array<String<ECSSPacketStoreIdSize>, 4> validPacketStores = {id, id2, id3, id4}; + return validPacketStores; +} + +etl::array<String<ECSSPacketStoreIdSize>, 4> invalidPacketStoreIds() { + uint8_t packetStoreData[ECSSPacketStoreIdSize] = "ps1"; + uint8_t packetStoreData2[ECSSPacketStoreIdSize] = "ps36"; + uint8_t packetStoreData3[ECSSPacketStoreIdSize] = "ps999"; + uint8_t packetStoreData4[ECSSPacketStoreIdSize] = "ps1234"; + + String<ECSSPacketStoreIdSize> id(packetStoreData); + String<ECSSPacketStoreIdSize> id2(packetStoreData2); + String<ECSSPacketStoreIdSize> id3(packetStoreData3); + String<ECSSPacketStoreIdSize> id4(packetStoreData4); + + etl::array<String<ECSSPacketStoreIdSize>, 4> validPacketStores = {id, id2, id3, id4}; + return validPacketStores; +} + +void padWithZeros(etl::array<String<ECSSPacketStoreIdSize>, 4>& packetStoreIds) { + uint8_t offsets[] = {3, 4, 5, 6}; + int index = 0; + // Padding every empty position with zeros, to avoid memory garbage collection, which leads to a faulty result. + for (auto& packetStoreId : packetStoreIds) { + uint8_t startingPosition = offsets[index++]; + for (uint8_t i = startingPosition; i < ECSSPacketStoreIdSize; i++) { + packetStoreId[i] = 0; + } + } +} + +void addTelemetryPacketsInPacketStores() { + auto packetStoreIds = validPacketStoreIds(); + + for (auto& timestamp : timestamps1) { + storageAndRetrieval.addTelemetryToPacketStore(packetStoreIds[0], timestamp); + } + for (auto& timestamp : timestamps2) { + storageAndRetrieval.addTelemetryToPacketStore(packetStoreIds[1], timestamp); + } + for (auto& timestamp : timestamps3) { + storageAndRetrieval.addTelemetryToPacketStore(packetStoreIds[2], timestamp); + } + for (auto& timestamp : timestamps4) { + storageAndRetrieval.addTelemetryToPacketStore(packetStoreIds[3], timestamp); + } +} + +void resetPacketStores() { + storageAndRetrieval.resetPacketStores(); +} + +TEST_CASE("Creating packet stores") { + SECTION("Valid packet store creation request") { + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CreatePacketStores, Message::TC, 1); + validPacketStoreCreationRequest(request); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 0); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[0]).sizeInBytes == 100); + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[1]).sizeInBytes == 200); + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[2]).sizeInBytes == 550); + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[3]).sizeInBytes == 340); + + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[0]).virtualChannel == 4); + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[1]).virtualChannel == 6); + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[2]).virtualChannel == 1); + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[3]).virtualChannel == 2); + + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[0]).packetStoreType == + PacketStore::PacketStoreType::Circular); + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[1]).packetStoreType == + PacketStore::PacketStoreType::Bounded); + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[2]).packetStoreType == + PacketStore::PacketStoreType::Circular); + CHECK(storageAndRetrieval.getPacketStore(packetStoreIds[3]).packetStoreType == + PacketStore::PacketStoreType::Bounded); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Invalid packet store creation request") { + uint8_t packetStoreData[ECSSPacketStoreIdSize] = "ps2"; + String<ECSSPacketStoreIdSize> existingPacketStoreId(packetStoreData); + PacketStore existingPacketStore; + storageAndRetrieval.addPacketStore(existingPacketStoreId, existingPacketStore); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 1); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CreatePacketStores, Message::TC, 1); + invalidPacketStoreCreationRequest(request); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 4); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::InvalidVirtualChannel) == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::AlreadyExistingPacketStore) == 2); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 2); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Exceeding the maximum number of packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CreatePacketStores, Message::TC, 1); + invalidPacketStoreCreationRequest(request); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::MaxNumberOfPacketStoresReached) == 1); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Deleting packet stores") { + SECTION("Valid deletion of specified packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStores, Message::TC, 1); + uint16_t numOfPacketStores = 4; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.storageStatus = false; + packetStore.byTimeRangeRetrievalStatus = false; + packetStore.openRetrievalStatus = PacketStore::Suspended; + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 0); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Valid deletion of all packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStores, Message::TC, 1); + uint16_t numOfPacketStores = 0; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.storageStatus = false; + packetStore.byTimeRangeRetrievalStatus = false; + packetStore.openRetrievalStatus = PacketStore::Suspended; + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 0); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Invalid deletion of specified packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStores, Message::TC, 1); + uint16_t numOfPacketStores = 4; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.storageStatus = false; + packetStore.byTimeRangeRetrievalStatus = false; + packetStore.openRetrievalStatus = PacketStore::Suspended; + request.appendString(packetStoreId); + } + + storageAndRetrieval.getPacketStore(packetStoreIds[0]).storageStatus = true; + storageAndRetrieval.getPacketStore(packetStoreIds[1]).byTimeRangeRetrievalStatus = true; + storageAndRetrieval.getPacketStore(packetStoreIds[2]).openRetrievalStatus = PacketStore::InProgress; + storageAndRetrieval.getPacketStore(packetStoreIds[3]).storageStatus = true; + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 4); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::DeletionOfPacketStoreWithStorageStatusEnabled) == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::DeletionOfPacketWithByTimeRangeRetrieval) == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::DeletionOfPacketWithOpenRetrievalInProgress) == 1); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Invalid deletion request of non existing packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = invalidPacketStoreIds(); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStores, Message::TC, 1); + uint16_t numOfPacketStores = 4; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + REQUIRE(not storageAndRetrieval.packetStoreExists(packetStoreId)); + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 4); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 4); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Invalid deletion of all packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStores, Message::TC, 1); + uint16_t numOfPacketStores = 0; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.storageStatus = false; + packetStore.byTimeRangeRetrievalStatus = false; + packetStore.openRetrievalStatus = PacketStore::Suspended; + } + + storageAndRetrieval.getPacketStore(packetStoreIds[0]).storageStatus = true; + storageAndRetrieval.getPacketStore(packetStoreIds[1]).byTimeRangeRetrievalStatus = true; + storageAndRetrieval.getPacketStore(packetStoreIds[2]).openRetrievalStatus = PacketStore::InProgress; + storageAndRetrieval.getPacketStore(packetStoreIds[3]).openRetrievalStatus = PacketStore::InProgress; + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 4); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::DeletionOfPacketStoreWithStorageStatusEnabled) == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::DeletionOfPacketWithByTimeRangeRetrieval) == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::DeletionOfPacketWithOpenRetrievalInProgress) == 2); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Both valid and invalid deletion requests") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStores, Message::TC, 1); + uint16_t numOfPacketStores = 8; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : correctPacketStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.storageStatus = false; + packetStore.byTimeRangeRetrievalStatus = false; + packetStore.openRetrievalStatus = PacketStore::Suspended; + request.appendString(packetStoreId); + } + + for (auto& packetStoreId : wrongPacketStoreIds) { + REQUIRE(not storageAndRetrieval.packetStoreExists(packetStoreId)); + request.appendString(packetStoreId); + } + + storageAndRetrieval.getPacketStore(correctPacketStoreIds[0]).storageStatus = true; + storageAndRetrieval.getPacketStore(correctPacketStoreIds[1]).byTimeRangeRetrievalStatus = true; + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 6); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 2); + REQUIRE(storageAndRetrieval.packetStoreExists(correctPacketStoreIds[0])); + REQUIRE(storageAndRetrieval.packetStoreExists(correctPacketStoreIds[1])); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::DeletionOfPacketStoreWithStorageStatusEnabled) == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::DeletionOfPacketWithByTimeRangeRetrieval) == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 4); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Enabling the storage of packet stores") { + SECTION("Valid enabling of storage") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::EnableStorageInPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 2; + request.appendUint16(numOfPacketStores); + for (int i = 0; i < numOfPacketStores; i++) { + REQUIRE(storageAndRetrieval.packetStoreExists(packetStoreIds[i])); + storageAndRetrieval.getPacketStore(packetStoreIds[i]).storageStatus = false; + request.appendString(packetStoreIds[i]); + } + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storageStatus = false; + storageAndRetrieval.getPacketStore(packetStoreIds[3]).storageStatus = false; + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).storageStatus == true); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).storageStatus == true); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storageStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).storageStatus == false); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Invalid enabling of storage") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = invalidPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::EnableStorageInPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + for (int i = 0; i < numOfPacketStores; i++) { + REQUIRE(not storageAndRetrieval.packetStoreExists(packetStoreIds[i])); + request.appendString(packetStoreIds[i]); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 3); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Enabling the storage of all packet stores") { + initializePacketStores(); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::EnableStorageInPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 0; + request.appendUint16(numOfPacketStores); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + for (auto& packetStoreId : packetStoreIds) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreId).storageStatus == true); + } + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Disabling the storage of packet stores") { + SECTION("Valid disabling of storage") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DisableStorageInPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 2; + request.appendUint16(numOfPacketStores); + for (int i = 0; i < numOfPacketStores; i++) { + storageAndRetrieval.getPacketStore(packetStoreIds[i]).storageStatus = true; + request.appendString(packetStoreIds[i]); + } + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storageStatus = true; + storageAndRetrieval.getPacketStore(packetStoreIds[3]).storageStatus = true; + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).storageStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).storageStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storageStatus == true); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).storageStatus == true); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Invalid disabling of storage") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = invalidPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DisableStorageInPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + for (int i = 0; i < numOfPacketStores; i++) { + REQUIRE(not storageAndRetrieval.packetStoreExists(packetStoreIds[i])); + request.appendString(packetStoreIds[i]); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 3); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Enabling the storage of all packet stores") { + initializePacketStores(); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DisableStorageInPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 0; + request.appendUint16(numOfPacketStores); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + for (auto& packetStoreId : packetStoreIds) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreId).storageStatus == false); + } + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Changing the open retrieval start-time-tag") { + SECTION("Successful change of the start-time-tag") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeOpenRetrievalStartingTime, Message::TC, 1); + + uint32_t startTimeTag = 200; + uint16_t numOfPacketStores = 2; + request.appendUint32(startTimeTag); + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStartTimeTag == 0); + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).openRetrievalStartTimeTag == 200); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).openRetrievalStartTimeTag == 200); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).openRetrievalStartTimeTag == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).openRetrievalStartTimeTag == 0); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed change of the start-time-tag") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeOpenRetrievalStartingTime, Message::TC, 1); + + uint32_t startTimeTag = 200; + uint16_t numOfPacketStores = 6; + request.appendUint32(startTimeTag); + request.appendUint16(numOfPacketStores); + + for (int i = 0; i < numOfPacketStores / 2; i++) { + auto packetStoreId = correctPacketStoreIds[i]; + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStartTimeTag == 0); + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::InProgress; + request.appendString(packetStoreId); + } + + for (int i = 0; i < numOfPacketStores / 2; i++) { + auto packetStoreId = wrongPacketStoreIds[i]; + REQUIRE(not storageAndRetrieval.packetStoreExists(packetStoreId)); + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 6); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::SetPacketStoreWithOpenRetrievalInProgress) == 3); + + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[0]).openRetrievalStartTimeTag == 0); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[1]).openRetrievalStartTimeTag == 0); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[2]).openRetrievalStartTimeTag == 0); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).openRetrievalStartTimeTag == 0); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Both successful and failed attempts to change the start-time-tag of all packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeOpenRetrievalStartingTime, Message::TC, 1); + + uint32_t startTimeTag = 200; + uint16_t numOfPacketStores = 0; + request.appendUint32(startTimeTag); + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStartTimeTag == 0); + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + } + storageAndRetrieval.getPacketStore(packetStoreIds[2]).openRetrievalStatus = PacketStore::InProgress; + storageAndRetrieval.getPacketStore(packetStoreIds[3]).openRetrievalStatus = PacketStore::InProgress; + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::SetPacketStoreWithOpenRetrievalInProgress) == 2); + + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).openRetrievalStartTimeTag == 200); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).openRetrievalStartTimeTag == 200); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).openRetrievalStartTimeTag == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).openRetrievalStartTimeTag == 0); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Resuming the open retrieval process") { + SECTION("Successful resuming of the open retrieval") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ResumeOpenRetrievalOfPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = false; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).openRetrievalStatus == PacketStore::InProgress); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).openRetrievalStatus == PacketStore::InProgress); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).openRetrievalStatus == PacketStore::InProgress); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).openRetrievalStatus == PacketStore::Suspended); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed resuming of the open retrieval") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ResumeOpenRetrievalOfPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 6; + request.appendUint16(numOfPacketStores); + + for (int i = 0; i < numOfPacketStores / 2; i++) { + auto packetStoreId = correctPacketStoreIds[i]; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = true; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + request.appendString(packetStoreId); + } + storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).openRetrievalStatus = PacketStore::Suspended; + + for (int i = 0; i < numOfPacketStores / 2; i++) { + auto packetStoreId = wrongPacketStoreIds[i]; + REQUIRE(not storageAndRetrieval.packetStoreExists(packetStoreId)); + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 6); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::SetPacketStoreWithByTimeRangeRetrieval) == 3); + + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[0]).openRetrievalStatus == + PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[1]).openRetrievalStatus == + PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[2]).openRetrievalStatus == + PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).openRetrievalStatus == + PacketStore::Suspended); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Both successful and failed attempts to resume the open retrieval of all packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ResumeOpenRetrievalOfPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 0; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = false; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + } + storageAndRetrieval.getPacketStore(packetStoreIds[2]).byTimeRangeRetrievalStatus = true; + storageAndRetrieval.getPacketStore(packetStoreIds[3]).byTimeRangeRetrievalStatus = true; + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::SetPacketStoreWithByTimeRangeRetrieval) == 2); + + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).openRetrievalStatus == PacketStore::InProgress); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).openRetrievalStatus == PacketStore::InProgress); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).openRetrievalStatus == PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).openRetrievalStatus == PacketStore::Suspended); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Suspending the open retrieval process") { + SECTION("Successful suspension of the open retrieval") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::SuspendOpenRetrievalOfPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::InProgress; + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).openRetrievalStatus == PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).openRetrievalStatus == PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).openRetrievalStatus == PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).openRetrievalStatus == PacketStore::InProgress); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed suspension of the open retrieval") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::SuspendOpenRetrievalOfPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 6; + request.appendUint16(numOfPacketStores); + + for (int i = 0; i < numOfPacketStores / 2; i++) { + auto packetStoreId = correctPacketStoreIds[i]; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::InProgress; + request.appendString(packetStoreId); + } + storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).openRetrievalStatus = PacketStore::InProgress; + + for (int i = 0; i < numOfPacketStores / 2; i++) { + auto packetStoreId = wrongPacketStoreIds[i]; + REQUIRE(not storageAndRetrieval.packetStoreExists(packetStoreId)); + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 3); + + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[0]).openRetrievalStatus == + PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[1]).openRetrievalStatus == + PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[2]).openRetrievalStatus == + PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).openRetrievalStatus == + PacketStore::InProgress); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Successful attempt to suspend the open retrieval of all packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::SuspendOpenRetrievalOfPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 0; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + REQUIRE(storageAndRetrieval.packetStoreExists(packetStoreId)); + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::InProgress; + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).openRetrievalStatus == PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).openRetrievalStatus == PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).openRetrievalStatus == PacketStore::Suspended); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).openRetrievalStatus == PacketStore::Suspended); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Starting the by-time-range retrieval of packet stores") { + SECTION("Successful starting of the by-time-range retrieval") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::StartByTimeRangeRetrieval, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + + uint32_t timeTags1[4] = {20, 30, 40, 50}; + uint32_t timeTags2[4] = {60, 70, 80, 90}; + + int index = 0; + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = false; + request.appendString(packetStoreId); + uint32_t timeTag1 = timeTags1[index]; + uint32_t timeTag2 = timeTags2[index++]; + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + for (int i = 0; i < numOfPacketStores; i++) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreIds[i]); + REQUIRE(packetStore.byTimeRangeRetrievalStatus == true); + REQUIRE(packetStore.retrievalStartTime == timeTags1[i]); + REQUIRE(packetStore.retrievalEndTime == timeTags2[i]); + } + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreIds[3]); + REQUIRE(packetStore.byTimeRangeRetrievalStatus == false); + REQUIRE(packetStore.retrievalStartTime == 0); + REQUIRE(packetStore.retrievalEndTime == 0); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed starting of the by-time-range retrieval") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::StartByTimeRangeRetrieval, Message::TC, 1); + + uint16_t numOfPacketStores = 6; + request.appendUint16(numOfPacketStores); + + for (int i = 0; i < numOfPacketStores / 2; i++) { + auto packetStoreId = correctPacketStoreIds[i]; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = + (i % 2 == 0) ? PacketStore::Suspended : PacketStore::InProgress; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = i % 2 == 0; + + request.appendString(packetStoreId); + uint32_t timeTag1 = 20; + uint32_t timeTag2 = 40; + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + } + storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).byTimeRangeRetrievalStatus = false; + + for (int i = 0; i < numOfPacketStores / 2; i++) { + auto packetStoreId = wrongPacketStoreIds[i]; + REQUIRE(not storageAndRetrieval.packetStoreExists(packetStoreId)); + request.appendString(packetStoreId); + uint32_t timeTag1 = 20; + uint32_t timeTag2 = 40; + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 6); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ByTimeRangeRetrievalAlreadyEnabled) == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::GetPacketStoreWithOpenRetrievalInProgress) == 1); + + for (int i = 0; i < numOfPacketStores / 2; i++) { + auto& packetStore = storageAndRetrieval.getPacketStore(correctPacketStoreIds[i]); + REQUIRE(packetStore.byTimeRangeRetrievalStatus == (i % 2 == 0)); + REQUIRE(packetStore.retrievalStartTime == 0); + REQUIRE(packetStore.retrievalEndTime == 0); + } + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).byTimeRangeRetrievalStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).retrievalStartTime == 0); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Invalid window requested") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::StartByTimeRangeRetrieval, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = false; + request.appendString(packetStoreId); + uint32_t timeTag1 = 90; + uint32_t timeTag2 = 20; + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::InvalidTimeWindow) == 3); + + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).byTimeRangeRetrievalStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).byTimeRangeRetrievalStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).byTimeRangeRetrievalStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).byTimeRangeRetrievalStatus == false); + + for (auto& packetStoreId : packetStoreIds) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreId).retrievalStartTime == 0); + } + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Aborting the by-time-range retrieval of packet stores") { + SECTION("Successful aborting of the by-time-range retrieval") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::AbortByTimeRangeRetrieval, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = true; + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + for (int i = 0; i < numOfPacketStores; i++) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[i]).byTimeRangeRetrievalStatus == false); + } + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).byTimeRangeRetrievalStatus == true); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed aborting of the by-time-range retrieval") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + auto correctPacketStoreIds = validPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::AbortByTimeRangeRetrieval, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : correctPacketStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = true; + } + + for (int i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = wrongPacketStoreIds[i]; + REQUIRE(not storageAndRetrieval.packetStoreExists(packetStoreId)); + request.appendString(packetStoreId); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 3); + for (auto& packetStoreId : correctPacketStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = true; + } + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Successful abort of the by-time-range retrieval of all packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::AbortByTimeRangeRetrieval, Message::TC, 1); + + uint16_t numOfPacketStores = 0; + request.appendUint16(numOfPacketStores); + + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = true; + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).byTimeRangeRetrievalStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).byTimeRangeRetrievalStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).byTimeRangeRetrievalStatus == false); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).byTimeRangeRetrievalStatus == false); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Reporting the status of packet stores") { + SECTION("Valid reporting of the packet store status") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + uint8_t packetStoreData[ECSSPacketStoreIdSize] = "ps2"; + uint8_t packetStoreData2[ECSSPacketStoreIdSize] = "ps25"; + uint8_t packetStoreData3[ECSSPacketStoreIdSize] = "ps799"; + uint8_t packetStoreData4[ECSSPacketStoreIdSize] = "ps5555"; + + int count = 0; + for (auto& packetStoreId : packetStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.storageStatus = (count % 2 == 0); + packetStore.byTimeRangeRetrievalStatus = (count % 2 != 0); + packetStore.openRetrievalStatus = (count % 2 == 0) ? PacketStore::InProgress : PacketStore::Suspended; + count++; + } + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ReportStatusOfPacketStores, Message::TC, 1); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + Message report = ServiceTests::get(0); + + REQUIRE(report.messageType == StorageAndRetrievalService::MessageType::PacketStoresStatusReport); + REQUIRE(report.readUint16() == 4); + + // Packet store 1 + uint8_t data[ECSSPacketStoreIdSize]; + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(data), std::end(data), std::begin(packetStoreData))); + CHECK(report.readBoolean() == true); + CHECK(report.readEnum8() == 1); + CHECK(report.readBoolean() == false); + // Packet store 2 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(data), std::end(data), std::begin(packetStoreData2))); + CHECK(report.readBoolean() == false); + CHECK(report.readEnum8() == 0); + CHECK(report.readBoolean() == true); + // Packet store 3 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(data), std::end(data), std::begin(packetStoreData4))); + CHECK(report.readBoolean() == false); + CHECK(report.readEnum8() == 0); + CHECK(report.readBoolean() == true); + // Packet store 4 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(data), std::end(data), std::begin(packetStoreData3))); + CHECK(report.readBoolean() == true); + CHECK(report.readEnum8() == 1); + CHECK(report.readBoolean() == false); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Reporting the configuration of packet stores") { + SECTION("Valid reporting of the configuration") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + uint8_t packetStoreData[ECSSPacketStoreIdSize] = "ps2"; + uint8_t packetStoreData2[ECSSPacketStoreIdSize] = "ps25"; + uint8_t packetStoreData3[ECSSPacketStoreIdSize] = "ps799"; + uint8_t packetStoreData4[ECSSPacketStoreIdSize] = "ps5555"; + + int count = 0; + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).packetStoreType = + (count % 2 == 0) ? PacketStore::Circular : PacketStore::Bounded; + count++; + } + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ReportConfigurationOfPacketStores, Message::TC, 1); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + Message report = ServiceTests::get(0); + + REQUIRE(report.messageType == StorageAndRetrievalService::MessageType::PacketStoreConfigurationReport); + REQUIRE(report.readUint16() == 4); + + // Packet store 1 + uint8_t data[ECSSPacketStoreIdSize]; + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(data), std::end(data), std::begin(packetStoreData))); + CHECK(report.readUint16() == 100); + CHECK(report.readUint8() == 0); + CHECK(report.readUint8() == 4); + // Packet store 2 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(data), std::end(data), std::begin(packetStoreData2))); + CHECK(report.readUint16() == 200); + CHECK(report.readUint8() == 1); + CHECK(report.readUint8() == 6); + // Packet store 3 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(data), std::end(data), std::begin(packetStoreData4))); + CHECK(report.readUint16() == 340); + CHECK(report.readUint8() == 1); + CHECK(report.readUint8() == 2); + // Packet store 4 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(data), std::end(data), std::begin(packetStoreData3))); + CHECK(report.readUint16() == 550); + CHECK(report.readUint8() == 0); + CHECK(report.readUint8() == 1); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Resizing the packet stores") { + SECTION("Successful resizing of packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + uint16_t newSizes[4] = {11, 22, 33, 44}; + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ResizePacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + int index = 0; + for (auto& packetStoreId : packetStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.storageStatus = false; + packetStore.openRetrievalStatus = PacketStore::Suspended; + packetStore.byTimeRangeRetrievalStatus = false; + + request.appendString(packetStoreId); + request.appendUint16(newSizes[index]); + index++; + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + for (int i = 0; i < numOfPacketStores; i++) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[i]).sizeInBytes == newSizes[i]); + } + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).sizeInBytes == 340); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed resizing of packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + uint16_t oldSizes[4] = {100, 200, 550, 340}; + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ResizePacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 4; + request.appendUint16(numOfPacketStores); + int index = 0; + for (auto& packetStoreId : packetStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.storageStatus = (index % 2 == 0); + packetStore.byTimeRangeRetrievalStatus = (index == 1); + packetStore.openRetrievalStatus = (index == 3) ? PacketStore::InProgress : PacketStore::Suspended; + + request.appendString(packetStoreId); + request.appendUint16(35); + index++; + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 4); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::GetPacketStoreWithStorageStatusEnabled) == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::GetPacketStoreWithOpenRetrievalInProgress) == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::GetPacketStoreWithByTimeRangeRetrieval) == 1); + int i = 0; + + for (auto& packetStoreId : packetStoreIds) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreId).sizeInBytes == oldSizes[i++]); + } + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Memory unable to handle the requested size") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + uint16_t newSizes[4] = {1000, 2000, 3400, 5500}; + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ResizePacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 4; + request.appendUint16(numOfPacketStores); + int index = 0; + for (auto& packetStoreId : packetStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.storageStatus = false; + packetStore.byTimeRangeRetrievalStatus = false; + packetStore.openRetrievalStatus = PacketStore::Suspended; + + request.appendString(packetStoreId); + request.appendUint16(newSizes[index++]); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 4); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::UnableToHandlePacketStoreSize) == 4); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Request to resize non existing packet stores") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + auto correctPacketStoreIds = validPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + uint16_t oldSizes[4] = {100, 200, 550, 340}; + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ResizePacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 4; + request.appendUint16(numOfPacketStores); + for (auto& packetStoreId : wrongPacketStoreIds) { + request.appendString(packetStoreId); + request.appendUint16(35); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 4); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 4); + int i = 0; + for (auto& packetStoreId : correctPacketStoreIds) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreId).sizeInBytes == oldSizes[i++]); + } + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Changing the packet store type to circular") { + SECTION("Successful changing of type to circular") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + for (auto& packetStoreId : packetStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.packetStoreType = PacketStore::Bounded; + packetStore.storageStatus = false; + packetStore.byTimeRangeRetrievalStatus = false; + packetStore.openRetrievalStatus = PacketStore::Suspended; + } + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeTypeToCircular, Message::TC, 1); + + request.appendString(packetStoreIds[0]); + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).packetStoreType == PacketStore::Circular); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).packetStoreType == PacketStore::Bounded); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).packetStoreType == PacketStore::Bounded); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).packetStoreType == PacketStore::Bounded); + + Message request2(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeTypeToCircular, Message::TC, 1); + + request2.appendString(packetStoreIds[3]); + MessageParser::execute(request2); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).packetStoreType == PacketStore::Circular); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).packetStoreType == PacketStore::Bounded); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).packetStoreType == PacketStore::Bounded); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).packetStoreType == PacketStore::Circular); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed changing of type to circular") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + int count = 0; + for (auto& packetStoreId : correctPacketStoreIds) { + auto& packetStore = storageAndRetrieval.getPacketStore(packetStoreId); + packetStore.packetStoreType = PacketStore::Bounded; + packetStore.storageStatus = (count == 0); + packetStore.byTimeRangeRetrievalStatus = (count == 1); + packetStore.openRetrievalStatus = (count == 2) ? PacketStore::InProgress : PacketStore::Suspended; + count++; + } + + String<ECSSPacketStoreIdSize> finalIds[4] = {wrongPacketStoreIds[0], correctPacketStoreIds[0], + correctPacketStoreIds[1], correctPacketStoreIds[2]}; + + ErrorHandler::ExecutionStartErrorType expectedErrors[4] = { + ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithStorageStatusEnabled, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithByTimeRangeRetrieval, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithOpenRetrievalInProgress}; + + for (int i = 0; i < 4; i++) { + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeTypeToCircular, Message::TC, 1); + + request.appendString(finalIds[i]); + MessageParser::execute(request); + CHECK(ServiceTests::count() == i + 1); + CHECK(ServiceTests::countThrownErrors(expectedErrors[i]) == 1); + } + + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[0]).packetStoreType == PacketStore::Bounded); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[1]).packetStoreType == PacketStore::Bounded); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[2]).packetStoreType == PacketStore::Bounded); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).packetStoreType == PacketStore::Bounded); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Changing the packet store type to bounded") { + SECTION("Successful changing of type to bounded") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).packetStoreType = PacketStore::Circular; + storageAndRetrieval.getPacketStore(packetStoreId).storageStatus = false; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = false; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + } + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeTypeToBounded, Message::TC, 1); + + request.appendString(packetStoreIds[0]); + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).packetStoreType == PacketStore::Bounded); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).packetStoreType == PacketStore::Circular); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).packetStoreType == PacketStore::Circular); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).packetStoreType == PacketStore::Circular); + + Message request2(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeTypeToBounded, Message::TC, 1); + + request2.appendString(packetStoreIds[3]); + MessageParser::execute(request2); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).packetStoreType == PacketStore::Bounded); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).packetStoreType == PacketStore::Circular); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).packetStoreType == PacketStore::Circular); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).packetStoreType == PacketStore::Bounded); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed changing of type to bounded") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + int count = 0; + for (auto& packetStoreId : correctPacketStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).packetStoreType = PacketStore::Circular; + storageAndRetrieval.getPacketStore(packetStoreId).storageStatus = (count == 0); + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = (count == 1); + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = + (count == 2) ? PacketStore::InProgress : PacketStore::Suspended; + count++; + } + + String<ECSSPacketStoreIdSize> finalIds[4] = {wrongPacketStoreIds[0], correctPacketStoreIds[0], + correctPacketStoreIds[1], correctPacketStoreIds[2]}; + + ErrorHandler::ExecutionStartErrorType expectedErrors[4] = { + ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithStorageStatusEnabled, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithByTimeRangeRetrieval, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithOpenRetrievalInProgress}; + + for (int i = 0; i < 4; i++) { + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeTypeToBounded, Message::TC, 1); + + request.appendString(finalIds[i]); + MessageParser::execute(request); + CHECK(ServiceTests::count() == i + 1); + CHECK(ServiceTests::countThrownErrors(expectedErrors[i]) == 1); + } + + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[0]).packetStoreType == PacketStore::Circular); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[1]).packetStoreType == PacketStore::Circular); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[2]).packetStoreType == PacketStore::Circular); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).packetStoreType == PacketStore::Circular); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Changing the virtual channel of packet stores") { + SECTION("Successful change of virtual channel") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + uint8_t virtualChannels[2] = {1, 5}; + + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = false; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + } + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeVirtualChannel, Message::TC, 1); + + request.appendString(packetStoreIds[0]); + request.appendUint8(virtualChannels[0]); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).virtualChannel == virtualChannels[0]); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).virtualChannel == 6); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).virtualChannel == 1); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).virtualChannel == 2); + + Message request2(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeVirtualChannel, Message::TC, 1); + + request2.appendString(packetStoreIds[3]); + request2.appendUint8(virtualChannels[1]); + + MessageParser::execute(request2); + + CHECK(ServiceTests::count() == 0); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).virtualChannel == virtualChannels[0]); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).virtualChannel == 6); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).virtualChannel == 1); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).virtualChannel == virtualChannels[1]); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed change of virtual channel") { + initializePacketStores(); + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + uint8_t oldVirtualChannels[4] = {4, 6, 1, 2}; + + int count = 0; + for (auto& packetStoreId : correctPacketStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = (count == 0); + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = + (count == 1) ? PacketStore::InProgress : PacketStore::Suspended; + count++; + } + + String<ECSSPacketStoreIdSize> finalIds[4] = {wrongPacketStoreIds[0], correctPacketStoreIds[0], + correctPacketStoreIds[1], correctPacketStoreIds[2]}; + + ErrorHandler::ExecutionStartErrorType expectedErrors[4] = { + ErrorHandler::ExecutionStartErrorType::NonExistingPacketStore, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithByTimeRangeRetrieval, + ErrorHandler::ExecutionStartErrorType::GetPacketStoreWithOpenRetrievalInProgress, + ErrorHandler::ExecutionStartErrorType::InvalidVirtualChannel}; + + for (int i = 0; i < 4; i++) { + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ChangeVirtualChannel, Message::TC, 1); + + request.appendString(finalIds[i]); + request.appendUint8(i == 3 ? VirtualChannelLimits.max + 1 : 3); + MessageParser::execute(request); + CHECK(ServiceTests::count() == i + 1); + CHECK(ServiceTests::countThrownErrors(expectedErrors[i]) == 1); + } + + int index = 0; + for (auto& packetStoreId : correctPacketStoreIds) { + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreId).virtualChannel == oldVirtualChannels[index]); + index++; + } + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Reporting the content summary of packet stores") { + SECTION("Successful content summary report of specified packet stores") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ReportContentSummaryOfPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 2; + request.appendUint16(numOfPacketStores); + for (int i = 0; i < numOfPacketStores; i++) { + storageAndRetrieval.getPacketStore(packetStoreIds[i]).openRetrievalStartTimeTag = 5; + request.appendString(packetStoreIds[i]); + } + + uint8_t packetStoreData[ECSSPacketStoreIdSize] = "ps2"; + uint8_t packetStoreData2[ECSSPacketStoreIdSize] = "ps25"; + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + Message report = ServiceTests::get(0); + REQUIRE(report.messageType == StorageAndRetrievalService::MessageType::PacketStoreContentSummaryReport); + REQUIRE(report.readUint16() == 2); + + // Packet store 1 + uint8_t data[ECSSPacketStoreIdSize]; + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(packetStoreData), std::end(packetStoreData), std::begin(data))); + CHECK(report.readUint32() == timestamps1[0]); + CHECK(report.readUint32() == timestamps1[5]); + CHECK(report.readUint32() == 5); + CHECK(report.readUint16() == 30); + CHECK(report.readUint16() == 20); + // Packet store 2 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(packetStoreData2), std::end(packetStoreData2), std::begin(data))); + CHECK(report.readUint32() == timestamps2[0]); + CHECK(report.readUint32() == timestamps2[4]); + CHECK(report.readUint32() == 5); + CHECK(report.readUint16() == 25); + CHECK(report.readUint16() == 10); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Successful content summary report of all packet stores") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + int count = 0; + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStartTimeTag = (count == 3) ? 20 : 15; + count++; + } + + uint8_t packetStoreData[ECSSPacketStoreIdSize] = "ps2"; + uint8_t packetStoreData2[ECSSPacketStoreIdSize] = "ps25"; + uint8_t packetStoreData3[ECSSPacketStoreIdSize] = "ps5555"; + uint8_t packetStoreData4[ECSSPacketStoreIdSize] = "ps799"; + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ReportContentSummaryOfPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 0; + request.appendUint16(numOfPacketStores); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + Message report = ServiceTests::get(0); + REQUIRE(report.messageType == StorageAndRetrievalService::MessageType::PacketStoreContentSummaryReport); + REQUIRE(report.readUint16() == 4); + + // Packet store 1 + uint8_t data[ECSSPacketStoreIdSize]; + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(packetStoreData), std::end(packetStoreData), std::begin(data))); + CHECK(report.readUint32() == timestamps1[0]); + CHECK(report.readUint32() == timestamps1[5]); + CHECK(report.readUint32() == 15); + CHECK(report.readUint16() == 30); + CHECK(report.readUint16() == 0); + // Packet store 2 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(packetStoreData2), std::end(packetStoreData2), std::begin(data))); + CHECK(report.readUint32() == timestamps2[0]); + CHECK(report.readUint32() == timestamps2[4]); + CHECK(report.readUint32() == 15); + CHECK(report.readUint16() == 25); + CHECK(report.readUint16() == 10); + // Packet store 3 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(packetStoreData3), std::end(packetStoreData3), std::begin(data))); + CHECK(report.readUint32() == timestamps4[0]); + CHECK(report.readUint32() == timestamps4[7]); + CHECK(report.readUint32() == 20); + CHECK(report.readUint16() == 40); + CHECK(report.readUint16() == 30); + // Packet store 4 + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(packetStoreData4), std::end(packetStoreData4), std::begin(data))); + CHECK(report.readUint32() == timestamps3[0]); + CHECK(report.readUint32() == timestamps3[3]); + CHECK(report.readUint32() == 15); + CHECK(report.readUint16() == 20); + CHECK(report.readUint16() == 0); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed content summary report of packet stores") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + String<ECSSPacketStoreIdSize> finalIds[3] = {wrongPacketStoreIds[0], wrongPacketStoreIds[1], + correctPacketStoreIds[0]}; + + storageAndRetrieval.getPacketStore(correctPacketStoreIds[0]).openRetrievalStartTimeTag = 5; + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::ReportContentSummaryOfPacketStores, Message::TC, 1); + + uint16_t numOfPacketStores = 3; + request.appendUint16(numOfPacketStores); + for (int i = 0; i < numOfPacketStores; i++) { + request.appendString(finalIds[i]); + } + + uint8_t packetStoreData[ECSSPacketStoreIdSize] = "ps2"; + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 2); + + Message report = ServiceTests::get(2); + REQUIRE(report.messageType == StorageAndRetrievalService::MessageType::PacketStoreContentSummaryReport); + REQUIRE(report.readUint16() == 1); + + // Packet store 1 + uint8_t data[ECSSPacketStoreIdSize]; + report.readString(data, ECSSPacketStoreIdSize); + CHECK(std::equal(std::begin(packetStoreData), std::end(packetStoreData), std::begin(data))); + CHECK(report.readUint32() == timestamps1[0]); + CHECK(report.readUint32() == timestamps1[5]); + CHECK(report.readUint32() == 5); + CHECK(report.readUint16() == 30); + CHECK(report.readUint16() == 20); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Deleting packet store content") { + SECTION("Successful deletion of content, specified time-tag in the middle of the packets stored") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStoreContent, Message::TC, 1); + + uint32_t storageTime = 5; + uint16_t numOfPacketStores = 2; + request.appendUint32(storageTime); + request.appendUint16(numOfPacketStores); + + for (int i = 0; i < numOfPacketStores; i++) { + auto packetStoreId = packetStoreIds[i]; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = false; + request.appendString(packetStoreId); + } + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).storedTelemetryPackets.size() == 6); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).storedTelemetryPackets.size() == 5); + + MessageParser::execute(request); + CHECK(ServiceTests::count() == 0); + + uint32_t expectedTimeStamps1[3] = {7, 9, 11}; + uint32_t expectedTimeStamps2[2] = {15, 22}; + uint32_t leftTimeStamps1[3]; + uint32_t leftTimeStamps2[2]; + + int count = 0; + for (auto& tmPacket : storageAndRetrieval.getPacketStore(packetStoreIds[0]).storedTelemetryPackets) { + leftTimeStamps1[count++] = tmPacket.first; + } + count = 0; + for (auto& tmPacket : storageAndRetrieval.getPacketStore(packetStoreIds[1]).storedTelemetryPackets) { + leftTimeStamps2[count++] = tmPacket.first; + } + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).storedTelemetryPackets.size() == 3); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).storedTelemetryPackets.size() == 2); + REQUIRE( + std::equal(std::begin(expectedTimeStamps1), std::end(expectedTimeStamps1), std::begin(leftTimeStamps1))); + REQUIRE( + std::equal(std::begin(expectedTimeStamps2), std::end(expectedTimeStamps2), std::begin(leftTimeStamps2))); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Successful deletion of content, specified time-tag is smaller than the min stored timestamp") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStoreContent, Message::TC, 1); + + uint32_t storageTime = 3; + uint16_t numOfPacketStores = 2; + request.appendUint32(storageTime); + request.appendUint16(numOfPacketStores); + + for (int i = 2; i < numOfPacketStores + 2; i++) { + auto packetStoreId = packetStoreIds[i]; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = false; + request.appendString(packetStoreId); + } + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.size() == 4); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).storedTelemetryPackets.size() == 8); + + MessageParser::execute(request); + CHECK(ServiceTests::count() == 0); + + uint32_t expectedTimeStamps1[4] = {4, 7, 9, 14}; + uint32_t expectedTimeStamps2[8] = {4, 6, 34, 40, 44, 51, 52, 58}; + uint32_t leftTimeStamps1[4]; + uint32_t leftTimeStamps2[8]; + + int count = 0; + for (auto& tmPacket : storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets) { + leftTimeStamps1[count++] = tmPacket.first; + } + count = 0; + for (auto& tmPacket : storageAndRetrieval.getPacketStore(packetStoreIds[3]).storedTelemetryPackets) { + leftTimeStamps2[count++] = tmPacket.first; + } + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.size() == 4); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).storedTelemetryPackets.size() == 8); + REQUIRE( + std::equal(std::begin(expectedTimeStamps1), std::end(expectedTimeStamps1), std::begin(leftTimeStamps1))); + REQUIRE( + std::equal(std::begin(expectedTimeStamps2), std::end(expectedTimeStamps2), std::begin(leftTimeStamps2))); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Successful deletion of content, specified time-tag is larger than the max stored timestamp") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStoreContent, Message::TC, 1); + + uint32_t storageTime = 59; + uint16_t numOfPacketStores = 2; + request.appendUint32(storageTime); + request.appendUint16(numOfPacketStores); + + for (int i = 2; i < numOfPacketStores + 2; i++) { + auto packetStoreId = packetStoreIds[i]; + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = PacketStore::Suspended; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = false; + request.appendString(packetStoreId); + } + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.size() == 4); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).storedTelemetryPackets.size() == 8); + + MessageParser::execute(request); + CHECK(ServiceTests::count() == 0); + + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).storedTelemetryPackets.empty()); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Both successful and failed deletion of content for all packet stores") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStoreContent, Message::TC, 1); + + uint32_t storageTime = 15; + uint16_t numOfPacketStores = 0; + request.appendUint32(storageTime); + request.appendUint16(numOfPacketStores); + + int count = 0; + for (auto& packetStoreId : packetStoreIds) { + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = (count == 0); + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = + (count == 1) ? PacketStore::InProgress : PacketStore::Suspended; + count++; + } + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).storedTelemetryPackets.size() == 6); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).storedTelemetryPackets.size() == 5); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.size() == 4); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).storedTelemetryPackets.size() == 8); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::SetPacketStoreWithByTimeRangeRetrieval) == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::SetPacketStoreWithOpenRetrievalInProgress) == 1); + + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[0]).storedTelemetryPackets.size() == 6); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[1]).storedTelemetryPackets.size() == 5); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[3]).storedTelemetryPackets.size() == 6); + + uint32_t expectedTimeStamps1[6] = {2, 4, 5, 7, 9, 11}; + uint32_t expectedTimeStamps2[5] = {0, 1, 4, 15, 22}; + uint32_t expectedTimeStamps4[6] = {34, 40, 44, 51, 52, 58}; + + uint32_t leftTimeStamps1[6]; + uint32_t leftTimeStamps2[5]; + uint32_t leftTimeStamps4[6]; + + count = 0; + for (auto& tmPacket : storageAndRetrieval.getPacketStore(packetStoreIds[0]).storedTelemetryPackets) { + leftTimeStamps1[count++] = tmPacket.first; + } + count = 0; + for (auto& tmPacket : storageAndRetrieval.getPacketStore(packetStoreIds[1]).storedTelemetryPackets) { + leftTimeStamps2[count++] = tmPacket.first; + } + count = 0; + for (auto& tmPacket : storageAndRetrieval.getPacketStore(packetStoreIds[3]).storedTelemetryPackets) { + leftTimeStamps4[count++] = tmPacket.first; + } + + REQUIRE( + std::equal(std::begin(expectedTimeStamps1), std::end(expectedTimeStamps1), std::begin(leftTimeStamps1))); + REQUIRE( + std::equal(std::begin(expectedTimeStamps2), std::end(expectedTimeStamps2), std::begin(leftTimeStamps2))); + REQUIRE( + std::equal(std::begin(expectedTimeStamps4), std::end(expectedTimeStamps4), std::begin(leftTimeStamps4))); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Failed deletion of content") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + String<ECSSPacketStoreIdSize> finalIds[7] = { + wrongPacketStoreIds[0], wrongPacketStoreIds[1], wrongPacketStoreIds[2], correctPacketStoreIds[0], + correctPacketStoreIds[1], correctPacketStoreIds[2], correctPacketStoreIds[3]}; + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::DeletePacketStoreContent, Message::TC, 1); + + uint32_t storageTime = 59; + uint16_t numOfPacketStores = 7; + request.appendUint32(storageTime); + request.appendUint16(numOfPacketStores); + + for (int i = 0; i < 3; i++) { + auto packetStoreId = finalIds[i]; + request.appendString(packetStoreId); + } + + for (int i = 3; i < 7; i++) { + auto packetStoreId = finalIds[i]; + storageAndRetrieval.getPacketStore(packetStoreId).byTimeRangeRetrievalStatus = (i == 4 || i == 6); + storageAndRetrieval.getPacketStore(packetStoreId).openRetrievalStatus = + (i == 3 || i == 5) ? PacketStore::InProgress : PacketStore::Suspended; + request.appendString(packetStoreId); + } + + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[0]).storedTelemetryPackets.size() == 6); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[1]).storedTelemetryPackets.size() == 5); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[2]).storedTelemetryPackets.size() == 4); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).storedTelemetryPackets.size() == 8); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 7); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::SetPacketStoreWithByTimeRangeRetrieval) == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::SetPacketStoreWithOpenRetrievalInProgress) == 2); + + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[0]).storedTelemetryPackets.size() == 6); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[1]).storedTelemetryPackets.size() == 5); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[2]).storedTelemetryPackets.size() == 4); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[3]).storedTelemetryPackets.size() == 8); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Copying packets in time window, from tag to tag") { + SECTION("Both time-tags earlier than the earliest time-tag") { + /** + * CASE 0: + * + * (tag1)-------(tag2)-------(earliest packet timestamp)-----(..more packets..)-----(latest packet timestamp) + * left-most packet in deque tag2 somewhere inside right-most packet in deque + */ + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::FromTagToTag; + uint32_t timeTag1 = 0; + uint32_t timeTag2 = 1; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::CopyOfPacketsFailed) == 1); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.empty()); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Time-tag1 earlier than the earliest stored time-tag, and time-tag2 in between the existing ones") { + /** + * CASE 1: + * + * (tag1)--------(earliest packet timestamp)-----(..more packets..)-----(tag2)--------(latest packet timestamp) + * left-most packet in deque tag2 somewhere inside right-most packet in deque + */ + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::FromTagToTag; + uint32_t timeTag1 = 0; + uint32_t timeTag2 = 4; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.size() == 2); + int index = 0; + for (auto& tmPacket : targetPacketStore.storedTelemetryPackets) { + REQUIRE(tmPacket.first == timestamps1[index++]); + } + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Both time-tags in between the stored timestamps") { + /** + * CASE 2: + * + * (earlier packet timestamp)-------(tag1)-----(..more packets)-----(tag2)--------(latest packet timestamp) + * left-most packet in deque both tag1 and tag2 inside right-most packet in deque + */ + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::FromTagToTag; + uint32_t timeTag1 = 35; + uint32_t timeTag2 = 52; + auto fromPacketStoreId = packetStoreIds[3]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.size() == 4); + int index = 3; + for (auto& tmPacket : targetPacketStore.storedTelemetryPackets) { + REQUIRE(tmPacket.first == timestamps4[index++]); + } + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Time-tag1 in between the stored timestamps and tag2 larger than the max timestamp") { + /** + * CASE 3: + * + * (earlier packet timestamp)-------(tag1)-----(..more packets)-----(latest packet timestamp)--------(tag2) + * left-most packet in deque tag1 inside right-most packet in deque + */ + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::FromTagToTag; + uint32_t timeTag1 = 3; + uint32_t timeTag2 = 27; + auto fromPacketStoreId = packetStoreIds[1]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.size() == 3); + int index = 2; + for (auto& tmPacket : targetPacketStore.storedTelemetryPackets) { + REQUIRE(tmPacket.first == timestamps2[index++]); + } + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Both time-tags larger than largest stored time-tag") { + /** + * CASE 4: + * + * (earliest packet timestamp)-----(..more packets..)-----(latest packet timestamp)-----(tag1)-------(tag2) + * left-most packet in deque tag2 somewhere inside right-most packet in deque + */ + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::FromTagToTag; + uint32_t timeTag1 = 12; + uint32_t timeTag2 = 14; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::CopyOfPacketsFailed) == 1); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.empty()); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Invalid packet store requested") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto correctPacketStoreIds = validPacketStoreIds(); + auto wrongPacketStoreIds = invalidPacketStoreIds(); + padWithZeros(correctPacketStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(correctPacketStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(correctPacketStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::FromTagToTag; + uint32_t timeTag1 = 3; + uint32_t timeTag2 = 27; + auto fromPacketStoreId = wrongPacketStoreIds[0]; + auto toPacketStoreId = correctPacketStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::NonExistingPacketStore) == 1); + REQUIRE(storageAndRetrieval.getPacketStore(toPacketStoreId).storedTelemetryPackets.empty()); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Invalid time window requested") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::FromTagToTag; + uint32_t timeTag1 = 26; + uint32_t timeTag2 = 17; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::InvalidTimeWindow) == 1); + REQUIRE(storageAndRetrieval.getPacketStore(toPacketStoreId).storedTelemetryPackets.empty()); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Destination packet not empty") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + REQUIRE(not storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::FromTagToTag; + uint32_t timeTag1 = 3; + uint32_t timeTag2 = 7; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::DestinationPacketStoreNotEmtpy) == 1); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("No packets contained into the requested time-window") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::FromTagToTag; + uint32_t timeTag1 = 0; + uint32_t timeTag2 = 3; + auto fromPacketStoreId = packetStoreIds[3]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::CopyOfPacketsFailed) == 1); + CHECK(storageAndRetrieval.getPacketStore(toPacketStoreId).storedTelemetryPackets.empty()); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Copying packets in time window, after time-tag") { + SECTION("Time-tag in between the stored time-tags") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::AfterTimeTag; + uint32_t timeTag1 = 6; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.size() == 3); + uint32_t expectedTimestamps[3] = {7, 9, 11}; + uint32_t existingTimestamps[3]; + + int index = 0; + for (auto& tmPacket : targetPacketStore.storedTelemetryPackets) { + existingTimestamps[index++] = tmPacket.first; + } + REQUIRE( + std::equal(std::begin(expectedTimestamps), std::end(expectedTimestamps), std::begin(existingTimestamps))); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Time-tag earlier than the earliest stored time-tag") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::AfterTimeTag; + uint32_t timeTag1 = 1; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.size() == 6); + uint32_t existingTimestamps[6]; + + int index = 0; + for (auto& tmPacket : targetPacketStore.storedTelemetryPackets) { + existingTimestamps[index++] = tmPacket.first; + } + REQUIRE(std::equal(std::begin(timestamps1), std::end(timestamps1), std::begin(existingTimestamps))); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Time-tag larger than the largest stored time-tag") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::AfterTimeTag; + uint32_t timeTag1 = 25; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag1); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::CopyOfPacketsFailed) == 1); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.empty()); + + ServiceTests::reset(); + Services.reset(); + } +} + +TEST_CASE("Copying packets in time window, before time-tag") { + SECTION("Time-tag in between the stored time-tags") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::BeforeTimeTag; + uint32_t timeTag2 = 6; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.size() == 3); + uint32_t expectedTimestamps[3] = {2, 4, 5}; + uint32_t existingTimestamps[3]; + + int index = 0; + for (auto& tmPacket : targetPacketStore.storedTelemetryPackets) { + existingTimestamps[index++] = tmPacket.first; + } + REQUIRE( + std::equal(std::begin(expectedTimestamps), std::end(expectedTimestamps), std::begin(existingTimestamps))); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Time-tag larger than the largest stored time-tag") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::BeforeTimeTag; + uint32_t timeTag2 = 56; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.size() == 6); + uint32_t existingTimestamps[6]; + + int index = 0; + for (auto& tmPacket : targetPacketStore.storedTelemetryPackets) { + existingTimestamps[index++] = tmPacket.first; + } + REQUIRE(std::equal(std::begin(timestamps1), std::end(timestamps1), std::begin(existingTimestamps))); + + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Time-tag earlier than the earliest stored time-tag") { + initializePacketStores(); + addTelemetryPacketsInPacketStores(); + + REQUIRE(storageAndRetrieval.currentNumberOfPacketStores() == 4); + auto packetStoreIds = validPacketStoreIds(); + padWithZeros(packetStoreIds); + + // Empty the target packet store, so the copy can occur + storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.clear(); + REQUIRE(storageAndRetrieval.getPacketStore(packetStoreIds[2]).storedTelemetryPackets.empty()); + + Message request(StorageAndRetrievalService::ServiceType, + StorageAndRetrievalService::MessageType::CopyPacketsInTimeWindow, Message::TC, 1); + + uint8_t typeOfTimeWindow = StorageAndRetrievalService::TimeWindowType::BeforeTimeTag; + uint32_t timeTag2 = 1; + auto fromPacketStoreId = packetStoreIds[0]; + auto toPacketStoreId = packetStoreIds[2]; + + request.appendEnum8(typeOfTimeWindow); + request.appendUint32(timeTag2); + request.appendString(fromPacketStoreId); + request.appendString(toPacketStoreId); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::CopyOfPacketsFailed) == 1); + auto& targetPacketStore = storageAndRetrieval.getPacketStore(toPacketStoreId); + REQUIRE(targetPacketStore.storedTelemetryPackets.empty()); + + ServiceTests::reset(); + Services.reset(); + } +}