diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2ba3de72d540afb9266a558792676bd60953e005..0b046fbdf84bdb2de8dcf8f30a35096a515b4f73 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,6 +30,7 @@ add_library(common OBJECT
         src/Services/TimeManagementService.cpp
         src/Services/TimeBasedSchedulingService.cpp
     	src/Services/EventActionService.cpp
+        src/Services/FunctionManagementService.cpp
         )
 
 # Specify the .cpp files for the executables
diff --git a/inc/ErrorHandler.hpp b/inc/ErrorHandler.hpp
index a378b93badfc49086ce15de24f415e575a68e3ac..4f50837588ce77417bc2818c2093b675a9bfd267 100644
--- a/inc/ErrorHandler.hpp
+++ b/inc/ErrorHandler.hpp
@@ -69,7 +69,11 @@ public:
 		/**
 		 * A function received a Message that was not of the correct type
 		 */
-		    OtherMessageType = 9,
+			OtherMessageType = 9,
+		/**
+		 * Attempt to insert new function in a full function map (ST[08])
+		 */
+			FunctionMapFull = 10,
 	};
 
 	/**
diff --git a/inc/Helpers/CRCHelper.hpp b/inc/Helpers/CRCHelper.hpp
index 12da516b2d6718d6743b17779c2fcf01dec178cd..aa7149846b762498ac4e13979afbbe215119b3bd 100644
--- a/inc/Helpers/CRCHelper.hpp
+++ b/inc/Helpers/CRCHelper.hpp
@@ -6,7 +6,7 @@
 class CRCHelper {
 
 	/**
-	 * CRC32 calculation helper class
+	 * CRC16 calculation helper class
 	 * This class declares a function which calculates the CRC16 checksum of the given data.
 	 *
 	 * For now the actual implementation is the CRC16/CCITT variant (ECSS-E-ST-70-41C, pg.615)
@@ -25,7 +25,7 @@ public:
 	 * Actual CRC calculation function.
 	 * @param  message (pointer to the data to be checksummed)
 	 * @param  length (size in bytes)
-	 * @return the CRC32 checksum of the input data
+	 * @return the CRC16 checksum of the input data
 	 */
 	static uint16_t calculateCRC(const uint8_t* message, uint32_t length);
 
diff --git a/inc/ServicePool.hpp b/inc/ServicePool.hpp
index 8a1e6035855eea8b35003ff37047ac4bb1b01f06..d928606dea82a53552f14b999559f9b6b9bb61f6 100644
--- a/inc/ServicePool.hpp
+++ b/inc/ServicePool.hpp
@@ -8,6 +8,7 @@
 #include "Services/ParameterService.hpp"
 #include "Services/TestService.hpp"
 #include "Services/MemoryManagementService.hpp"
