diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a2dcbd240bf332022c13ee82b8a4f3d5ecf1799..5b47f76be72a6f43473ff978f1ac24dfbbe9e245 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,19 +13,33 @@ add_custom_target(check COMMAND ./clang-tidy.sh WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/ci") +# Specify the .cpp files common across all targets +add_library(common OBJECT + src/Message.cpp + src/MessageParser.cpp + src/Services/MemoryManagementService.cpp + src/Services/ParameterService.cpp + src/Services/RequestVerificationService.cpp + src/Services/TestService.cpp + ) + # Specify the .cpp files for the executables -add_executable(ecss_services src/main.cpp src/Message.cpp src/Service.cpp - src/Services/TestService.cpp src/Services/RequestVerificationService.cpp - src/Services/MemoryManagementService.cpp src/Services/ParameterService.cpp) +add_executable(ecss_services + src/main.cpp + $<TARGET_OBJECTS:common> + src/Platform/x86/Service.cpp + ) IF (EXISTS "${PROJECT_SOURCE_DIR}/lib/Catch2/CMakeLists.txt") + # Gather all the .cpp files corresponding to tests + file(GLOB test_main_SRC "test/*.cpp") + file(GLOB test_SRC "test/**/*.cpp") + add_subdirectory(lib/Catch2) - add_executable(tests src/Message.cpp src/Services/TestService.cpp - src/Services/RequestVerificationService.cpp src/Services/ParameterService.cpp - src/Services/MemoryManagementService.cpp test/tests.cpp test/Message.cpp - test/TestPlatform.cpp test/Services/TestService.cpp - test/Services/RequestVerificationService.cpp test/Services/ParameterService.cpp - test/Services/MemoryManagementService.cpp) + add_executable(tests + $<TARGET_OBJECTS:common> + ${test_main_SRC} + ${test_SRC}) target_link_libraries(tests Catch2::Catch2) ENDIF () diff --git a/ci/.clang-tidy b/ci/.clang-tidy index 4ce5a961297d6a1ab3cb70979d18ef3ba15dead8..6114218612a520f187515cdc7631f09629fa8b84 100644 --- a/ci/.clang-tidy +++ b/ci/.clang-tidy @@ -17,7 +17,7 @@ Checks: > -misc-non-private-member-variables-in-classes, performance-*, readability-*, -WarningsAsErrors: '*,-misc-unused-parameters,-llvm-header-guard,-cppcoreguidelines-pro-type-member-init,-google-runtime-references,-clang-diagnostic-tautological-constant-out-of-range-compare' +WarningsAsErrors: '*,-misc-unused-parameters,-llvm-header-guard,-cppcoreguidelines-pro-type-member-init,-google-runtime-references,-clang-diagnostic-tautological-constant-out-of-range-compare,-readability-redundant-declaration' HeaderFilterRegex: '.*' AnalyzeTemporaryDtors: false ... diff --git a/inc/MessageParser.hpp b/inc/MessageParser.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ca2fd59970197af6b714b15f62cb71776f9b0c0f --- /dev/null +++ b/inc/MessageParser.hpp @@ -0,0 +1,35 @@ +#ifndef ECSS_SERVICES_MESSAGEPARSER_HPP +#define ECSS_SERVICES_MESSAGEPARSER_HPP + +// include all the header files for the services that have been implemented for the time being +#include "Services/TestService.hpp" +#include "Services/RequestVerificationService.hpp" +#include <iostream> // This file should be removed + +/** + * A generic class responsible for the execution of the incoming telemetry and telecommand + * packets. + * + * @todo Make the connection between the ST[01]-request verification service and the services + * that initiate it + * @todo Implement the execute function in the upcoming services or generally in the upcoming + * activities + * + */ + +class MessageParser { +public: + +/** + * It is responsible to call the suitable function that execute the proper service. The way that + * the services are selected is based on the serviceType(class member of Message) of the param + * message + * + * @todo The implementation of the execute function should correspond to the numbers of the + * services/activities that have been created + */ + void execute(Message &message); +}; + + +#endif //ECSS_SERVICES_MESSAGEPARSER_HPP diff --git a/inc/Service.hpp b/inc/Service.hpp index 3afd67fa73d6ce148555bd03ead9a8743666364c..0aab624de64f9196d2ddae82ce97d3cb0c738156 100644 --- a/inc/Service.hpp +++ b/inc/Service.hpp @@ -3,6 +3,7 @@ #include <cstdint> #include "Message.hpp" +#include <iostream> // This file should be removed /** * A spacecraft service, as defined in ECSS-E-ST-70-41C @@ -37,7 +38,13 @@ protected: * Note: For now, since we don't have any mechanisms to queue messages and send them later, * we just print the message to the screen */ - void storeMessage(const Message& message); + void storeMessage(const Message &message); + + /** + * This function declared only to remind us that every service must have a function like + * this, but this particular function does actually nothing. + */ + void execute(Message &message); }; diff --git a/inc/Services/RequestVerificationService.hpp b/inc/Services/RequestVerificationService.hpp index dcabc558f73e1be592e04a6bfb7e7975b5901533..9c1a86da8fec46969c9671c30e05e172cc95e423 100644 --- a/inc/Services/RequestVerificationService.hpp +++ b/inc/Services/RequestVerificationService.hpp @@ -71,7 +71,23 @@ public: */ void failRoutingVerification(Message &request); + /** + * It is responsible to call the suitable function that execute the proper subservice. The + * way that the subservices are selected is for the time being based on the messageType(class + * member of class Message) of the param message + * + * Note:The functions of this service takes dummy values as arguments for the time being + * + * @todo Error handling for the switch() in the implementation of this execute function + */ + void execute(Message &message); + /** + * The purpose of this instance is to access the execute function of this service when a + * MessageParser object is created + */ + static RequestVerificationService instance; }; + #endif //ECSS_SERVICES_REQUESTVERIFICATIONSERVICE_HPP diff --git a/inc/Services/TestService.hpp b/inc/Services/TestService.hpp index a3704aa16a0ca3b7d7a19c9d639983614f5d91fd..f06be9693ff82a88faa69ae2b4c1f86a5760a2cf 100644 --- a/inc/Services/TestService.hpp +++ b/inc/Services/TestService.hpp @@ -23,6 +23,21 @@ public: * @todo Only respond if we have the correct APID */ void onBoardConnection(Message &request); + + /** + * It is responsible to call the suitable function that execute the proper subservice. The + * way that the subservices are selected is for the time being based on the messageType(class + * member of class Message) of the param message + * + * @todo Error handling for the switch() in the implementation of this execute function + */ + void execute(Message &message); + + /** + * The purpose of this instance is to access the execute function of this service when a + * MessageParser object is created + */ + static TestService instance; }; diff --git a/src/Message.cpp b/src/Message.cpp index 60259a597339b14b686352bd67f4eb1ff8f1eb0d..997b617ba4035f5e8af9e40ad27715df94551db9 100644 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -20,7 +20,7 @@ void Message::appendBits(uint8_t numBits, uint16_t data) { this->data[dataSize] |= static_cast<uint8_t>(data >> (numBits - bitsToAddNow)); // Remove used bits - data &= (1 << bitsToAddNow) - 1; + data &= (1 << (numBits - bitsToAddNow)) - 1; numBits -= bitsToAddNow; currentBit = 0; diff --git a/src/MessageParser.cpp b/src/MessageParser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83326ebae59489de577e0ce6e2c3d974a74d4c99 --- /dev/null +++ b/src/MessageParser.cpp @@ -0,0 +1,19 @@ +#include "MessageParser.hpp" + +TestService TestService::instance; +RequestVerificationService RequestVerificationService::instance; + +void MessageParser::execute(Message &message) { + switch (message.serviceType) { + case 1: + RequestVerificationService::instance.execute(message); + break; + case 17: + TestService::instance.execute(message); + break; + default: + // cout is very bad for embedded systems + std::cout << "This service hasn't been implemented yet or it doesn't exist"; + break; + } +} diff --git a/src/Platform/README.md b/src/Platform/README.md new file mode 100644 index 0000000000000000000000000000000000000000..eb0a3ae39f9c1079d32ec6cd60298838564319a9 --- /dev/null +++ b/src/Platform/README.md @@ -0,0 +1,3 @@ +This folder contains platform-specific files: + +- **x86**: Files to be run on a PC with a proper operating system \ No newline at end of file diff --git a/src/Service.cpp b/src/Platform/x86/Service.cpp similarity index 100% rename from src/Service.cpp rename to src/Platform/x86/Service.cpp diff --git a/src/Services/RequestVerificationService.cpp b/src/Services/RequestVerificationService.cpp index 28cc34043ca0817a79e0fc68ab77d5c4492ecfb2..ba9779625acf079947e8542587b29d88a837a229 100644 --- a/src/Services/RequestVerificationService.cpp +++ b/src/Services/RequestVerificationService.cpp @@ -81,3 +81,28 @@ RequestVerificationService::failRoutingVerification(Message &request) { storeMessage(report); } + +void RequestVerificationService::execute(Message &message) { + switch (message.messageType) { + case 1: + successAcceptanceVerification(message); + break; + case 2: + failAcceptanceVerification(message); + break; + case 7: + successExecutionVerification(message); + break; + case 8: + failExecutionVerification(message); + break; + case 10: + failRoutingVerification(message); + break; + default: + // cout is very bad for embedded systems + std::cout << "Error: There is not such a message type in ST[01] service"; + assert(false); + break; + } +} diff --git a/src/Services/TestService.cpp b/src/Services/TestService.cpp index 670a8e2fe18cdf1403490b7393d7e7e9030b01d9..2584c75cb529826e3653a56cda8eb33d114933be 100644 --- a/src/Services/TestService.cpp +++ b/src/Services/TestService.cpp @@ -15,3 +15,19 @@ void TestService::onBoardConnection(Message &request) { // just print it on the screen storeMessage(report); } + +void TestService::execute(Message &message) { + switch (message.messageType) { + case 1: + areYouAlive(message); + break; + case 3: + onBoardConnection(message); + break; + default: + // cout is very bad for embedded systems + std::cout << "Error: There is not such a message type in ST[17] test"; + assert(false); + break; + } +} diff --git a/src/main.cpp b/src/main.cpp index 856da839e4350d42a629589e73329c45b3e14b41..8f4bf906c97b832f8a5e1d2bf8298160deed8521 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include "Services/RequestVerificationService.hpp" #include "Services/MemoryManagementService.hpp" #include "Message.hpp" +#include "MessageParser.hpp" #include "Services/MemoryManagementService.hpp" int main() { @@ -54,7 +55,7 @@ int main() { paramService.setParameterIds(sentPacket2); paramService.reportParameterIds(sentPacket); -// ST[06] testing + // ST[06] testing char anotherStr[8] = "Fgthred"; char yetAnotherStr[2] = "F"; char *pStr = static_cast<char *>(malloc(4)); @@ -106,5 +107,29 @@ int main() { receivedMessage = Message(1, 10, Message::TC, 3); reqVerifService.failRoutingVerification(receivedMessage); + + // MessageParser class test + std::cout << "\n"; + + // ST[17] test + Message message = Message(17, 1, Message::TC, 1); + MessageParser messageParser; + messageParser.execute(message); + message = Message(17, 3, Message::TC, 1); + message.appendUint16(7); + messageParser.execute(message); + + // ST[01] test + message = Message(1, 1, Message::TC, 3); + messageParser.execute(message); + message = Message(1, 2, Message::TC, 3); + messageParser.execute(message); + message = Message(1, 7, Message::TC, 3); + messageParser.execute(message); + message = Message(1, 8, Message::TC, 3); + messageParser.execute(message); + message = Message(1, 10, Message::TC, 3); + messageParser.execute(message); + return 0; } diff --git a/test/MessageParser.cpp b/test/MessageParser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d7436ecdf354ca37f2b7dd475d622c50bb6d03e --- /dev/null +++ b/test/MessageParser.cpp @@ -0,0 +1,64 @@ +#include <catch2/catch.hpp> +#include <Services/TestService.hpp> +#include <Services/RequestVerificationService.hpp> +#include <Message.hpp> +#include "MessageParser.hpp" +#include "Services/ServiceTests.hpp" + +TEST_CASE("ST[01] message parsing", "[MessageParser][st01]") { + MessageParser messageParser; + + Message message = Message(1, 1, Message::TC, 2); + messageParser.execute(message); + Message response = ServiceTests::get(0); + CHECK(response.serviceType == 1); + CHECK(response.messageType == 1); + CHECK(response.packetType == Message::TM); + + message = Message(1, 2, Message::TC, 2); + messageParser.execute(message); + response = ServiceTests::get(1); + CHECK(response.serviceType == 1); + CHECK(response.messageType == 2); + CHECK(response.packetType == Message::TM); + + message = Message(1, 7, Message::TC, 2); + messageParser.execute(message); + response = ServiceTests::get(2); + CHECK(response.serviceType == 1); + CHECK(response.messageType == 7); + CHECK(response.packetType == Message::TM); + + message = Message(1, 8, Message::TC, 2); + messageParser.execute(message); + response = ServiceTests::get(3); + CHECK(response.serviceType == 1); + CHECK(response.messageType == 8); + CHECK(response.packetType == Message::TM); + + message = Message(1, 10, Message::TC, 2); + messageParser.execute(message); + response = ServiceTests::get(4); + CHECK(response.serviceType == 1); + CHECK(response.messageType == 10); + CHECK(response.packetType == Message::TM); +} + +TEST_CASE("ST[17] message parsing", "[MessageParser][st17]") { + MessageParser messageParser; + + Message message = Message(17, 1, Message::TC, 1); + messageParser.execute(message); + Message response = ServiceTests::get(0); + CHECK(response.serviceType == 17); + CHECK(response.messageType == 2); + CHECK(response.packetType == Message::TM); + + message = Message(17, 3, Message::TC, 1); + message.appendUint16(7); + messageParser.execute(message); + response = ServiceTests::get(1); + CHECK(response.serviceType == 17); + CHECK(response.messageType == 4); + CHECK(response.packetType == Message::TM); +}