From d139a1a7f435869fb7906083693a198b5a934ba3 Mon Sep 17 00:00:00 2001 From: kongr45gpen <electrovesta@gmail.com> Date: Thu, 20 Dec 2018 19:35:34 +0000 Subject: [PATCH] TC parser --- inc/ErrorHandler.hpp | 9 +++++++ inc/MessageParser.hpp | 49 +++++++++++++++++++++++++----------- src/MessageParser.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++ test/MessageParser.cpp | 20 +++++++++++++-- 4 files changed, 118 insertions(+), 17 deletions(-) diff --git a/inc/ErrorHandler.hpp b/inc/ErrorHandler.hpp index b18ae744..21710efa 100644 --- a/inc/ErrorHandler.hpp +++ b/inc/ErrorHandler.hpp @@ -50,6 +50,11 @@ public: * A string is larger than the largest allowed string */ StringTooLarge = 4, + + /** + * An error in the header of a packet makes it unable to be parsed + */ + UnacceptablePacket = 5, }; /** @@ -72,6 +77,10 @@ public: * Cannot read a string, because it is larger than the largest allowed string */ StringTooShort = 4, + /** + * Cannot parse a Message, because there is an error in its secondary header + */ + UnacceptableMessage = 5, }; /** diff --git a/inc/MessageParser.hpp b/inc/MessageParser.hpp index ca2fd599..0af0afbf 100644 --- a/inc/MessageParser.hpp +++ b/inc/MessageParser.hpp @@ -1,34 +1,53 @@ #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 +#include "Message.hpp" /** * 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 - */ + /** + * It is responsible to call the suitable function that executes the proper service. The way that + * the services are selected is based on the serviceType of the \p 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); + + /** + * Parse a message that contains the CCSDS and ECSS packet headers, as well as the data + * + * As defined in CCSDS 133.0-B-1 + * + * @param data The data of the message (not null-terminated) + * @param length The size of the message + * @return A new object that represents the parsed message + */ + Message parse(uint8_t * data, uint32_t length); + +private: + /** + * Parse the ECSS Telecommand packet secondary header + * + * As specified in section 7.4.4.1 of the standard + * + * @todo Implement the acknowledgement flags + * @todo Store and parse the source ID, if needed + * + * @param data The data of the header (not null-terminated) + * @param length The size of the header + * @param message The Message to modify based on the header + */ + void parseTC(uint8_t *data, uint16_t length, Message &message); }; diff --git a/src/MessageParser.cpp b/src/MessageParser.cpp index 83326eba..fe2426e5 100644 --- a/src/MessageParser.cpp +++ b/src/MessageParser.cpp @@ -1,4 +1,9 @@ +#include <cstring> +#include "ErrorHandler.hpp" #include "MessageParser.hpp" +#include "macros.hpp" +#include "Services/TestService.hpp" +#include "Services/RequestVerificationService.hpp" TestService TestService::instance; RequestVerificationService RequestVerificationService::instance; @@ -17,3 +22,55 @@ void MessageParser::execute(Message &message) { break; } } + +Message MessageParser::parse(uint8_t *data, uint32_t length) { + assertI(length >= 6, ErrorHandler::UnacceptablePacket); + + uint16_t packetHeaderIdentification = (data[0] << 8) | data[1]; + uint16_t packetSequenceControl = (data[2] << 8) | data[3]; + uint16_t packetDataLength = (data[4] << 8) | data[5]; + + // Individual fields of the CCSDS Space Packet primary header + uint8_t versionNumber = data[0] >> 5; + Message::PacketType packetType = ((data[0] & 0x10) == 0) ? Message::TM : Message::TC; + uint8_t secondaryHeaderFlag = data[0] & static_cast<uint8_t>(0x08); + uint16_t APID = packetHeaderIdentification & static_cast<uint16_t>(0x07ff); + auto sequenceFlags = static_cast<uint8_t>(packetSequenceControl >> 14); + + // Returning an internal error, since the Message is not available yet + assertI(versionNumber == 0, ErrorHandler::UnacceptablePacket); + assertI(secondaryHeaderFlag == 1, ErrorHandler::UnacceptablePacket); + assertI(sequenceFlags == 0x3, ErrorHandler::UnacceptablePacket); + assertI(packetDataLength == length - 6, ErrorHandler::UnacceptablePacket); + + Message message(0, 0, packetType, APID); + + if (packetType == Message::TC) { + parseTC(data + 6, packetDataLength, message); + } else { + assert(false); // Not implemented yet + } + + return message; +} + +void MessageParser::parseTC(uint8_t *data, uint16_t length, Message &message) { + ErrorHandler::assertRequest(length >= 5, message, ErrorHandler::UnacceptableMessage); + + // Individual fields of the TC header + uint8_t pusVersion = data[0] >> 4; + uint8_t serviceType = data[1]; + uint8_t messageType = data[2]; + + ErrorHandler::assertRequest(pusVersion == 2, message, ErrorHandler::UnacceptableMessage); + + // Remove the length of the header + length -= 5; + + // Copy the data to the message + // TODO: See if memcpy is needed for this + message.serviceType = serviceType; + message.messageType = messageType; + memcpy(message.data, data + 5, length); + message.dataSize = length; +} diff --git a/test/MessageParser.cpp b/test/MessageParser.cpp index 1d7436ec..25265d55 100644 --- a/test/MessageParser.cpp +++ b/test/MessageParser.cpp @@ -2,10 +2,11 @@ #include <Services/TestService.hpp> #include <Services/RequestVerificationService.hpp> #include <Message.hpp> +#include <cstring> #include "MessageParser.hpp" #include "Services/ServiceTests.hpp" -TEST_CASE("ST[01] message parsing", "[MessageParser][st01]") { +TEST_CASE("ST[01] message execution", "[MessageParser][st01]") { MessageParser messageParser; Message message = Message(1, 1, Message::TC, 2); @@ -44,7 +45,7 @@ TEST_CASE("ST[01] message parsing", "[MessageParser][st01]") { CHECK(response.packetType == Message::TM); } -TEST_CASE("ST[17] message parsing", "[MessageParser][st17]") { +TEST_CASE("ST[17] message execution", "[MessageParser][st17]") { MessageParser messageParser; Message message = Message(17, 1, Message::TC, 1); @@ -62,3 +63,18 @@ TEST_CASE("ST[17] message parsing", "[MessageParser][st17]") { CHECK(response.messageType == 4); CHECK(response.packetType == Message::TM); } + +TEST_CASE("TC message parsing", "[MessageParser]") { + MessageParser messageParser; + + uint8_t packet[] = {0x18, 0x07, 0xc0, 0x4d, 0x00, 0x0a, 0x20, 0x81, 0x1f, 0x00, 0x00, 0x68, + 0x65, 0x6c, 0x6c, 0x6f}; + + Message message = messageParser.parse(packet, 16); + CHECK(message.packetType == Message::TC); + CHECK(message.applicationId == 7); + CHECK(message.dataSize == 5); + CHECK(message.serviceType == 129); + CHECK(message.messageType == 31); + CHECK(memcmp(message.data, "hello", 5) == 0); +} -- GitLab