From a62f961028f0cca3b4d3637e942f686c4f7144db Mon Sep 17 00:00:00 2001
From: Grigoris Pavlakis <grigpavl@ece.auth.gr>
Date: Mon, 31 Dec 2018 17:18:33 +0200
Subject: [PATCH] Complete basic functionality (i.e. retrieval of function
 pointer and execution with arguments). Needs more testing and safeguarding
 against corrupted messages

---
 inc/Services/FunctionManagementService.hpp | 37 ++++++----
 src/Services/FunctionManagementService.cpp | 83 ++++++++++++++--------
 src/main.cpp                               |  8 +++
 3 files changed, 85 insertions(+), 43 deletions(-)

diff --git a/inc/Services/FunctionManagementService.hpp b/inc/Services/FunctionManagementService.hpp
index 49a69a0b..08f30c75 100644
--- a/inc/Services/FunctionManagementService.hpp
+++ b/inc/Services/FunctionManagementService.hpp
@@ -10,31 +10,42 @@
 #include "etl/String.hpp"
 #include "Message.hpp"
 
+#define FUNCMAPSIZE        128      // size of the function map in bytes (temporary, arbitrary)
+#define MAXFUNCNAMELENGTH  32      // max length of the function name (temporary, arbitrary)
+#define MAXARGLENGTH       32       // maximum argument byte string length
+
 /**
  * Implementation of the ST[08] function management service
  *
- * This class implements a basic framework for the ST[08] service as described in ECSS-E-ST-70-41C,
- * pages 157-159. Final implementation is dependent on subsystem requirements which are, as of this
- * writing, undefined yet.
- * *
+ * This class implements a skeleton framework for the ST[08] service as described in
+ * ECSS-E-ST-70-41C, pages 157-159. Final implementation is dependent on subsystem requirements
+ * which are, as of this writing, undefined yet.
+ *
+ * WARNING! Any string handling in this class involves non-null-terminated strings!
+ *
  * @author Grigoris Pavlakis <grigpavl@ece.auth.gr>
  */
 