+#include "Services/FunctionManagementService.hpp"
 
 /**
  * Defines a class that contains instances of all Services.
@@ -25,6 +26,7 @@ public:
 	EventActionService eventAction;
 	TestService testService;
 	ParameterService parameterManagement;
+	FunctionManagementService functionManagement;
 
 	/**
 	 * The default ServicePool constructor
diff --git a/inc/Services/FunctionManagementService.hpp b/inc/Services/FunctionManagementService.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2267f7ea112afabefbb97adce73d4844ad40a883
--- /dev/null
+++ b/inc/Services/FunctionManagementService.hpp
@@ -0,0 +1,95 @@
+#ifndef ECSS_SERVICES_FUNCTIONMANAGEMENTSERVICE_HPP
+#define ECSS_SERVICES_FUNCTIONMANAGEMENTSERVICE_HPP
+
+#include "etl/map.h"
+#include "etl/String.hpp"
+#include "Message.hpp"
+#include "Service.hpp"
+#include "ErrorHandler.hpp"
+
+#define FUNC_MAP_SIZE     5     // size of the function map (number of elements)
+#define FUNC_NAME_LENGTH  32      // max length of the function name
+#define MAX_ARG_LENGTH    32      // maximum argument byte string length
+
+/**
+ * Implementation of the ST[08] function management service
+ *
+ * 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.
+ *
+ * Caveats:
+ * 1) Function names shall be exactly MAXFUNCNAMELENGTH-lengthed in order to be properly read
+ * and stored!  (not sure if this is a caveat though, as ECSS-E-ST-70-41C stipulates for ST[08]
+ * that all function names must be fixed-length character strings)
+ *
+ * You have been warned.
+ *
+ * @author Grigoris Pavlakis <grigpavl@ece.auth.gr>
+ */
+
+ /**
+ * Usage of the include() function:
+ *
+ * @code
+ * void foo(String<MAX_ARG_LENGTH> b) {
+ * 		std::cout << "SPAAAACE!" << std::endl;
+ * 	}
+ *
+ * void bar(String<MAX_ARG_LENGTH> b) {
+ * 		std::cout << "I HAZ A CUBESAT THAT SNAPS PIX!" << std::endl;
+ * 	}
+ *
+ * void baz(String<MAX_ARG_LENGTH> b) {
+ * 		std::cout << "QWERTYUIOP" << std::endl;
+ * 	}
+ *
+ * 	FunctionManagementService::FunctionManagementService() {
+ * 		include(String<FUNC_NAME_LENGTH>("foo"), &foo);
+ * 		include(String<FUNC_NAME_LENGTH>("bar"), &bar);
+ * 		include(String<FUNC_NAME_LENGTH>("baz"), &baz);
+ * 	}
+ */
+
+typedef String<FUNC_NAME_LENGTH> functionName;
+typedef etl::map<functionName, void(*)(String<MAX_ARG_LENGTH>), FUNC_MAP_SIZE>
+FunctionMap;
+
+class FunctionManagementService : public Service {
+	/**
+	 * Map of the function names to their respective pointers. Size controlled by FUNC_MAP_SIZE
+	 */
+	FunctionMap funcPtrIndex;
+
+
+public:
+	/**
+	 * Constructs the function pointer index with all the necessary functions at initialization time
+	 * These functions need to be in scope. Un-default when needed.
+	 *
+	 * @param None
+	 */
+	FunctionManagementService() = default;
+
+	/**
+	 * Calls the function described in the TC[8,1] message *msg*, passing the arguments contained
+	 * and, if non-existent, generates a failed start of execution notification. Returns an unneeded
+	 * int, for testing purposes.
+	 * @param msg A TC[8,1] message
+	 */
+	void call(Message& msg);
+
+	/**
+	 * Includes a new function in the pointer map. This enables it to be called by way of a valid
+	 * TC [8,1] message.
+	 *
+	 * @param funcName the function's name. Max. length is FUNC_NAME_LENGTH bytes.
+	 * @param ptr pointer to a function of void return type and a MAX_ARG_LENGTH-lengthed byte
+	 * string as argument (which contains the actual arguments of the function)
+	 */
+	void include(String<FUNC_NAME_LENGTH> funcName, void(*ptr)(String<MAX_ARG_LENGTH>));
+
+	int getMapSize() { return funcPtrIndex.size(); }
+};
+
+#endif //ECSS_SERVICES_FUNCTIONMANAGEMENTSERVICE_HPP
diff --git a/inc/etl/String.hpp b/inc/etl/String.hpp
index 8fbd401cc4eb033cce095feb13d4fa577aa7d013..f9198df199888453fa690067020528ce9c2d1a36 100644
--- a/inc/etl/String.hpp
+++ b/inc/etl/String.hpp
@@ -1,7 +1,6 @@
 #ifndef ECSS_SERVICES_ETL_STRING_HPP
 #define ECSS_SERVICES_ETL_STRING_HPP
 
-
 #include <cstddef>
 #include <etl/cstring.h>
 
