diff --git a/.gitmodules b/.gitmodules index c30fec28aea7f8a5584f89122ff9fc8a58a6863a..ebb319f25194b99f4bf61ba4c2415525d7a86ec0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ [submodule "lib/Catch2"] - path = lib/Catch2 - url = https://github.com/catchorg/Catch2.git + path = lib/Catch2 + url = https://github.com/catchorg/Catch2.git [submodule "lib/etl"] - path = lib/etl - url = https://github.com/ETLCPP/etl.git + path = lib/etl + url = https://github.com/ETLCPP/etl.git [submodule "ci/page_style/doxygen_dark_theme"] - path = ci/page_style/doxygen_dark_theme - url = https://github.com/MaJerle/doxygen_dark_theme.git + path = ci/page_style/doxygen_dark_theme + url = https://github.com/MaJerle/doxygen_dark_theme.git [submodule "lib/logger"] - path = lib/logger - url = https://gitlab.com/acubesat/obc/logger.git + path = lib/logger + url = https://gitlab.com/acubesat/obc/logger.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e5c2dee5446dfbb812365dd96086ae1574fbfd2..24ae6a8fd012616ff86b4a546faef0c52dd084a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,9 @@ add_library(common OBJECT src/Services/ParameterStatisticsService.cpp src/Services/OnBoardMonitoringService.cpp src/Helpers/Statistic.cpp + src/Services/RealTimeForwardingControlService.cpp src/Helpers/PMONBase.cpp + src/Helpers/AllMessageTypes.cpp ) # Specify the .cpp files for the executables diff --git a/inc/ECSS_Definitions.hpp b/inc/ECSS_Definitions.hpp index 01fc74b1db03fab7a40ea7d22c3a58d5c46a4429..24c490d77bb42b615960788e50d9c0ad8f4d22c8 100644 --- a/inc/ECSS_Definitions.hpp +++ b/inc/ECSS_Definitions.hpp @@ -183,6 +183,42 @@ inline const uint16_t ECSSPacketStoreIdSize = 15; */ inline const uint8_t ECSSMaxHousekeepingStructures = 10; +/** + * The max number of controlled application processes + * @see RealTimeForwardingControlService + */ +inline const uint8_t ECSSMaxControlledApplicationProcesses = 5; + +/** + * The max number of report type blocking definitions per service type definition in the application process + * configuration + * @see RealTimeForwardingControlService + * todo: must change when a service with more report types is implemented. + */ +inline const uint8_t ECSSMaxReportTypeDefinitions = 20; + +/** + * The max number of service type definitions per application process type definition in the application process + * configuration + * @see RealTimeForwardingControlService + * todo: must change when all 15 services are implemented. + */ +inline const uint8_t ECSSMaxServiceTypeDefinitions = 10; + +/** + * The number of possible combinations between application processes and service types, i.e. the number of all + * possible (applicationID, serviceType) pairs. + */ +inline const uint8_t ECSSMaxApplicationsServicesCombinations = ECSSMaxControlledApplicationProcesses * + ECSSMaxServiceTypeDefinitions; + +/** + * The max number of event definition IDs per event report blocking type definition in the event report blocking + * configuration + * @see RealTimeForwardingControlService + */ +inline const uint8_t ECSSMaxEventDefinitionIDs = 15; + /** * Limits noting the minimum and maximum valid Virtual Channels used by the Storage and Retrieval subservice */ @@ -196,6 +232,5 @@ inline struct { */ inline const uint8_t ECSSMaxMonitoringDefinitions = 4; - /** @} */ #endif // ECSS_SERVICES_ECSS_DEFINITIONS_H diff --git a/inc/ErrorHandler.hpp b/inc/ErrorHandler.hpp index bffa26ddb99f9bfc607acf557c2f111329a00a5f..351a75caba2833cef379c3d5af9549de4022572c 100644 --- a/inc/ErrorHandler.hpp +++ b/inc/ErrorHandler.hpp @@ -1,8 +1,8 @@ #ifndef PROJECT_ERRORHANDLER_HPP #define PROJECT_ERRORHANDLER_HPP -#include <type_traits> #include <stdint.h> // for the uint_8t stepID +#include <type_traits> // Forward declaration of the class, since its header file depends on the ErrorHandler class Message; @@ -323,7 +323,27 @@ public: /** * Request to report a non existent parameter monitoring definition. */ - ReportParameterNotInTheParameterMonitoringList = 46 + ReportParameterNotInTheParameterMonitoringList = 46, + /** + * Attempt to add a new service type, when the addition of all service types is already enabled in the + * Application Process configuration (ST[14]) + */ + AllServiceTypesAlreadyAllowed = 47, + /** + * Attempt to add a new report type, when the max number of reports types allowed per service type + * definition in the Application Process configuration is already reached (ST[14]) + */ + MaxReportTypesReached = 48, + /** + * Attempt to add a new service type, when the max number of service types allowed per application process + * definition in the Application Process configuration is already reached (ST[14]) + */ + MaxServiceTypesReached = 49, + /** + * Attempt to add a report/event definition/housekeeping report type, when the specified application process + * ID is not controlled by the Service (ST[14]) + */ + NotControlledApplication = 50, }; /** diff --git a/inc/Helpers/AllMessageTypes.hpp b/inc/Helpers/AllMessageTypes.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fb5c2c488647f0b54fa783dd09c72eff28801092 --- /dev/null +++ b/inc/Helpers/AllMessageTypes.hpp @@ -0,0 +1,20 @@ +#ifndef ECSS_SERVICES_ALLMESSAGETYPES_HPP +#define ECSS_SERVICES_ALLMESSAGETYPES_HPP + +#include "ECSS_Definitions.hpp" +#include <etl/map.h> +#include <etl/vector.h> + +/** + * Namespace containing all the message types for every service type. + */ +namespace AllMessageTypes { + /** + * Map containing all the message types, per service. The key is the ServiceType and the value, + * an etl vector containing the message types. + */ + extern etl::map<uint8_t, etl::vector<uint8_t, ECSSMaxReportTypeDefinitions>, ECSSMaxServiceTypeDefinitions> messagesOfService; + +} // namespace AllMessageTypes + +#endif diff --git a/inc/Helpers/ForwardControlConfiguration.hpp b/inc/Helpers/ForwardControlConfiguration.hpp new file mode 100644 index 0000000000000000000000000000000000000000..da573dd1ff4979caaa4ed8953fb88874ee3a1e35 --- /dev/null +++ b/inc/Helpers/ForwardControlConfiguration.hpp @@ -0,0 +1,47 @@ +#ifndef ECSS_SERVICES_FORWARDCONTROLCONFIGURATION_HPP +#define ECSS_SERVICES_FORWARDCONTROLCONFIGURATION_HPP + +#include "ECSS_Definitions.hpp" +#include "ErrorHandler.hpp" +#include "Helpers/Parameter.hpp" +#include "etl/map.h" +#include "etl/vector.h" + +/** + * The Application Process configuration. It's basically a map, storing a vector of report type definitions for each + * pair of (applicationID, serviceType). It contains definitions, which indicate whether a telemetry message, produced + * by a service, inside an application process (subsystem), should be forwarded to the ground station. + */ +class ApplicationProcessConfiguration { +public: + /** + * Vector containing the Report Type definitions. Each definition has its unique name of type uint8. For + * example, a Report Type definition could be 'ReportHousekeepingStructures'. + */ + typedef etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> ReportTypeDefinitions; + + /** + * This is the key for the application process configuration map. It contains a pair with the applicationID and + * the serviceType. + */ + typedef std::pair<uint8_t, uint8_t> AppServiceKey; + + /** + * Map containing the report type definitions. Each application process has its own ID. The combination of the + * application ID and the service type is used as a key to provide access to the list of report type definitions. + * + * @note + * The report type definitions are basically the message types of each service. For example a message type for the + * 'ParameterStatisticsService' (ST04) is 'ParameterStatisticsService::MessageType::ParameterStatisticsReport'. The + * Real Time Forwarding Control Service (ST14) uses this map as a lookup table, to identify whether a requested + * triplet (app->service->message type) is allowed to be forwarded to the ground station via the corresponding virtual + * channel. The requested message type is only forwarded, if the requested application process ID and service type + * already exist in the map, and the requested report type is located in the vector of report types, which corresponds + * to the appID and service type. + */ + etl::map<AppServiceKey, ReportTypeDefinitions, ECSSMaxApplicationsServicesCombinations> definitions; + + ApplicationProcessConfiguration() = default; +}; + +#endif diff --git a/inc/Platform/x86/ECSS_Configuration.hpp b/inc/Platform/x86/ECSS_Configuration.hpp index 3b27fecf53cd2ad67e162144c2f9f1c5d6bd3774..6dbedb3a135a1eba0f72b7d4f6c2e30c0569506f 100644 --- a/inc/Platform/x86/ECSS_Configuration.hpp +++ b/inc/Platform/x86/ECSS_Configuration.hpp @@ -18,24 +18,22 @@ * @{ */ -#define SERVICE_ALL ///< Enables compilation of all the ECSS services - -#ifdef SERVICE_ALL -#define SERVICE_EVENTACTION ///< Compile ST[19] event-action -#define SERVICE_EVENTREPORT ///< Compile ST[05] event reporting -#define SERVICE_FUNCTION ///< Compile ST[08] function management -#define SERVICE_HOUSEKEEPING ///< Compile ST[03] housekeeping -#define SERVICE_LARGEPACKET ///< Compile ST[13] large packet transfer -#define SERVICE_MEMORY ///< Compile ST[06] memory management -#define SERVICE_ONBOARDMONITORING ///< Compile ST[12] on-board monitoring -#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_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 +#define SERVICE_ALL ///< Enables compilation of all the ECSS services +#define SERVICE_EVENTACTION ///< Compile ST[19] event-action +#define SERVICE_EVENTREPORT ///< Compile ST[05] event reporting +#define SERVICE_FUNCTION ///< Compile ST[08] function management +#define SERVICE_HOUSEKEEPING ///< Compile ST[03] housekeeping +#define SERVICE_LARGEPACKET ///< Compile ST[13] large packet transfer +#define SERVICE_MEMORY ///< Compile ST[06] memory management +#define SERVICE_ONBOARDMONITORING ///< Compile ST[12] on-board monitoring +#define SERVICE_PARAMETER ///< Compile ST[20] parameter management +#define SERVICE_PARAMETERSTATISTICS ///< Compile ST[04] parameter statistics +#define SERVICE_REALTIMEFORWARDINGCONTROL ///< Compile ST[14] real time forwarding control +#define SERVICE_REQUESTVERIFICATION ///< Compile ST[01] request verification +#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 // ECSS_SERVICES_ECSS_CONFIGURATION_HPP diff --git a/inc/Platform/x86/Parameters/PlatformParameters.hpp b/inc/Platform/x86/Parameters/PlatformParameters.hpp index a1332949b970ef685be69101461a8f181afc7be6..3977b370ca020248a7216533768c747c8d9a4488 100644 --- a/inc/Platform/x86/Parameters/PlatformParameters.hpp +++ b/inc/Platform/x86/Parameters/PlatformParameters.hpp @@ -21,4 +21,4 @@ namespace PlatformParameters { inline Parameter<uint32_t> parameter3(10); } -#endif \ No newline at end of file +#endif diff --git a/inc/ServicePool.hpp b/inc/ServicePool.hpp index 9dbb533a2640a1d96abed2543d33129edf5b5314..47ff8595a6c909500d7aa9491f304054845a6d63 100644 --- a/inc/ServicePool.hpp +++ b/inc/ServicePool.hpp @@ -14,6 +14,7 @@ #include "Services/StorageAndRetrievalService.hpp" #include "Services/HousekeepingService.hpp" #include "Services/ParameterStatisticsService.hpp" +#include "Services/RealTimeForwardingControlService.hpp" #include "Services/OnBoardMonitoringService.hpp" /** @@ -70,6 +71,10 @@ public: ParameterService parameterManagement; #endif +#ifdef SERVICE_REALTIMEFORWARDINGCONTROL + RealTimeForwardingControlService realTimeForwarding; +#endif + #ifdef SERVICE_PARAMETERSTATISTICS ParameterStatisticsService parameterStatistics; #endif diff --git a/inc/Services/RealTimeForwardingControlService.hpp b/inc/Services/RealTimeForwardingControlService.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5e42edbeadf9da26029f9b8d5fb5bd357d135a65 --- /dev/null +++ b/inc/Services/RealTimeForwardingControlService.hpp @@ -0,0 +1,129 @@ +#ifndef ECSS_SERVICES_REALTIMEFORWARDINGCONTROLSERVICE_HPP +#define ECSS_SERVICES_REALTIMEFORWARDINGCONTROLSERVICE_HPP + +#include "ECSS_Definitions.hpp" +#include "ErrorHandler.hpp" +#include "Helpers/AllMessageTypes.hpp" +#include "Helpers/ForwardControlConfiguration.hpp" +#include "Service.hpp" +#include "etl/vector.h" + +/** + * Implementation of the ST[14] 'Real Time Forwarding Control Service' as defined in ECSS-E-ST-70-41C. + * + * The purpose of this Service is to control the forwarding of the telemetry to the ground station. It includes + * conditions for all the application processes that are controlled by the Service, which determine whether a message + * should be forwarded to the ground station, through the corresponding virtual channel. + * + * @author Konstantinos Petridis <petridkon@gmail.com> + */ +class RealTimeForwardingControlService { +public: + inline static const uint8_t ServiceType = 14; + + enum MessageType : uint8_t { + AddReportTypesToAppProcessConfiguration = 1, + }; + + RealTimeForwardingControlService() = default; + + /** + * Contains the Application IDs, controlled by the Service. + */ + etl::vector<uint8_t, ECSSMaxControlledApplicationProcesses> controlledApplications; + + /** + * The Application Process configuration, containing all the application process, service type and message type + * definitions. + */ + ApplicationProcessConfiguration applicationProcessConfiguration; + +private: + /** + * Adds all report types of the specified application process definition, to the application process configuration. + */ + void addAllReportsOfApplication(uint8_t applicationID); + + /** + * Adds all report types of the specified service type, to the application process configuration. + */ + void addAllReportsOfService(uint8_t applicationID, uint8_t serviceType); + + /** + * Counts the number of service types, stored for the specified application process. + */ + uint8_t countServicesOfApplication(uint8_t applicationID); + + /** + * Counts the number of report types, stored for the specified service type. + */ + uint8_t countReportsOfService(uint8_t applicationID, uint8_t serviceType); + + /** + * Checks whether the specified message type already exists in the specified application process and service + * type definition. + */ + bool reportExistsInAppProcessConfiguration(uint8_t applicationID, uint8_t serviceType, uint8_t messageType); + + /** + * Performs the necessary error checking/logging for a specific application process ID. Also, skips the necessary + * bytes from the request message, in case of an invalid request. + * + * @return True: if the application is valid and passes all the necessary error checking. + */ + bool checkApplicationOfAppProcessConfig(Message& request, uint8_t applicationID, uint8_t numOfServices); + + /** + * Checks if the specified application process is controlled by the Service and returns true if it does. + */ + bool checkAppControlled(Message& request, uint8_t applicationId); + + /** + * Checks if all service types are allowed already, i.e. if the application process contains no service type + * definitions. + */ + bool allServiceTypesAllowed(Message& request, uint8_t applicationID); + + /** + * Checks if the maximum number of service type definitions per application process is reached. + */ + bool maxServiceTypesReached(Message& request, uint8_t applicationID); + + /** + * Performs the necessary error checking/logging for a specific service type. Also, skips the necessary bytes + * from the request message, in case of an invalid request. + * + * @return True: if the service type is valid and passes all the necessary error checking. + */ + bool checkService(Message& request, uint8_t applicationID, uint8_t numOfMessages); + + /** + * Checks if the maximum number of report type definitions per service type definition is reached. + */ + bool maxReportTypesReached(Message& request, uint8_t applicationID, uint8_t serviceType); + + /** + * Checks if the maximum number of message types that can be contained inside a service type definition, is + * already reached. + * + * @return True: if the message type is valid and passes all the necessary error checking. + */ + bool checkMessage(Message& request, uint8_t applicationID, uint8_t serviceType, uint8_t messageType); + +public: + /** + * TC[14,1] 'Add report types to the application process forward control configuration'. + */ + void addReportTypesToAppProcessConfiguration(Message& request); + + /** + * It is responsible to call the suitable function that executes a TC 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 message Contains the necessary parameters to call the suitable subservice. + */ + void execute(Message& message); +}; + +#endif diff --git a/src/Helpers/AllMessageTypes.cpp b/src/Helpers/AllMessageTypes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c67e09b31d3ebf98fd7a477d051b23beb7949a62 --- /dev/null +++ b/src/Helpers/AllMessageTypes.cpp @@ -0,0 +1,72 @@ +#include "Helpers/AllMessageTypes.hpp" +#include "Services/EventActionService.hpp" +#include "Services/EventReportService.hpp" +#include "Services/HousekeepingService.hpp" +#include "Services/LargePacketTransferService.hpp" +#include "Services/MemoryManagementService.hpp" +#include "Services/ParameterService.hpp" +#include "Services/ParameterStatisticsService.hpp" +#include "Services/RealTimeForwardingControlService.hpp" +#include "Services/RequestVerificationService.hpp" +#include "Services/TestService.hpp" +#include "Services/TimeBasedSchedulingService.hpp" + +namespace AllMessageTypes { + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st01Messages = {RequestVerificationService::MessageType::FailedAcceptanceReport, + RequestVerificationService::MessageType::FailedCompletionOfExecution, + RequestVerificationService::MessageType::FailedProgressOfExecution, + RequestVerificationService::MessageType::FailedRoutingReport, + RequestVerificationService::MessageType::FailedStartOfExecution, + RequestVerificationService::MessageType::SuccessfulAcceptanceReport, + RequestVerificationService::MessageType::SuccessfulCompletionOfExecution, + RequestVerificationService::MessageType::SuccessfulProgressOfExecution, + RequestVerificationService::MessageType::SuccessfulStartOfExecution}; + + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st03Messages = { + HousekeepingService::MessageType::DisablePeriodicHousekeepingParametersReport, + HousekeepingService::MessageType::EnablePeriodicHousekeepingParametersReport, + HousekeepingService::MessageType::GenerateOneShotHousekeepingReport, + HousekeepingService::MessageType::HousekeepingParametersReport, + HousekeepingService::MessageType::HousekeepingPeriodicPropertiesReport, + HousekeepingService::MessageType::HousekeepingStructuresReport}; + + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st04Messages = { + ParameterStatisticsService::MessageType::ParameterStatisticsDefinitionsReport, + ParameterStatisticsService::MessageType::ParameterStatisticsReport, + }; + + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st05Messages = {EventReportService::MessageType::HighSeverityAnomalyReport, + EventReportService::MessageType::DisabledListEventReport, + EventReportService::MessageType::InformativeEventReport, + EventReportService::MessageType::LowSeverityAnomalyReport, + EventReportService::MessageType::MediumSeverityAnomalyReport}; + + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st06Messages = {MemoryManagementService::MessageType::CheckRawMemoryDataReport, + MemoryManagementService::MessageType::DumpRawMemoryDataReport}; + + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st11Messages = {TimeBasedSchedulingService::MessageType::TimeBasedScheduledSummaryReport}; + + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st13Messages = {LargePacketTransferService::MessageType::FirstDownlinkPartReport, + LargePacketTransferService::MessageType::InternalDownlinkPartReport, + LargePacketTransferService::MessageType::LastDownlinkPartReport}; + + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st17Messages = {TestService::MessageType::AreYouAliveTestReport, + TestService::MessageType::OnBoardConnectionTestReport}; + + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st19Messages = {EventActionService::MessageType::EventActionStatusReport}; + + etl::vector<uint8_t, ECSSMaxReportTypeDefinitions> st20Messages = {ParameterService::MessageType::ParameterValuesReport}; + + etl::map<uint8_t, etl::vector<uint8_t, ECSSMaxReportTypeDefinitions>, ECSSMaxServiceTypeDefinitions> messagesOfService = { + {RequestVerificationService::ServiceType, st01Messages}, + {HousekeepingService::ServiceType, st03Messages}, + {ParameterStatisticsService::ServiceType, st04Messages}, + {EventReportService::ServiceType, st05Messages}, + {MemoryManagementService::ServiceType, st06Messages}, + {TimeBasedSchedulingService::ServiceType, st11Messages}, + {LargePacketTransferService::ServiceType, st13Messages}, + {TestService::ServiceType, st17Messages}, + {EventActionService::ServiceType, st19Messages}, + {ParameterService::ServiceType, st20Messages}}; + +} // namespace AllMessageTypes diff --git a/src/MessageParser.cpp b/src/MessageParser.cpp index d756549295a1750a7a45cc0c3d628a50af055a97..7ce06c23b64058b079a73eb0bf449462cd471b82 100644 --- a/src/MessageParser.cpp +++ b/src/MessageParser.cpp @@ -74,6 +74,12 @@ void MessageParser::execute(Message& message) { break; #endif +#ifdef SERVICE_REALTIMEFORWARDINGCONTROL + case RealTimeForwardingControlService::ServiceType: + Services.realTimeForwarding.execute(message); + break; +#endif + default: ErrorHandler::reportInternalError(ErrorHandler::OtherMessageType); } diff --git a/src/Services/RealTimeForwardingControlService.cpp b/src/Services/RealTimeForwardingControlService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..315bfbe3e4dd11b979f95a240e90e8c75a813841 --- /dev/null +++ b/src/Services/RealTimeForwardingControlService.cpp @@ -0,0 +1,157 @@ +#include "Services/RealTimeForwardingControlService.hpp" +#include <iostream> + +void RealTimeForwardingControlService::addAllReportsOfApplication(uint8_t applicationID) { + for (auto& service: AllMessageTypes::messagesOfService) { + uint8_t serviceType = service.first; + addAllReportsOfService(applicationID, serviceType); + } +} + +void RealTimeForwardingControlService::addAllReportsOfService(uint8_t applicationID, uint8_t serviceType) { + for (auto& messageType: AllMessageTypes::messagesOfService[serviceType]) { + auto appServicePair = std::make_pair(applicationID, serviceType); + applicationProcessConfiguration.definitions[appServicePair].push_back(messageType); + } +} + +uint8_t RealTimeForwardingControlService::countServicesOfApplication(uint8_t applicationID) { + uint8_t serviceCounter = 0; + for (auto& definition: applicationProcessConfiguration.definitions) { + auto& pair = definition.first; + if (pair.first == applicationID) { + serviceCounter++; + } + } + return serviceCounter; +} + +uint8_t RealTimeForwardingControlService::countReportsOfService(uint8_t applicationID, uint8_t serviceType) { + auto appServicePair = std::make_pair(applicationID, serviceType); + return applicationProcessConfiguration.definitions[appServicePair].size(); +} + +bool RealTimeForwardingControlService::checkAppControlled(Message& request, uint8_t applicationId) { + if (std::find(controlledApplications.begin(), controlledApplications.end(), applicationId) == + controlledApplications.end()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::NotControlledApplication); + return false; + } + return true; +} + +bool RealTimeForwardingControlService::checkApplicationOfAppProcessConfig(Message& request, uint8_t applicationID, + uint8_t numOfServices) { + if (not checkAppControlled(request, applicationID) or allServiceTypesAllowed(request, applicationID)) { + for (uint8_t i = 0; i < numOfServices; i++) { + request.skipBytes(1); + uint8_t numOfMessages = request.readUint8(); + request.skipBytes(numOfMessages); + } + return false; + } + return true; +} + +bool RealTimeForwardingControlService::allServiceTypesAllowed(Message& request, uint8_t applicationID) { + if (countServicesOfApplication(applicationID) >= ECSSMaxServiceTypeDefinitions) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::AllServiceTypesAlreadyAllowed); + return true; + } + return false; +} + +bool RealTimeForwardingControlService::maxServiceTypesReached(Message& request, uint8_t applicationID) { + if (countServicesOfApplication(applicationID) >= ECSSMaxServiceTypeDefinitions) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::MaxServiceTypesReached); + return true; + } + return false; +} + +bool RealTimeForwardingControlService::checkService(Message& request, uint8_t applicationID, uint8_t numOfMessages) { + if (maxServiceTypesReached(request, applicationID)) { + request.skipBytes(numOfMessages); + return false; + } + return true; +} + +bool RealTimeForwardingControlService::maxReportTypesReached(Message& request, uint8_t applicationID, + uint8_t serviceType) { + if (countReportsOfService(applicationID, serviceType) >= AllMessageTypes::messagesOfService[serviceType].size()) { + ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::MaxReportTypesReached); + return true; + } + return false; +} + +bool RealTimeForwardingControlService::checkMessage(Message& request, uint8_t applicationID, uint8_t serviceType, + uint8_t messageType) { + if (maxReportTypesReached(request, applicationID, serviceType) or + reportExistsInAppProcessConfiguration(applicationID, serviceType, messageType)) { + return false; + } + return true; +} + +bool RealTimeForwardingControlService::reportExistsInAppProcessConfiguration(uint8_t applicationID, uint8_t serviceType, + uint8_t messageType) { + auto key = std::make_pair(applicationID, serviceType); + auto& messages = applicationProcessConfiguration.definitions[key]; + return std::find(messages.begin(), messages.end(), messageType) != messages.end(); +} + +void RealTimeForwardingControlService::addReportTypesToAppProcessConfiguration(Message& request) { + request.assertTC(ServiceType, MessageType::AddReportTypesToAppProcessConfiguration); + uint8_t numOfApplications = request.readUint8(); + + for (uint8_t i = 0; i < numOfApplications; i++) { + uint8_t applicationID = request.readUint8(); + uint8_t numOfServices = request.readUint8(); + + if (not checkApplicationOfAppProcessConfig(request, applicationID, numOfServices)) { + continue; + } + + if (numOfServices == 0) { + addAllReportsOfApplication(applicationID); + continue; + } + + for (uint8_t j = 0; j < numOfServices; j++) { + uint8_t serviceType = request.readUint8(); + uint8_t numOfMessages = request.readUint8(); + + if (not checkService(request, applicationID, numOfMessages)) { + continue; + } + + if (numOfMessages == 0) { + addAllReportsOfService(applicationID, serviceType); + continue; + } + + for (uint8_t k = 0; k < numOfMessages; k++) { + uint8_t messageType = request.readUint8(); + + if (not checkMessage(request, applicationID, serviceType, messageType)) { + continue; + } + auto key = std::make_pair(applicationID, serviceType); + applicationProcessConfiguration.definitions[key].push_back( + messageType); + } + } + } +} + +void RealTimeForwardingControlService::execute(Message& message) { + switch (message.messageType) { + case AddReportTypesToAppProcessConfiguration: + addReportTypesToAppProcessConfiguration(message); + break; + default: + ErrorHandler::reportInternalError(ErrorHandler::OtherMessageType); + } +} diff --git a/test/Services/HousekeepingService.cpp b/test/Services/HousekeepingService.cpp index 459ec7528c0c502c1e7124a242ac2b0e9cedaa2b..c4fec918d3564e717b230f50fe7679b97280f655 100644 --- a/test/Services/HousekeepingService.cpp +++ b/test/Services/HousekeepingService.cpp @@ -1,8 +1,8 @@ +#include "Services/HousekeepingService.hpp" #include <iostream> -#include "catch2/catch.hpp" #include "Message.hpp" #include "ServiceTests.hpp" -#include "Services/HousekeepingService.hpp" +#include "catch2/catch.hpp" #include "etl/algorithm.h" HousekeepingService& housekeepingService = Services.housekeeping; @@ -18,7 +18,7 @@ void buildRequest(Message& request, uint8_t idToCreate) { request.appendUint8(idToCreate); request.appendUint32(interval); request.appendUint16(numOfSimplyCommutatedParams); - for (auto& id : simplyCommutatedIds) { + for (auto& id: simplyCommutatedIds) { request.appendUint16(id); } } @@ -39,11 +39,11 @@ void initializeHousekeepingStructures() { HousekeepingStructure structures[3]; int i = 0; - for (auto& newStructure : structures) { + for (auto& newStructure: structures) { newStructure.structureId = ids[i]; newStructure.collectionInterval = interval; newStructure.periodicGenerationActionStatus = false; - for (uint16_t parameterId : simplyCommutatedIds) { + for (uint16_t parameterId: simplyCommutatedIds) { newStructure.simplyCommutatedParameterIds.push_back(parameterId); } housekeepingService.housekeepingStructures.insert({ids[i], newStructure}); @@ -60,9 +60,6 @@ void initializeHousekeepingStructures() { * Helper function that stores samples into simply commutated parameters of different data type each. */ void storeSamplesToParameters(uint16_t id1, uint16_t id2, uint16_t id3) { - Message samples(HousekeepingService::ServiceType, - HousekeepingService::MessageType::ReportHousekeepingPeriodicProperties, Message::TM, 1); - static_cast<Parameter<uint16_t>&>(Services.parameterManagement.getParameter(id1)->get()).setValue(33); static_cast<Parameter<uint8_t>&>(Services.parameterManagement.getParameter(id2)->get()).setValue(77); static_cast<Parameter<uint32_t>&>(Services.parameterManagement.getParameter(id3)->get()).setValue(99); @@ -77,7 +74,7 @@ void appendNewParameters(Message& request, uint8_t idToAppend) { request.appendUint8(idToAppend); request.appendUint16(numOfSimplyCommutatedParams); - for (auto& id : simplyCommutatedIds) { + for (auto& id: simplyCommutatedIds) { request.appendUint16(id); } } @@ -94,7 +91,7 @@ TEST_CASE("Create housekeeping structure") { request.appendUint8(idToCreate); request.appendUint32(interval); request.appendUint16(numOfSimplyCommutatedParams); - for (auto& id : simplyCommutatedIds) { + for (auto& id: simplyCommutatedIds) { request.appendUint16(id); } @@ -146,11 +143,11 @@ TEST_CASE("Create housekeeping structure") { REQUIRE(housekeepingService.housekeepingStructures.size() == 0); - for (auto& structId : idsToCreate) { + for (auto& structId: idsToCreate) { request.appendUint8(structId); request.appendUint32(interval); request.appendUint16(numOfSimplyCommutatedParams); - for (auto& parameterId : simplyCommutatedIds) { + for (auto& parameterId: simplyCommutatedIds) { request.appendUint16(parameterId); } MessageParser::execute(request); @@ -176,7 +173,7 @@ TEST_CASE("Create housekeeping structure") { request.appendUint8(idToCreate); request.appendUint32(interval); request.appendUint16(numOfSimplyCommutatedParams); - for (auto& id : simplyCommutatedIds) { + for (auto& id: simplyCommutatedIds) { request.appendUint16(id); } @@ -188,7 +185,7 @@ TEST_CASE("Create housekeeping structure") { REQUIRE(newStruct.simplyCommutatedParameterIds.size() == 4); uint16_t existingParameterIds[4] = {8, 4, 5, 11}; - for (auto parameterId : newStruct.simplyCommutatedParameterIds) { + for (auto parameterId: newStruct.simplyCommutatedParameterIds) { CHECK(std::find(std::begin(existingParameterIds), std::end(existingParameterIds), parameterId) != std::end(existingParameterIds)); } @@ -214,7 +211,7 @@ TEST_CASE("Delete housekeeping structure") { uint8_t numOfStructs = 5; uint8_t ids[5] = {2, 3, 4, 7, 8}; request.appendUint8(numOfStructs); - for (auto& id : ids) { + for (auto& id: ids) { request.appendUint8(id); } @@ -260,7 +257,7 @@ TEST_CASE("Enable the periodic generation of housekeeping structures") { uint8_t numOfStructs = 5; uint8_t idsToEnable[5] = {1, 3, 4, 6, 7}; request2.appendUint8(numOfStructs); - for (auto& id : idsToEnable) { + for (auto& id: idsToEnable) { request2.appendUint8(id); } REQUIRE(not housekeepingService.housekeepingStructures[0].periodicGenerationActionStatus); @@ -288,7 +285,7 @@ TEST_CASE("Disable the periodic generation of housekeeping structures") { uint8_t numOfStructs = 4; uint8_t idsToDisable[4] = {0, 1, 4, 6}; request2.appendUint8(numOfStructs); - for (auto& id : idsToDisable) { + for (auto& id: idsToDisable) { request2.appendUint8(id); } housekeepingService.housekeepingStructures[0].periodicGenerationActionStatus = true; @@ -317,7 +314,7 @@ TEST_CASE("Reporting of housekeeping structures") { uint8_t numOfStructs = 3; uint8_t idsToReport[3] = {9, 4, 2}; request2.appendUint8(numOfStructs); - for (auto& id : idsToReport) { + for (auto& id: idsToReport) { request2.appendUint8(id); } MessageParser::execute(request2); @@ -431,7 +428,7 @@ TEST_CASE("One-shot housekeeping parameter report generation") { uint8_t numOfStructs = 5; uint8_t structIds[5] = {0, 4, 7, 8, 11}; request2.appendUint8(numOfStructs); - for (auto& id : structIds) { + for (auto& id: structIds) { request2.appendUint8(id); } MessageParser::execute(request2); @@ -520,7 +517,7 @@ TEST_CASE("Append parameters in housekeeping report structure") { uint16_t currentlyExistingParameters[] = {8, 4, 5, 9, 10, 11}; HousekeepingStructure structToCheck = housekeepingService.housekeepingStructures[structId]; REQUIRE(structToCheck.simplyCommutatedParameterIds.size() == 6); - for (auto& existingParameter : currentlyExistingParameters) { + for (auto& existingParameter: currentlyExistingParameters) { CHECK(std::find(std::begin(structToCheck.simplyCommutatedParameterIds), std::end(structToCheck.simplyCommutatedParameterIds), existingParameter) != std::end(structToCheck.simplyCommutatedParameterIds)); @@ -540,7 +537,7 @@ TEST_CASE("Append parameters in housekeeping report structure") { request.appendUint8(structId); request.appendUint16(numOfSimplyCommutatedParams); - for (auto& id : simplyCommutatedIds) { + for (auto& id: simplyCommutatedIds) { request.appendUint16(id); } REQUIRE(housekeepingService.housekeepingStructures.find(structId) != @@ -570,7 +567,7 @@ TEST_CASE("Modification of housekeeping structures' interval") { uint32_t intervals[4] = {12, 21, 32, 17}; request.appendUint8(numOfStructs); int i = 0; - for (auto& id : structIds) { + for (auto& id: structIds) { request.appendUint8(id); request.appendUint32(intervals[i++]); } @@ -595,7 +592,7 @@ TEST_CASE("Reporting of housekeeping structure periodic properties") { uint8_t numOfStructs = 6; uint8_t structIds[6] = {0, 4, 1, 6, 9, 10}; request.appendUint8(numOfStructs); - for (auto& id : structIds) { + for (auto& id: structIds) { request.appendUint8(id); } housekeepingService.housekeepingStructures[0].periodicGenerationActionStatus = true; @@ -609,16 +606,16 @@ TEST_CASE("Reporting of housekeeping structure periodic properties") { 3); Message report = ServiceTests::get(3); - CHECK(report.readUint8() == 3); // Number of valid ids - CHECK(report.readUint8() == 0); // Id - CHECK(report.readBoolean() == true); // Periodic status - CHECK(report.readUint32() == 7); // Interval - CHECK(report.readUint8() == 4); // Id + CHECK(report.readUint8() == 3); // Number of valid ids + CHECK(report.readUint8() == 0); // Id + CHECK(report.readBoolean() == true); // Periodic status + CHECK(report.readUint32() == 7); // Interval + CHECK(report.readUint8() == 4); // Id CHECK(report.readBoolean() == false); // Periodic status - CHECK(report.readUint32() == 24); // Interval - CHECK(report.readUint8() == 6); // Id + CHECK(report.readUint32() == 24); // Interval + CHECK(report.readUint8() == 6); // Id CHECK(report.readBoolean() == false); // Periodic status - CHECK(report.readUint32() == 13); // Interval + CHECK(report.readUint32() == 13); // Interval ServiceTests::reset(); Services.reset(); diff --git a/test/Services/RealTimeForwardingControl.cpp b/test/Services/RealTimeForwardingControl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3553697dff0d3748aa67c78e75631653435972b0 --- /dev/null +++ b/test/Services/RealTimeForwardingControl.cpp @@ -0,0 +1,553 @@ +#include <iostream> +#include "ECSS_Definitions.hpp" +#include "Message.hpp" +#include "ServiceTests.hpp" +#include "Services/RealTimeForwardingControlService.hpp" +#include "catch2/catch.hpp" + +RealTimeForwardingControlService& realTimeForwarding = Services.realTimeForwarding; + +uint8_t applications[] = {1}; +uint8_t services[] = {3, 5}; +uint8_t allServices[] = {1, 3, 4, 5, 6, 11, 13, 17, 19, 20}; +uint8_t redundantServices[] = {1, 3, 4, 5, 6, 11, 13, 17, 19, 20, 1, 3}; +uint8_t messages1[] = {HousekeepingService::MessageType::HousekeepingPeriodicPropertiesReport, + HousekeepingService::MessageType::DisablePeriodicHousekeepingParametersReport}; + +uint8_t messages2[] = {EventReportService::MessageType::InformativeEventReport, + EventReportService::MessageType::DisabledListEventReport}; + +void validReportTypes(Message& request) { + uint8_t numOfApplications = 1; + uint8_t numOfServicesPerApp = 2; + uint8_t numOfMessagesPerService = 2; + + request.appendUint8(numOfApplications); + + for (auto appID: applications) { + request.appendUint8(appID); + request.appendUint8(numOfServicesPerApp); + + for (uint8_t j = 0; j < numOfServicesPerApp; j++) { + uint8_t serviceType = services[j]; + request.appendUint8(serviceType); + request.appendUint8(numOfMessagesPerService); + uint8_t* messages = (j == 0) ? messages1 : messages2; + + for (uint8_t k = 0; k < numOfMessagesPerService; k++) { + request.appendUint8(messages[k]); + } + } + } +} + +void duplicateReportTypes(Message& request) { + uint8_t numOfApplications = 1; + uint8_t numOfServicesPerApp = 2; + uint8_t numOfMessagesPerService = 2; + + request.appendUint8(numOfApplications); + + for (auto appID: applications) { + request.appendUint8(appID); + request.appendUint8(numOfServicesPerApp); + + for (uint8_t j = 0; j < numOfServicesPerApp; j++) { + uint8_t serviceType = services[j]; + request.appendUint8(serviceType); + request.appendUint8(numOfMessagesPerService); + + for (uint8_t k = 0; k < numOfMessagesPerService; k++) { + request.appendUint8(messages1[0]); + } + } + } +} + +void validInvalidReportTypes(Message& request) { + uint8_t numOfApplications = 3; + uint8_t numOfMessagesPerService = 2; + + uint8_t applications2[] = {1, 2, 3}; + request.appendUint8(numOfApplications); + + for (uint8_t i = 0; i < numOfApplications; i++) { + request.appendUint8(applications2[i]); + uint8_t numOfServicesPerApp = (i == 0) ? 12 : 2; + uint8_t* servicesToPick = (i == 0) ? redundantServices : services; + request.appendUint8(numOfServicesPerApp); + + for (uint8_t j = 0; j < numOfServicesPerApp; j++) { + uint8_t serviceType = servicesToPick[j]; + request.appendUint8(serviceType); + request.appendUint8(numOfMessagesPerService); + uint8_t* messages = (j == 0) ? messages1 : messages2; + + for (uint8_t k = 0; k < numOfMessagesPerService; k++) { + request.appendUint8(messages[k]); + } + } + } +} + +void validAllReportsOfService(Message& request) { + uint8_t numOfApplications = 1; + uint8_t numOfServicesPerApp = 2; + uint8_t numOfMessagesPerService = 0; + + request.appendUint8(numOfApplications); + + for (auto appID: applications) { + request.appendUint8(appID); + request.appendUint8(numOfServicesPerApp); + + for (uint8_t j = 0; j < numOfServicesPerApp; j++) { + uint8_t serviceType = services[j]; + request.appendUint8(serviceType); + request.appendUint8(numOfMessagesPerService); + } + } +} + +void validInvalidAllReportsOfService(Message& request) { + uint8_t numOfApplications = 3; + uint8_t numOfMessagesPerService = 2; + + uint8_t applications2[] = {1, 2, 3}; + request.appendUint8(numOfApplications); + + for (uint8_t i = 0; i < numOfApplications; i++) { + request.appendUint8(applications2[i]); + uint8_t numOfServicesPerApp = (i == 0) ? 12 : 2; + uint8_t* servicesToPick = (i == 0) ? redundantServices : services; + request.appendUint8(numOfServicesPerApp); + + for (uint8_t j = 0; j < numOfServicesPerApp; j++) { + uint8_t serviceType = servicesToPick[j]; + request.appendUint8(serviceType); + uint8_t numOfMessages = (i < 2) ? 0 : numOfMessagesPerService; + request.appendUint8(numOfMessages); + if (i >= 2) { + uint8_t* messages = (j == 0) ? messages1 : messages2; + + for (uint8_t k = 0; k < numOfMessagesPerService; k++) { + request.appendUint8(messages[k]); + } + } + } + } +} + +void validAllReportsOfApp(Message& request) { + uint8_t numOfApplications = 1; + uint8_t numOfServicesPerApp = 0; + + request.appendUint8(numOfApplications); + + for (auto appID: applications) { + request.appendUint8(appID); + request.appendUint8(numOfServicesPerApp); + } +} + +void validInvalidAllReportsOfApp(Message& request) { + uint8_t numOfApplications = 3; + uint8_t numOfMessagesPerService = 2; + + uint8_t applications2[] = {1, 2, 3}; + request.appendUint8(numOfApplications); + + for (uint8_t i = 0; i < numOfApplications; i++) { + request.appendUint8(applications2[i]); + uint8_t numOfServicesPerApp = (i == 0 or i == 1) ? 0 : 2; + uint8_t* servicesToPick = (i == 0) ? redundantServices : services; + request.appendUint8(numOfServicesPerApp); + + if (i >= 2) { + for (uint8_t j = 0; j < numOfServicesPerApp; j++) { + uint8_t serviceType = servicesToPick[j]; + request.appendUint8(serviceType); + uint8_t numOfMessages = (i == 0 or i == 1) ? 0 : numOfMessagesPerService; + request.appendUint8(numOfMessages); + + uint8_t* messages = (j == 0) ? messages1 : messages2; + + for (uint8_t k = 0; k < numOfMessagesPerService; k++) { + request.appendUint8(messages[k]); + } + } + } + } +} + +void resetAppProcessConfiguration() { + realTimeForwarding.applicationProcessConfiguration.definitions.clear(); + REQUIRE(realTimeForwarding.applicationProcessConfiguration.definitions.empty()); +} + +TEST_CASE("Add report types to the Application Process Configuration") { + SECTION("Successful addition of report types to the Application Process Configuration") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + + uint8_t applicationID = 1; + realTimeForwarding.controlledApplications.push_back(applicationID); + validReportTypes(request); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions; + REQUIRE(applicationProcesses.size() == 2); + + for (auto appID: applications) { + for (uint8_t j = 0; j < 2; j++) { + uint8_t serviceType = services[j]; + auto appServicePair = std::make_pair(appID, serviceType); + REQUIRE(applicationProcesses.find(appServicePair) != applicationProcesses.end()); + REQUIRE(applicationProcesses[appServicePair].size() == 2); + uint8_t* messages = (j == 0) ? messages1 : messages2; + + for (uint8_t k = 0; k < 2; k++) { + REQUIRE(std::find(applicationProcesses[appServicePair].begin(), + applicationProcesses[appServicePair].end(), + messages[k]) != applicationProcesses[appServicePair].end()); + } + } + } + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Requested Application Process is not controlled by the service") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + + uint8_t applicationID = 1; + validReportTypes(request); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::NotControlledApplication) == 1); + REQUIRE(realTimeForwarding.applicationProcessConfiguration.definitions.empty()); + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("All service types already allowed") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + + uint8_t applicationID = 1; + realTimeForwarding.controlledApplications.push_back(applicationID); + validReportTypes(request); + + for (uint8_t i = 1; i < ECSSMaxServiceTypeDefinitions + 1; i++) { + realTimeForwarding.applicationProcessConfiguration.definitions[std::make_pair(applicationID, i)]; + } + CHECK(realTimeForwarding.applicationProcessConfiguration.definitions.size() == ECSSMaxServiceTypeDefinitions); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::AllServiceTypesAlreadyAllowed) == + 1); + REQUIRE(realTimeForwarding.applicationProcessConfiguration.definitions.size() == ECSSMaxServiceTypeDefinitions); + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Max service types already reached") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + + uint8_t applicationID = 1; + uint8_t serviceType1 = services[0]; // st03 + uint8_t serviceType2 = services[1]; // st05 + + realTimeForwarding.controlledApplications.push_back(applicationID); + validReportTypes(request); + + auto& applicationProcessConfig = realTimeForwarding.applicationProcessConfiguration.definitions; + + for (uint8_t i = 100; i < ECSSMaxServiceTypeDefinitions + 99; i++) { + applicationProcessConfig[std::make_pair(applicationID, i)]; + } + CHECK(applicationProcessConfig.size() == ECSSMaxServiceTypeDefinitions - 1); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::MaxServiceTypesReached) == 1); + REQUIRE(applicationProcessConfig.size() == ECSSMaxServiceTypeDefinitions); + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("All report types already allowed") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + + uint8_t applicationID = 1; + uint8_t serviceType = services[0]; // st03 + realTimeForwarding.controlledApplications.push_back(applicationID); + validReportTypes(request); + + for (auto message: AllMessageTypes::messagesOfService[serviceType]) { + realTimeForwarding.applicationProcessConfiguration.definitions[std::make_pair(applicationID, serviceType)] + .push_back(message); + } + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::MaxReportTypesReached) == + 2); + REQUIRE( + realTimeForwarding.applicationProcessConfiguration.definitions[std::make_pair(applicationID, serviceType)] + .size() == AllMessageTypes::messagesOfService[serviceType].size()); + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Max report types already reached") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + + uint8_t applicationID = 1; + uint8_t serviceType1 = services[0]; // st03 + uint8_t serviceType2 = services[1]; // st05 + + realTimeForwarding.controlledApplications.push_back(applicationID); + validReportTypes(request); + + auto& applicationProcessConfig = realTimeForwarding.applicationProcessConfiguration; + + auto appServicePair1 = std::make_pair(applicationID, serviceType1); + auto appServicePair2 = std::make_pair(applicationID, serviceType2); + REQUIRE(applicationProcessConfig.definitions[appServicePair1].empty()); + REQUIRE(applicationProcessConfig.definitions[appServicePair2].empty()); + + auto numOfMessages1 = AllMessageTypes::messagesOfService[serviceType1].size(); + auto numOfMessages2 = AllMessageTypes::messagesOfService[serviceType2].size(); + + for (uint8_t i = 0; i < numOfMessages1 - 1; i++) { + applicationProcessConfig.definitions[appServicePair1].push_back(i); + } + for (uint8_t i = 16; i < numOfMessages2 + 15; i++) { + applicationProcessConfig.definitions[appServicePair2].push_back(i); + } + REQUIRE(applicationProcessConfig.definitions[appServicePair1].size() == numOfMessages1 - 1); + REQUIRE(applicationProcessConfig.definitions[appServicePair2].size() == numOfMessages2 - 1); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 2); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::MaxReportTypesReached) == 2); + REQUIRE(applicationProcessConfig.definitions.size() == 2); + REQUIRE(applicationProcessConfig.definitions[appServicePair1].size() == numOfMessages1); + REQUIRE(applicationProcessConfig.definitions[appServicePair2].size() == numOfMessages2); + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Requested addition of duplicate report type definitions") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + + uint8_t applicationID = 1; + realTimeForwarding.controlledApplications.push_back(applicationID); + duplicateReportTypes(request); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions; + REQUIRE(applicationProcesses.size() == 2); + + for (auto appID: applications) { + for (auto& serviceType: services) { + auto appServicePair = std::make_pair(appID, serviceType); + REQUIRE(applicationProcesses.find(appServicePair) != applicationProcesses.end()); + REQUIRE(applicationProcesses[appServicePair].size() == 1); + REQUIRE(std::find(applicationProcesses[appServicePair].begin(), + applicationProcesses[appServicePair].end(), + messages1[0]) != applicationProcesses[appServicePair].end()); + } + } + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Valid and invalid application-related requests combined") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + uint8_t applicationID1 = 1; + uint8_t applicationID2 = 2; + uint8_t applicationID3 = 3; + realTimeForwarding.controlledApplications.push_back(applicationID1); + realTimeForwarding.controlledApplications.push_back(applicationID3); + validInvalidReportTypes(request); + + for (uint8_t i = 100; i < ECSSMaxServiceTypeDefinitions + 99; i++) { + realTimeForwarding.applicationProcessConfiguration.definitions[std::make_pair(applicationID3, i)]; + } + CHECK(realTimeForwarding.applicationProcessConfiguration.definitions.size() == + ECSSMaxServiceTypeDefinitions - 1); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 7); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::NotControlledApplication) == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::MaxServiceTypesReached) == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::MaxReportTypesReached) == 3); + + auto& definitions = realTimeForwarding.applicationProcessConfiguration.definitions; + REQUIRE(definitions.size() == 20); + for (auto serviceType: allServices) { + REQUIRE(definitions.find(std::make_pair(applicationID1, serviceType)) != definitions.end()); + } + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Valid addition of all report types of a specified service type") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + uint8_t applicationID1 = 1; + realTimeForwarding.controlledApplications.push_back(applicationID1); + validAllReportsOfService(request); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& applicationProcesses = realTimeForwarding.applicationProcessConfiguration.definitions; + for (auto serviceType: services) { + REQUIRE(applicationProcesses[std::make_pair(applicationID1, serviceType)].size() == + AllMessageTypes::messagesOfService[serviceType].size()); + } + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Addition of all report types of a service type, combined with invalid requests") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + uint8_t applicationID1 = 1; + uint8_t applicationID2 = 2; + realTimeForwarding.controlledApplications.push_back(applicationID1); + realTimeForwarding.controlledApplications.push_back(applicationID2); + validInvalidAllReportsOfService(request); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 3); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::NotControlledApplication) == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::MaxServiceTypesReached) == 2); + + auto& definitions = realTimeForwarding.applicationProcessConfiguration.definitions; + REQUIRE(definitions.size() == 12); + + int cnt1 = 0; + int cnt2 = 0; + for (auto& pair: definitions) { + if (pair.first.first == applicationID1) { + cnt1++; + } else if (pair.first.first == applicationID2) { + cnt2++; + } + } + REQUIRE(cnt1 == 10); + REQUIRE(cnt2 == 2); + + for (auto& serviceType: allServices) { + REQUIRE(definitions[std::make_pair(applicationID1, serviceType)].size() == + AllMessageTypes::messagesOfService[serviceType].size()); + } + for (auto& serviceType: services) { + REQUIRE(definitions[std::make_pair(applicationID2, serviceType)].size() == + AllMessageTypes::messagesOfService[serviceType].size()); + } + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Valid addition of all report types of an application process") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + uint8_t applicationID1 = 1; + realTimeForwarding.controlledApplications.push_back(applicationID1); + validAllReportsOfApp(request); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 0); + auto& definitions = realTimeForwarding.applicationProcessConfiguration.definitions; + REQUIRE(definitions.size() == ECSSMaxServiceTypeDefinitions); + + for (auto serviceType: allServices) { + REQUIRE(std::equal(definitions[std::make_pair(applicationID1, serviceType)].begin(), + definitions[std::make_pair(applicationID1, serviceType)].end(), + AllMessageTypes::messagesOfService[serviceType].begin())); + } + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } + + SECTION("Addition of all report types of an application process, combined with invalid request") { + Message request(RealTimeForwardingControlService::ServiceType, + RealTimeForwardingControlService::MessageType::AddReportTypesToAppProcessConfiguration, + Message::TC, 1); + uint8_t applicationID1 = 1; + uint8_t applicationID2 = 2; + realTimeForwarding.controlledApplications.push_back(applicationID1); + realTimeForwarding.controlledApplications.push_back(applicationID2); + validInvalidAllReportsOfApp(request); + + MessageParser::execute(request); + + CHECK(ServiceTests::count() == 1); + CHECK(ServiceTests::countThrownErrors(ErrorHandler::ExecutionStartErrorType::NotControlledApplication) == 1); + auto& definitions = realTimeForwarding.applicationProcessConfiguration.definitions; + + REQUIRE(definitions.size() == 2 * ECSSMaxServiceTypeDefinitions); + + resetAppProcessConfiguration(); + ServiceTests::reset(); + Services.reset(); + } +}