-#define FUNCMAPSIZE     5        // size of the function map (temporary, arbitrary)
-#define MAXFUNCNAMELEN  128      // max length of the function (temporary, arbitrary)
-#define MAXFUNCARGS     64       // maximum arguments that a function can hold
-#define MAXARGLENGTH    32       // maximum argument name length
-
-typedef String<MAXFUNCNAMELEN> funcName;
+typedef String<MAXFUNCNAMELENGTH> functionName;
+typedef etl::map<functionName, void(*)(String<MAXARGLENGTH>), (const size_t) FUNCMAPSIZE>
+PointerMap;
 
 class FunctionManagementService {
-	etl::map<funcName, void*, (const size_t) FUNCMAPSIZE> funcPtrIndex;
-	// map of function names to their pointers
+	/**
+	 * Map of the function names to their respective pointers. Size controlled by FUNCMAPSIZE
+	 */
+	 PointerMap funcPtrIndex;
 
 public:
-	//FunctionManagementService(); // dummy constructor (commented out to pacify clang-tidy)
+	/**
+	 * Constructs the function pointer index. All functions to be included shall be visible to it.
+	 * @param None
+	 */
+	FunctionManagementService();
+
 	/**
 	 * Calls the function described in the TC[8,1] message *msg*, passing the arguments contained
+	 * WARNING: Do not include any spaces in the arguments, they are ignored and replaced with NULL
 	 * @param msg A TC[8,1] message
 	 */
 	void call(Message msg);
diff --git a/src/Services/FunctionManagementService.cpp b/src/Services/FunctionManagementService.cpp
index 2294539c..313ee6d8 100644
--- a/src/Services/FunctionManagementService.cpp
+++ b/src/Services/FunctionManagementService.cpp
@@ -1,49 +1,72 @@
 #include "Services/FunctionManagementService.hpp"
 
-// Dummy functions which will populate the map
-float dummy1(float a, int b) {
-	return a * b;
+// Dummy functions which will populate the map.
+// This one prints whatever bytes are contained in the argument.
+void dummy1(const String<MAXARGLENGTH> a) {
+	std::cout << a.c_str() << std::endl;
 }
 
-void dummy2(char c) {
-	std::cout << c << std::endl;
-}
 
-//FunctionManagementService::FunctionManagementService() {
-//	funcPtrIndex.insert(std::make_pair(String<MAXFUNCNAMELEN>("dummy1"), reinterpret_cast<void*>
-//	(&dummy1)));
-//	funcPtrIndex.insert(std::make_pair(String<MAXFUNCNAMELEN>("dummy2"), reinterpret_cast<void*>
-//	(&dummy2)));
-//
-//	//reinterpret_cast<float(*)(float, int)>(funcPtrIndex["dummy1"])(3.14, 45);
-//	//reinterpret_cast<void(*)(char)>(funcPtrIndex["dummy2"])('h');
-//}
+FunctionManagementService::FunctionManagementService() {
+	String<MAXFUNCNAMELENGTH> str("");
+	str.append("dummy1");
+	str.append(MAXFUNCNAMELENGTH - 6, '\0');
+	void(*dummyPtr)(String<MAXARGLENGTH>) = &dummy1;
+	funcPtrIndex.insert(std::make_pair(str, dummyPtr));
+}
 
 void FunctionManagementService::call(Message msg){
-	uint8_t funcName[MAXFUNCNAMELEN];  // the function's name
+	assert(msg.messageType == 1);
+	assert(msg.serviceType == 8);
+
+	uint8_t funcName[MAXFUNCNAMELENGTH];  // the function's name
+	uint8_t funcArgs[MAXARGLENGTH];    // arguments for the function
 
-	// initialize the function name array
-	for (int i = 0; i < MAXFUNCNAMELEN; i++) {
-		funcName[i] = 0;
+	// initialize the function name and the argument arrays
+	for (int i = 0; i < MAXFUNCNAMELENGTH; i++) {
+		funcName[i] = '\0';
+		funcArgs[i] = '\0';
 	}
 
 	// isolate the function's name from the incoming message
-	for (int i = 0; i < MAXFUNCNAMELEN; i++) {
+	for (int i = 0; i < MAXFUNCNAMELENGTH; i++) {
 		uint8_t currByte = msg.readByte();
-		if (currByte == 0x00) {
-			funcName[i] = currByte;
-			break;
+		if (currByte == 0x20) {
+			continue;
 		}
 		funcName[i] = currByte;
 	}
 
-	// isolate the number of args (currently an unsigned 32-bit number, the standard doesn't
-	// specify a maximum number)
-	uint32_t numOfArgs = msg.readUint32();
-	for (int i = 0; i < numOfArgs; i++) {
-		// TODO: find a way to deduce the argument types as contained or store them somehow
-		//  (finding a way to store them is better because it also solves the pointer casting
-		//  problem)
+	// isolate the string containing the args (if string length exceeds max, the remaining bytes
+	// are silently ignored)
+	for (int i = 0; i < MAXARGLENGTH; i++) {
+		uint8_t currByte = msg.readByte();
+		if (currByte == 0x20) {
+			continue;
+		}
+		funcArgs[i] = currByte;
+	}
+
+	// locate the appropriate function pointer
+	String<MAXFUNCNAMELENGTH> name(funcName);
+	PointerMap::iterator iter = funcPtrIndex.find(name);
+	void(*selected)(String<MAXARGLENGTH>) = nullptr;
+
+	if (iter == funcPtrIndex.end()) {
+		std::cout << "ERROR: Malformed query." << std::endl;
+	}
+	else {
+		selected = *iter->second;
+	}
+
+	// send proper exec failure notification and terminate if name is incorrect
+	if (selected == nullptr) {
+		/**
+		 * @todo Send failed start of execution
+		 */
+		return;
 	}
 
+	//  execute the function if there are no obvious flaws (defined in the standard, pg.158)
+	selected(funcArgs);
 }
diff --git a/src/main.cpp b/src/main.cpp
index 057c2313..37188eb7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -202,7 +202,15 @@ int main() {
 	eventReportService.requestListOfDisabledEvents(eventMessage3);
 
 	// ST[08] test
+	Message callMessage(8, 1, Message::TC, 1);
+	String<256> str = String<256>("");
+	str.append("dummy1");
+	str.append(MAXFUNCNAMELENGTH - 6, ' ');
+	str.append("THISSENTENCEISFALSE!");
+
+	callMessage.appendString<256>(str);
 	FunctionManagementService fms;
+	fms.call(callMessage);
 
 	return 0;
 }
-- 
GitLab