diff --git a/src/Services/FunctionManagementService.cpp b/src/Services/FunctionManagementService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8dcc602792b45199d17bf95e53330905ebcfaab0
--- /dev/null
+++ b/src/Services/FunctionManagementService.cpp
@@ -0,0 +1,52 @@
+#include "Services/FunctionManagementService.hpp"
+
+void FunctionManagementService::call(Message& msg) {
+	msg.resetRead();
+	ErrorHandler::assertRequest(msg.packetType == Message::TC, msg,
+	                            ErrorHandler::AcceptanceErrorType::UnacceptableMessage);
+	ErrorHandler::assertRequest(msg.messageType == 1, msg,
+	                            ErrorHandler::AcceptanceErrorType::UnacceptableMessage);
+	ErrorHandler::assertRequest(msg.serviceType == 8, msg,
+	                            ErrorHandler::AcceptanceErrorType::UnacceptableMessage);
+
+	uint8_t funcName[FUNC_NAME_LENGTH];  // the function's name
+	uint8_t funcArgs[MAX_ARG_LENGTH];    // arguments for the function
+
+	msg.readString(funcName, FUNC_NAME_LENGTH);
+	msg.readString(funcArgs, MAX_ARG_LENGTH);
+
+	if (msg.dataSize > FUNC_NAME_LENGTH + MAX_ARG_LENGTH) {
+		ErrorHandler::reportError(msg,
+			ErrorHandler::ExecutionStartErrorType::UnknownExecutionStartError);  // report failed
+			// start of execution as requested by the standard
+			return;
+	}
+
+	// locate the appropriate function pointer
+	String<FUNC_NAME_LENGTH> name(funcName);
+	FunctionMap::iterator iter = funcPtrIndex.find(name);
+	void (*selected)(String<MAX_ARG_LENGTH>);
+
+	if (iter != funcPtrIndex.end()) {
+		selected = *iter->second;
+	} else {
+		ErrorHandler::reportError(msg,
+			ErrorHandler::ExecutionStartErrorType::UnknownExecutionStartError);
+		return;
+	}
+
+	// execute the function if there are no obvious flaws (defined in the standard, pg.158)
+	selected(funcArgs);
+}
+
+void FunctionManagementService::include(String<FUNC_NAME_LENGTH> funcName, void(*ptr)
+	(String<MAX_ARG_LENGTH>)) {
+
+	if (not funcPtrIndex.full()) {  // CAUTION: etl::map won't check by itself if it's full
+		// before attempting to insert a key-value pair, causing segmentation faults. Check first!
+		funcName.append(FUNC_NAME_LENGTH - funcName.length(), '\0');
+		funcPtrIndex.insert(std::make_pair(funcName, ptr));
+	} else {
+		ErrorHandler::reportInternalError(ErrorHandler::InternalErrorType::FunctionMapFull);
+	}
+}
diff --git a/src/main.cpp b/src/main.cpp
index 407e7a534a2df58096cfcac170a62a97da95ad64..6067a82a5459d2c2137f0b8702484c7ece768791 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,6 +7,7 @@
 #include "Services/RequestVerificationService.hpp"
 #include "Services/MemoryManagementService.hpp"
 #include "Services/EventReportService.hpp"
+#include "Services/FunctionManagementService.hpp"
 #include "Services/TimeManagementService.hpp"
 #include "Services/EventActionService.hpp"
 #include "Services/TimeBasedSchedulingService.hpp"
diff --git a/test/Services/FunctionManagementService.cpp b/test/Services/FunctionManagementService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1cd99bf509a995fd08ce849965d0cd6d3f28a83c
--- /dev/null
+++ b/test/Services/FunctionManagementService.cpp
@@ -0,0 +1,52 @@
+#include "catch2/catch.hpp"
+#include "Services/FunctionManagementService.hpp"
+#include "ServicePool.hpp"
+#include "ServiceTests.hpp"
+#include <iostream>
+
+FunctionManagementService & fms = Services.functionManagement;
+
+void test(String<MAX_ARG_LENGTH> a) {
+	std::cout << a.c_str() << std::endl;
+}
+
+TEST_CASE("ST[08] - Call Tests") {
+
+	SECTION("Malformed name") {
+		ServiceTests::reset();
+		fms.include(String<FUNC_NAME_LENGTH>("test"), &test);
+		Message msg(8, 1, Message::TC, 1);
+		msg.appendString(String<FUNC_NAME_LENGTH>("t3st"));
+		fms.call(msg);
+		CHECK(ServiceTests::get(0).messageType == 4);
+		CHECK(ServiceTests::get(0).serviceType == 1);
+	}
+
+	SECTION("Too long message") {
+		ServiceTests::reset();
+		fms.include(String<FUNC_NAME_LENGTH>("test"), &test);
+		Message msg(8, 1, Message::TC, 1);
+		msg.appendString(String<FUNC_NAME_LENGTH>("test"));
+		msg.appendString(String<65>
+		    ("eqrhjweghjhwqgthjkrghthjkdsfhgsdfhjsdjsfdhgkjdfsghfjdgkdfsgdfgsgd"));
+		fms.call(msg);
+		CHECK(ServiceTests::get(0).messageType == 4);
+		CHECK(ServiceTests::get(0).serviceType == 1);
+	}
+}
+
+
+TEST_CASE("ST[08] - Insert Tests") {
+
+	SECTION("Insertion to full pointer map") {
+		// make sure the pointer map is full to the brim
+		ServiceTests::reset();
+		std::string name = "test";  // FOR TESTING ONLY!
+
+		for (int i = 0; i < FUNC_MAP_SIZE + 1; i++) {
+			name += std::to_string(i); // different names to fill up the map
+			fms.include(String<FUNC_NAME_LENGTH>(name.c_str()), &test);
+		}
+		CHECK(ServiceTests::thrownError(ErrorHandler::InternalErrorType::FunctionMapFull));
+	}
+}