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