diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 5b44ac96da73d9acc2af3bb992aa3611e574d766..f25060c0a0ccdd77d361f71cffaeeb85e993991b 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -3,27 +3,8 @@
     <option name="RIGHT_MARGIN" value="100" />
     <option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
     <Objective-C-extensions>
-      <file>
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
-      </file>
-      <class>
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
-        <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
-      </class>
       <extensions>
-        <pair source="cpp" header="hpp" fileNamingConvention="NONE" />
+        <pair source="cpp" header="hpp" fileNamingConvention="PASCAL_CASE" />
         <pair source="c" header="h" fileNamingConvention="NONE" />
       </extensions>
     </Objective-C-extensions>
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 91d4361702769bdfe6326464a61298263c79e5e3..8d27e92289fda7a84ec8630f7524d1a11b9eb00a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -9,5 +9,8 @@
     <libraryRoots>
       <file path="$PROJECT_DIR$/lib" />
     </libraryRoots>
+    <excludeRoots>
+      <file path="$PROJECT_DIR$/docs" />
+    </excludeRoots>
   </component>
-</project>
\ No newline at end of file
+</project>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5b47f76be72a6f43473ff978f1ac24dfbbe9e245..d709806f9a52996a68922e321a364f40e032ff64 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,8 +15,11 @@ add_custom_target(check
 
 # Specify the .cpp files common across all targets
 add_library(common OBJECT
+        src/ErrorHandler.cpp
         src/Message.cpp
-        src/MessageParser.cpp
+	    src/MessageParser.cpp
+        src/Helpers/CRCHelper.cpp
+	    src/Services/EventReportService.cpp
         src/Services/MemoryManagementService.cpp
         src/Services/ParameterService.cpp
         src/Services/RequestVerificationService.cpp
diff --git a/inc/ECSS_Definitions.hpp b/inc/ECSS_Definitions.hpp
index 9bbcb5c1a433955104eb8f545a6dd713dd78228b..3a2eeedba9ebd9fd6e080c054e485a7936880ae5 100644
--- a/inc/ECSS_Definitions.hpp
+++ b/inc/ECSS_Definitions.hpp
@@ -12,4 +12,7 @@
 // 7.4.4.1c
 #define ECSS_PUS_VERSION 2
 
+// 9.3.1a.1.e
+#define ECSS_SEQUENCE_FLAGS 0x3
+
 #endif //ECSS_SERVICES_ECSS_DEFINITIONS_H
diff --git a/inc/ErrorHandler.hpp b/inc/ErrorHandler.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..56223cacaecfa11b03c0a12b0e3626d0d3d0b7c0
--- /dev/null
+++ b/inc/ErrorHandler.hpp
@@ -0,0 +1,157 @@
+#ifndef PROJECT_ERRORHANDLER_HPP
+#define PROJECT_ERRORHANDLER_HPP
+
+#include "Message.hpp"
+
+/**
+ * A class that handles unexpected software errors, including internal errors or errors due to
+ * invalid & incorrect input data.
+ *
+ * @todo Add auxiliary data field to errors
+ */
+class ErrorHandler {
+private:
+	/**
+	 * Log the error to a logging facility. Currently, this just displays the error on the screen.
+	 *
+	 * @todo This function MUST be moved as platform-dependent code. Currently, it uses g++ specific
+	 * functions for desktop.
+	 */
+	template<typename ErrorType>
+	static void logError(const Message &message, ErrorType errorType);
+
+	/**
+	 * Log an error without a Message to a logging facility. Currently, this just displays the error
+	 * on the screen.
+	 *
+	 * @todo This function MUST be moved as platform-dependent code. Currently, it uses g++ specific
+	 * functions for desktop.
+	 */
+	template<typename ErrorType>
+	static void logError(ErrorType errorType);
+
+public:
+	enum InternalErrorType {
+		UnknownInternalError = 0,
+		/**
+		 * While writing (creating) a message, an amount of bytes was tried to be added but
+		 * resulted in failure, since the message storage was not enough.
+		 */
+			MessageTooLarge = 1,
+		/**
+		 * Asked to append a number of bits larger than supported
+		 */
+			TooManyBitsAppend = 2,
+		/**
+		 * Asked to append a byte, while the previous byte was not complete
+		 */
+			ByteBetweenBits = 3,
+		/**
+		 * A string is larger than the largest allowed string
+		 */
+			StringTooLarge = 4,
+	};
+
+	/**
+	 * The error code for failed acceptance reports, as specified in ECSS 6.1.4.3d
+	 *
+	 * Note: Numbers are kept in code explicitly, so that there is no uncertainty when something
+	 * changes.
+	 */
+	enum AcceptanceErrorType {
+		UnknownAcceptanceError = 0,
+		/**
+		 * The received message does not contain enough information as specified
+		 */
+			MessageTooShort = 1,
+		/**
+		 * Asked to read a number of bits larger than supported
+		 */
+			TooManyBitsRead = 2,
+		/**
+		 * Cannot read a string, because it is larger than the largest allowed string
+		 */
+			StringTooShort = 4,
+	};
+
+	/**
+	 * The error code for failed completion of execution reports, as specified in ECSS 5.3.5.2.3g
+	 *
+	 * Note: Numbers are kept in code explicitly, so that there is no uncertainty when something
+	 * changes.
+	 */
+	enum ExecutionErrorType {
+		UnknownExecutionError = 0
+	};
+
+	/**
+	 * The error code for failed completion of execution reports, as specified in ECSS 6.1.3.3d
+	 *
+	 * Note: Numbers are kept in code explicitly, so that there is no uncertainty when something
+	 * changes.
+	 */
+	enum RoutingErrorType {
+		UnknownRoutingError = 0
+	};
+
+	/**
+	 * The location where the error occurred
+	 */
+	enum ErrorSource {
+		Internal,
+		Acceptance,
+		ExecutionStart,
+		ExecutionProgress,
+		ExecutionCompletion,
+		Routing
+	};
+
+	/**
+	 * Report a failure and, if applicable, store a failure report message
+	 *
+	 * @tparam ErrorType The Type struct of the error; can be AcceptanceErrorType,
+	 * 					 ExecutionErrorType, or RoutingErrorType.
+	 * @param message The incoming message that prompted the failure
+	 * @param errorCode The error's code, as defined in ErrorHandler
+	 * @todo See if this needs to include InternalErrorType
+	 */
+	template<typename ErrorType>
+	static void reportError(const Message &message, ErrorType errorCode);
+
+	/**
+	 * Report a failure that occurred internally, not due to a failure of a received packet.
+	 *
+	 * Note that these errors correspond to bugs or faults in the software, and should be treated
+	 * differently. Such an error may prompt a task or software reset.
+	 */
+	static void reportInternalError(InternalErrorType errorCode);
+
+	/**
+	 * Make an assertion, to ensure that a runtime condition is met.
+	 *
+	 * Reports a failure that occurred internally, not due to a failure of a received packet.
+	 *
+	 * Creates an error if \p condition is false. The created error is Internal.
+	 */
+	static void assertInternal(bool condition, InternalErrorType errorCode) {
+		if (not condition) {
+			reportInternalError(errorCode);
+		}
+	}
+
+	/**
+	 * Make an assertion, to ensure that a runtime condition is met.
+	 *
+	 * Reports a failure that occurred while processing a request, in any of the process phases.
+	 *
+	 * Creates an error if \p condition is false. The created error corresponds to a \p message.
+	 */
+	template<typename ErrorType>
+	static void assertRequest(bool condition, const Message &message, ErrorType errorCode) {
+		if (not condition) {
+			reportError(message, errorCode);
+		}
+	}
+};
+
+#endif //PROJECT_ERRORHANDLER_HPP
diff --git a/inc/Helpers/CRCHelper.hpp b/inc/Helpers/CRCHelper.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d70ca5782b7a33add0110990bd23c0c2253dd1e7
--- /dev/null
+++ b/inc/Helpers/CRCHelper.hpp
@@ -0,0 +1,43 @@
+#ifndef ECSS_SERVICES_CRCHELPER_HPP
+#define ECSS_SERVICES_CRCHELPER_HPP
+
+#include <cstdint>
+
+class CRCHelper {
+
+	/**
+	 * CRC32 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)
+	 * (polynomial 0x1021, normal input), but this can change at any time
+	 * (even to a hardware CRC implementation, if available)
+	 *
+	 * Please report all found bugs.
+	 *
+	 * @author (CRC explanation) http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html
+	 * @author (class code & dox) Grigoris Pavlakis <grigpavl@ece.auth.gr>
+	 */
+
+// TODO: Change this to hardware implementation or a trusted software one
+// TODO: Use CRC with received TC and transmitted TM packets
+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
+	 */
+	static uint16_t calculateCRC(const uint8_t* message, uint32_t length);
+
+	/**
+	 * CRC validation function. Make sure the passed message actually contains a CRC checksum
+	 * appended at the very end!
+	 * @param  message (pointer to the data to be validated)
+	 * @param  length (in bytes, plus 2 bytes for the CRC checksum)
+	 * @return 0 when the data is valid, a nonzero uint16 when the data is corrupted
+	 */
+	 static uint16_t validateCRC(const uint8_t* message, uint32_t length);
+};
+
+#endif //ECSS_SERVICES_CRCHELPER_HPP
diff --git a/inc/Message.hpp b/inc/Message.hpp
index 0e311b4e1b796b00cb0bd6294a3b5afd9e5cb651..78bef90e7ee869cecdfe85f278df60437fd28f0c 100644
--- a/inc/Message.hpp
+++ b/inc/Message.hpp
@@ -26,12 +26,19 @@ public:
 	// As specified in CCSDS 133.0-B-1 (TM or TC)
 	PacketType packetType;
 
-	// Maximum value of 2047 (5.4.2.1c)
+	/**
+	 * The destination APID of the message
+	 *
+	 * Maximum value of 2047 (5.4.2.1c)
+	 */
 	uint16_t applicationId;
 
 	// 7.4.3.1b
 	uint16_t messageTypeCounter = 0;
 
+	// 7.4.1, as defined in CCSDS 133.0-B-1
+	uint16_t packetSequenceCount = 0;
+
 	// TODO: Find out if we need more than 16 bits for this
 	uint16_t dataSize = 0;
 
@@ -87,7 +94,7 @@ public:
 	 * @todo See if more than uint8_t strings will be supported
 	 * @todo Is uint16_t size too much or not enough? It has to be defined
 	 */
-	void appendString(uint16_t size, uint8_t *value);
+	void appendString(uint16_t size, const uint8_t *value);
 
 	/**
 	 * Reads the next \p numBits bits from the the message in a big-endian format
diff --git a/inc/Services/EventReportService.hpp b/inc/Services/EventReportService.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4f516648a2a681a17eb14879d2c676dd7fb56164
--- /dev/null
+++ b/inc/Services/EventReportService.hpp
@@ -0,0 +1,128 @@
+#ifndef ECSS_SERVICES_EVENTREPORTSERVICE_HPP
+#define ECSS_SERVICES_EVENTREPORTSERVICE_HPP
+
+#include "Service.hpp"
+/**
+ * Implementation of ST[05] event reporting service
+ * @todo add enum event definition id (and maybe some appending?)
+ *
+ * @todo changes enums event IDs
+ *
+ * Note: enum IDs are these just for test purposes
+ *
+ */
+#define CSS_EVENTS_MAX_COUNT 16
+#define ECSS_EVENTS_BITS 16
+
+class EventReportService : public Service {
+public:
+	EventReportService() {
+		serviceType = 5;
+	}
+
+	/**
+	 * Type of the information event
+	 */
+	enum InformationEvent {
+		/**
+		 * An unknown event occured
+		 */
+			InformativeUnknownEvent = 0,
+		/**
+		 * Watchdogs have reset
+		 */
+			WWDGReset = 1,
+		/**
+		 * An assertion has failed
+		 */
+			AssertionFail = 2,
+		/**
+		 * Microcontroller has started
+		 */
+			MCUStart = 3,
+	};
+
+	/**
+	 * Type of the low severity anomaly event
+	 */
+	enum LowSeverityAnomalyEvent {
+		/**
+		 * An unknown anomaly of low severity anomalyhas occurred
+		 */
+			LowSeverityUnknownEvent = 1,
+	};
+
+	/**
+	 * Type of the medium severity anomaly event
+	 */
+	enum MediumSeverityAnomalyEvent {
+		/**
+		 * An unknown anomaly of medium severity has occurred
+		 */
+			MediumSeverityUnknownEvent = 2,
+	};
+
+	/**
+	 * Type of the high severity anomaly event
+	 */
+	enum HighSeverityAnomalyEvent {
+		/**
+		 * An unknown anomaly of high severity has occurred
+		 */
+			HighSeverityUnknownEvent = 3,
+	};
+
+	/**
+	 * TM[5,1] informative event report
+	 * Send report to inform the respective recipients about an event
+	 *
+	 * Note: The parameters are defined by the standard, but the event definition id is missing!
+	 *
+	 * @param eventID event definition ID
+	 * @param data the data of the report
+	 * @param length the length of the data
+	 */
+	void informativeEventReport(InformationEvent eventID, const uint8_t *data, uint8_t length);
+
+	/**
+	 * TM[5,2] low severiity anomaly report
+	 * Send report when there is an anomaly event of low severity to the respective recipients
+	 *
+	 * Note: The parameters are defined by the standard, but the event definition id is missing!
+	 *
+	 * @param eventID event definition ID
+	 * @param data the data of the report
+	 * @param length the length of the data
+	 */
+	void
+	lowSeverityAnomalyReport(LowSeverityAnomalyEvent eventID, const uint8_t *data, uint8_t length);
+
+	/**
+	 * TM[5,3] medium severity anomaly report
+	 * Send report when there is an anomaly event of medium severity to the respective recipients
+	 *
+	 * Note: The parameters are defined by the standard, but the event definition id is missing!
+	 *
+	 * @param eventID event definition ID
+	 * @param data the data of the report
+	 * @param length the length of the data
+	 */
+	void mediumSeverityAnomalyReport(MediumSeverityAnomalyEvent eventID, const uint8_t *data,
+	                                 uint8_t length);
+
+	/**
+	 * TM[5,4] high severity anomaly report
+	 * Send report when there is an anomaly event of hgih severity to the respective recipients
+	 *
+	 * Note: The parameters are defined by the standard, but the event definition id is missing!
+	 *
+	 * @param eventID event definition ID
+	 * @param data the data of the report
+	 * @param length the length of the data
+	 */
+	void highSeverityAnomalyReport(HighSeverityAnomalyEvent eventID, const uint8_t *data,
+	                               uint8_t length);
+
+};
+
+#endif //ECSS_SERVICES_EVENTREPORTSERVICE_HPP
diff --git a/inc/macros.hpp b/inc/macros.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..25a0833b069d95c291b668d7bb2d7eb93d4f79b9
--- /dev/null
+++ b/inc/macros.hpp
@@ -0,0 +1,7 @@
+#ifndef ECSS_SERVICES_MACROS_HPP
+#define ECSS_SERVICES_MACROS_HPP
+
+#define assertI(cond, error) (ErrorHandler::assertInternal((cond), (error)))
+#define assertR(cond, error) (ErrorHandler::assertRequest((cond), *this, (error)))
+
+#endif //ECSS_SERVICES_MACROS_HPP
diff --git a/src/ErrorHandler.cpp b/src/ErrorHandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d278b1edcd06e67b2c24faea34c6b9f45f0975df
--- /dev/null
+++ b/src/ErrorHandler.cpp
@@ -0,0 +1,77 @@
+#include <iostream>
+#include <cxxabi.h>
+#include <ErrorHandler.hpp>
+
+#include "Services/RequestVerificationService.hpp"
+
+// TODO: Use service singleton, as soon as singletons are ready
+static RequestVerificationService requestVerificationService;
+
+template<>
+void ErrorHandler::reportError(const Message &message, AcceptanceErrorType errorCode) {
+	requestVerificationService.failAcceptanceVerification(
+		message.packetType,
+		true,
+		message.applicationId,
+		ECSS_SEQUENCE_FLAGS,
+		message.packetSequenceCount,
+		static_cast<uint16_t>(errorCode)
+	);
+
+	logError(message, errorCode);
+}
+
+template<>
+void ErrorHandler::reportError(const Message &message, ExecutionErrorType errorCode) {
+	requestVerificationService.failExecutionVerification(
+		message.packetType,
+		true,
+		message.applicationId,
+		ECSS_SEQUENCE_FLAGS,
+		message.packetSequenceCount,
+		static_cast<uint16_t>(errorCode)
+	);
+
+	logError(message, errorCode);
+}
+
+template<>
+void ErrorHandler::reportError(const Message &message, RoutingErrorType errorCode) {
+	requestVerificationService.failRoutingVerification(
+		message.packetType,
+		true,
+		message.applicationId,
+		ECSS_SEQUENCE_FLAGS,
+		message.packetSequenceCount,
+		static_cast<uint16_t>(errorCode)
+	);
+
+	logError(message, errorCode);
+}
+
+void ErrorHandler::reportInternalError(ErrorHandler::InternalErrorType errorCode) {
+	logError(UnknownInternalError);
+}
+
+template<typename ErrorType>
+void ErrorHandler::logError(const Message &message, ErrorType errorType) {
+	std::cerr
+		/*
+		 * Gets the error class name from the template
+		 * Note: This is g++-dependent code and should only be used for debugging.
+		 */
+		<< abi::__cxa_demangle(typeid(ErrorType).name(), nullptr, nullptr, nullptr)
+		<< " Error " << "[" << static_cast<uint16_t>(message.serviceType) << "," <<
+		static_cast<uint16_t>(message.messageType) << "]: " << errorType << std::endl;
+}
+
+template<typename ErrorType>
+void ErrorHandler::logError(ErrorType errorType) {
+	std::cerr
+		/*
+		 * Gets the error class name from the template
+		 * Note: This is g++-dependent code and should only be used for debugging.
+		 */
+		<< abi::__cxa_demangle(typeid(ErrorType).name(), nullptr, nullptr, nullptr)
+		<< " Error: " << errorType << std::endl;
+}
diff --git a/src/Helpers/CRCHelper.cpp b/src/Helpers/CRCHelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e0cd4ebf914ff885c7f50a52aeec4cd3e42c8da8
--- /dev/null
+++ b/src/Helpers/CRCHelper.cpp
@@ -0,0 +1,34 @@
+#include "Helpers/CRCHelper.hpp"
+
+// TODO: THIS IS TEMPORARY CODE, WILL SURELY BE REPLACED
+
+uint16_t CRCHelper::calculateCRC(const uint8_t* message, uint32_t length) {
+	// shift register contains all 1's initially (ECSS-E-ST-70-41C, Annex B - CRC and ISO checksum)
+	uint16_t shiftReg = 0xFFFFu;
+
+	// CRC16-CCITT generator polynomial (as specified in standard)
+	uint16_t polynomial = 0x1021u;
+
+	for (int i = 0; i < length; i++) {
+		// "copy" (XOR w/ existing contents) the current msg bits into the MSB of the shift register
+		shiftReg ^= (message[i] << 8u);
+
+		for (int j = 0; j < 8; j++) {
+			// if the MSB is set, the bitwise AND gives 1
+			if ((shiftReg & 0x8000u) != 0) {
+				// toss out of the register the MSB and divide (XOR) its content with the generator
+				shiftReg = ((shiftReg << 1u) ^ polynomial);
+			}
+			else {
+				// just toss out the MSB and make room for a new bit
+				shiftReg <<= 1u;
+			}
+		}
+	}
+	return shiftReg;
+}
+
+uint16_t CRCHelper::validateCRC(const uint8_t *message, uint32_t length) {
+	return calculateCRC(message, length);
+	// CRC result of a correct msg w/checksum appended is 0
+}
diff --git a/src/Message.cpp b/src/Message.cpp
index 997b617ba4035f5e8af9e40ad27715df94551db9..b51954ec0ec3f08a29582f3bcf8bf8d7972d38fe 100644
--- a/src/Message.cpp
+++ b/src/Message.cpp
@@ -1,5 +1,7 @@
 #include "Message.hpp"
+#include "macros.hpp"
 #include <cstring>
+#include <ErrorHandler.hpp>
 
 
 Message::Message(uint8_t serviceType, uint8_t messageType, Message::PacketType packetType,
@@ -8,10 +10,10 @@ Message::Message(uint8_t serviceType, uint8_t messageType, Message::PacketType p
 
 void Message::appendBits(uint8_t numBits, uint16_t data) {
 	// TODO: Add assertion that data does not contain 1s outside of numBits bits
-	assert(numBits <= 16);
+	assertI(numBits <= 16, ErrorHandler::TooManyBitsAppend);
 
 	while (numBits > 0) { // For every sequence of 8 bits...
-		assert(dataSize < ECSS_MAX_MESSAGE_SIZE);
+		assertI(dataSize < ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooLarge);
 
 		if (currentBit + numBits >= 8) {
 			// Will have to shift the bits and insert the next ones later
@@ -35,16 +37,16 @@ void Message::appendBits(uint8_t numBits, uint16_t data) {
 }
 
 void Message::appendByte(uint8_t value) {
-	assert(dataSize < ECSS_MAX_MESSAGE_SIZE);
-	assert(currentBit == 0);
+	assertI(dataSize < ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooLarge);
+	assertI(currentBit == 0, ErrorHandler::ByteBetweenBits);
 
 	data[dataSize] = value;
 	dataSize++;
 }
 
 void Message::appendHalfword(uint16_t value) {
-	assert(dataSize + 2 <= ECSS_MAX_MESSAGE_SIZE);
-	assert(currentBit == 0);
+	assertI(dataSize + 2 <= ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooLarge);
+	assertI(currentBit == 0, ErrorHandler::ByteBetweenBits);
 
 	data[dataSize] = static_cast<uint8_t>((value >> 8) & 0xFF);
 	data[dataSize + 1] = static_cast<uint8_t>(value & 0xFF);
@@ -53,8 +55,8 @@ void Message::appendHalfword(uint16_t value) {
 }
 
 void Message::appendWord(uint32_t value) {
-	assert(dataSize + 4 <= ECSS_MAX_MESSAGE_SIZE);
-	assert(currentBit == 0);
+	assertI(dataSize + 4 <= ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooLarge);
+	assertI(currentBit == 0, ErrorHandler::ByteBetweenBits);
 
 	data[dataSize] = static_cast<uint8_t>((value >> 24) & 0xFF);
 	data[dataSize + 1] = static_cast<uint8_t>((value >> 16) & 0xFF);
@@ -65,17 +67,17 @@ void Message::appendWord(uint32_t value) {
 }
 
 void Message::appendString(uint8_t size, const char *value) {
-	assert(dataSize + size <= ECSS_MAX_MESSAGE_SIZE);
-	assert(size < ECSS_MAX_STRING_SIZE);
+	assertI(dataSize + size < ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooLarge);
+	assertI(size < ECSS_MAX_STRING_SIZE, ErrorHandler::StringTooLarge);
 
 	memcpy(data + dataSize, value, size);
 
 	dataSize += size;
 }
 
-void Message::appendString(uint16_t size, uint8_t *value) {
-	assert(dataSize + size <= ECSS_MAX_MESSAGE_SIZE);
-	assert(size < ECSS_MAX_STRING_SIZE);
+void Message::appendString(uint16_t size, const uint8_t *value) {
+	assertI(dataSize + size <= ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooLarge);
+	assertI(size < ECSS_MAX_STRING_SIZE, ErrorHandler::StringTooLarge);
 
 	memcpy(data + dataSize, value, size);
 
@@ -83,13 +85,13 @@ void Message::appendString(uint16_t size, uint8_t *value) {
 }
 
 uint16_t Message::readBits(uint8_t numBits) {
-	assert(numBits <= 16);
+	assertR(numBits <= 16, ErrorHandler::TooManyBitsRead);
 	// TODO: Add assert
 
 	uint16_t value = 0x0;
 
 	while (numBits > 0) {
-		assert(readPosition < ECSS_MAX_MESSAGE_SIZE);
+		assertR(readPosition < ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooShort);
 
 		if (currentBit + numBits >= 8) {
 			auto bitsToAddNow = static_cast<uint8_t>(8 - currentBit);
@@ -111,7 +113,7 @@ uint16_t Message::readBits(uint8_t numBits) {
 }
 
 uint8_t Message::readByte() {
-	assert(readPosition < ECSS_MAX_MESSAGE_SIZE);
+	assertR(readPosition < ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooShort);
 
 	uint8_t value = data[readPosition];
 	readPosition++;
@@ -120,7 +122,7 @@ uint8_t Message::readByte() {
 }
 
 uint16_t Message::readHalfword() {
-	assert(readPosition + 2 < ECSS_MAX_MESSAGE_SIZE);
+	assertR(readPosition + 2 <= ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooShort);
 
 	uint16_t value = (data[readPosition] << 8) | data[readPosition + 1];
 	readPosition += 2;
@@ -129,7 +131,7 @@ uint16_t Message::readHalfword() {
 }
 
 uint32_t Message::readWord() {
-	assert(readPosition + 4 < ECSS_MAX_MESSAGE_SIZE);
+	assertR(readPosition + 4 <= ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooShort);
 
 	uint32_t value = (data[readPosition] << 24) | (data[readPosition + 1] << 16) |
 	                 (data[readPosition + 2] << 8) | data[readPosition + 3];
@@ -139,8 +141,8 @@ uint32_t Message::readWord() {
 }
 
 void Message::readString(char *string, uint8_t size) {
-	assert(readPosition + size <= ECSS_MAX_MESSAGE_SIZE);
-	assert(size < ECSS_MAX_STRING_SIZE);
+	assertR(readPosition + size <= ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooShort);
+	assertR(size < ECSS_MAX_STRING_SIZE, ErrorHandler::StringTooShort);
 
 	memcpy(string, data + readPosition, size);
 	string[size] = '\0'; // todo: Use that for now to avoid problems. Later to be removed
@@ -149,8 +151,8 @@ void Message::readString(char *string, uint8_t size) {
 }
 
 void Message::readString(uint8_t *string, uint16_t size) {
-	assert(readPosition + size <= ECSS_MAX_MESSAGE_SIZE);
-	assert(size < ECSS_MAX_STRING_SIZE);
+	assertR(readPosition + size <= ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooShort);
+	assertR(size < ECSS_MAX_STRING_SIZE, ErrorHandler::StringTooShort);
 
 	memcpy(string, data + readPosition, size);
 
diff --git a/src/Services/EventReportService.cpp b/src/Services/EventReportService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0a89f5c9765aa49e8932c0df9c1a4f1ed732a4ac
--- /dev/null
+++ b/src/Services/EventReportService.cpp
@@ -0,0 +1,46 @@
+#include "Services/EventReportService.hpp"
+#include "Message.hpp"
+
+
+void EventReportService::informativeEventReport(InformationEvent eventID, const uint8_t *data,
+                                                uint8_t length) {
+	// TM[5,1]
+	Message report = createTM(1);
+	report.appendEnum16(eventID);
+	report.appendString(length, data);
+
+	storeMessage(report);
+}
+
+void
+EventReportService::lowSeverityAnomalyReport(LowSeverityAnomalyEvent eventID, const uint8_t *data,
+                                             uint8_t length) {
+	// TM[5,2]
+	Message report = createTM(2);
+	report.appendEnum16(eventID);
+	report.appendString(length, data);
+
+	storeMessage(report);
+}
+
+void EventReportService::mediumSeverityAnomalyReport(MediumSeverityAnomalyEvent eventID,
+                                                     const uint8_t *data,
+                                                     uint8_t length) {
+	// TM[5,3]
+	Message report = createTM(3);
+	report.appendEnum16(eventID);
+	report.appendString(length, data);
+
+	storeMessage(report);
+}
+
+void
+EventReportService::highSeverityAnomalyReport(HighSeverityAnomalyEvent eventID, const uint8_t *data,
+                                              uint8_t length) {
+	// TM[5,4]
+	Message report = createTM(4);
+	report.appendEnum16(eventID);
+	report.appendString(length, data);
+
+	storeMessage(report);
+}
diff --git a/src/main.cpp b/src/main.cpp
index 8f4bf906c97b832f8a5e1d2bf8298160deed8521..de68902f98961a2f8781b450f8fd9a83eb328f2e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,11 +1,14 @@
 #include <iostream>
+#include "Helpers/CRCHelper.hpp"
 #include "Services/TestService.hpp"
 #include "Services/ParameterService.hpp"
 #include "Services/RequestVerificationService.hpp"
 #include "Services/MemoryManagementService.hpp"
+#include "Services/EventReportService.hpp"
 #include "Message.hpp"
 #include "MessageParser.hpp"
 #include "Services/MemoryManagementService.hpp"
+#include "ErrorHandler.hpp"
 
 int main() {
 	Message packet = Message(0, 0, Message::TC, 1);
@@ -108,6 +111,18 @@ int main() {
 	receivedMessage = Message(1, 10, Message::TC, 3);
 	reqVerifService.failRoutingVerification(receivedMessage);
 
+	// ST[05] test [works]
+	const unsigned char eventReportData[12] = "Hello World";
+	EventReportService eventReportService;
+	eventReportService.informativeEventReport(EventReportService::InformativeUnknownEvent,
+	                                          eventReportData, 11);
+	eventReportService.lowSeverityAnomalyReport(EventReportService::LowSeverityUnknownEvent,
+	                                            eventReportData, 11);
+	eventReportService.mediumSeverityAnomalyReport(EventReportService::MediumSeverityUnknownEvent,
+	                                               eventReportData, 11);
+	eventReportService.highSeverityAnomalyReport(EventReportService::HighSeverityUnknownEvent,
+	                                             eventReportData, 11);
+
 	// MessageParser class test
 	std::cout << "\n";
 
@@ -131,5 +146,14 @@ int main() {
 	message = Message(1, 10, Message::TC, 3);
 	messageParser.execute(message);
 
+	// ErrorHandler test
+	std::cout << std::flush;
+	std::cerr << std::flush;
+	ErrorHandler::reportError(receivedPacket, ErrorHandler::MessageTooShort);
+	ErrorHandler::reportInternalError(ErrorHandler::MessageTooLarge);
+	Message errorMessage(0, 0, Message::TC, 1);
+	errorMessage.appendBits(2, 7);
+	errorMessage.appendByte(15);
+
 	return 0;
 }
diff --git a/test/ErrorHandler.cpp b/test/ErrorHandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..23eaa2aef869e2501b7b74ea56157db7255e6503
--- /dev/null
+++ b/test/ErrorHandler.cpp
@@ -0,0 +1,69 @@
+#include <catch2/catch.hpp>
+#include <ErrorHandler.hpp>
+#include "Services/ServiceTests.hpp"
+
+TEST_CASE("Error: Failed Acceptance", "[errors]") {
+	Message failedMessage(38, 32, Message::TC, 47);
+	ErrorHandler::reportError(failedMessage, ErrorHandler::MessageTooShort);
+
+	REQUIRE(ServiceTests::hasOneMessage());
+	Message report = ServiceTests::get(0);
+
+	// Check that a TM[1,2] message was returned
+	CHECK(report.serviceType == 1);
+	CHECK(report.messageType == 2);
+	CHECK(report.packetType == Message::TM);
+	REQUIRE(report.dataSize == 6);
+
+	CHECK(report.readBits(3) == ECSS_PUS_VERSION);
+	CHECK(report.readBits(1) == static_cast<uint16_t>(Message::TC));
+	CHECK(report.readBits(1) == true);
+	CHECK(report.readBits(11) == 47);
+	CHECK(report.readBits(2) == ECSS_SEQUENCE_FLAGS);
+	CHECK(report.readBits(14) == failedMessage.packetSequenceCount);
+	CHECK(report.readEnum16() == 1);
+}
+
+TEST_CASE("Error: Failed Execution Completion", "[errors]") {
+	Message failedMessage(38, 32, Message::TC, 56);
+	ErrorHandler::reportError(failedMessage, ErrorHandler::UnknownExecutionError);
+
+	REQUIRE(ServiceTests::hasOneMessage());
+	Message report = ServiceTests::get(0);
+
+	// Check that a TM[1,8] message was returned
+	CHECK(report.serviceType == 1);
+	CHECK(report.messageType == 8);
+	CHECK(report.packetType == Message::TM);
+	REQUIRE(report.dataSize == 6);
+
+	CHECK(report.readBits(3) == ECSS_PUS_VERSION);
+	CHECK(report.readBits(1) == static_cast<uint16_t>(Message::TC));
+	CHECK(report.readBits(1) == true);
+	CHECK(report.readBits(11) == 56);
+	CHECK(report.readBits(2) == ECSS_SEQUENCE_FLAGS);
+	CHECK(report.readBits(14) == failedMessage.packetSequenceCount);
+	CHECK(report.readEnum16() == 0);
+}
+
+TEST_CASE("Error: Failed Routing", "[errors]") {
+	Message failedMessage(38, 32, Message::TC, 71);
+	ErrorHandler::reportError(failedMessage, ErrorHandler::UnknownRoutingError);
+
+	REQUIRE(ServiceTests::hasOneMessage());
+	Message report = ServiceTests::get(0);
+
+	// Check that a TM[1,8] message was returned
+	CHECK(report.serviceType == 1);
+	CHECK(report.messageType == 10);
+	CHECK(report.packetType == Message::TM);
+	REQUIRE(report.dataSize == 6);
+
+	CHECK(report.readBits(3) == ECSS_PUS_VERSION);
+	CHECK(report.readBits(1) == static_cast<uint16_t>(Message::TC));
+	CHECK(report.readBits(1) == true);
+	CHECK(report.readBits(11) == 71);
+	CHECK(report.readBits(2) == ECSS_SEQUENCE_FLAGS);
+	CHECK(report.readBits(14) == failedMessage.packetSequenceCount);
+	CHECK(report.readEnum16() == 0);
+}
diff --git a/test/Helpers/CRCHelper.cpp b/test/Helpers/CRCHelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..73909a920026b63e62ba0364f0db51777ea665c9
--- /dev/null
+++ b/test/Helpers/CRCHelper.cpp
@@ -0,0 +1,51 @@
+#include "catch2/catch.hpp"
+#include "Helpers/CRCHelper.hpp"
+
+TEST_CASE("CRC calculation - Basic string tests") {
+	CHECK(CRCHelper::calculateCRC((uint8_t*) "Raccoon Squad!", 14) == 0x08FC);
+	CHECK(CRCHelper::calculateCRC((uint8_t*) "ASAT", 4) == 0xBFFA);
+	CHECK(CRCHelper::calculateCRC((uint8_t*) "All your space are belong to us", 31) == 0x545F);
+	CHECK(CRCHelper::calculateCRC((uint8_t*) "SPAAAAAAAAACE!", 14) == 0xB441);
+}
+
+TEST_CASE("CRC calculation - Basic byte tests") {
+	SECTION("ECSS compliance verification tests (p.617)") {
+		uint8_t data1[2] = {0x00, 0x00};
+		uint8_t data2[3] = {0x00, 0x00, 0x00};
+		uint8_t data3[4] = {0xAB, 0xCD, 0xEF, 0x01};
+		uint8_t data4[6] = {0x14, 0x56, 0xF8, 0x9A, 0x00, 0x01};
+
+		CHECK(CRCHelper::calculateCRC(data1, 2) == 0x1D0F);
+		CHECK(CRCHelper::calculateCRC(data2, 3) == 0xCC9C);
+		CHECK(CRCHelper::calculateCRC(data3, 4) == 0x04A2);
+		CHECK(CRCHelper::calculateCRC(data4, 6) == 0x7FD5);
+	}
+
+	SECTION("Null (0x00) before ending") {
+		uint8_t data1[5] = {0x45, 0xF2, 0x00, 0xA2, 0x01};
+		uint8_t data2[8] = {0x21, 0x65, 0xDF, 0x00, 0xC4, 0x00, 0x00, 0xBF};
+		uint8_t data3[4] = {0x07, 0x00, 0x05, 0xFF};
+
+		CHECK(CRCHelper::calculateCRC(data1, 5) == 0x3A2B);
+		CHECK(CRCHelper::calculateCRC(data2, 8) == 0x89EE);
+		CHECK(CRCHelper::calculateCRC(data3, 4) == 0x34E8);
+	}
+}
+
+TEST_CASE("CRC validation - Basic tests") {
+	uint8_t data1[7] = {'H', 'e', 'l', 'l', 'o', 0xDA, 0xDA};
+	uint8_t data2[6] = {'A', 'S', 'A', 'T', 0xBF, 0xFA};
+	uint8_t data3[10] = {'S', 'p', 'A', '@', 'A', 'c', '3', '!', 0xB4, 0x41};
+	// checksum from original SPAAAAAAAAACE! string
+	uint8_t data4[6] = {'A', 0x43, 0x52, 0xDF, 0xBF, 0xFA};
+	// ASAT, but "corrupted" with the last 2 bytes the original checksum of the 'ASAT' string
+
+	uint8_t data5[9] = {'C', 'U', 'B', 'E', 'S', 'A', 'T', 0x53, 0x15};  //corrupted CRC checksum
+
+
+	CHECK(CRCHelper::validateCRC(data1, 7) == 0x0);
+	CHECK(CRCHelper::validateCRC(data2, 6) == 0x0);
+	CHECK(CRCHelper::validateCRC(data3, 10) != 0x0);
+	CHECK(CRCHelper::validateCRC(data4, 6) != 0x0);
+	CHECK(CRCHelper::validateCRC(data5, 9) != 0x0);
+}
diff --git a/test/Services/EventReportService.cpp b/test/Services/EventReportService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..32f4f30b18ee8d9e38c9c5a059fcfd07ad27c9f1
--- /dev/null
+++ b/test/Services/EventReportService.cpp
@@ -0,0 +1,88 @@
+#include <catch2/catch.hpp>
+#include <Services/EventReportService.hpp>
+#include <Message.hpp>
+#include "ServiceTests.hpp"
+#include <cstring>
+
+/*
+ * @todo Change the reinterpret_cast
+ */
+TEST_CASE("Informative Event Report TM[5,1]", "[service][st05]") {
+	EventReportService eventReportService;
+	const unsigned char eventReportData[] = "HelloWorld";
+	char checkString[255];
+	eventReportService.informativeEventReport(EventReportService::InformativeUnknownEvent,
+	                                          eventReportData, 10);
+	REQUIRE(ServiceTests::hasOneMessage());
+
+	Message report = ServiceTests::get(0);
+	// Checks for the data-members of the report Message created
+	CHECK(report.serviceType == 5);
+	CHECK(report.messageType == 1);
+	CHECK(report.packetType == Message::TM); // packet type(TM = 0, TC = 1)
+	REQUIRE(report.dataSize == 12);
+	// Check for the value that is stored in <<data>> array(data-member of object response)
+	CHECK(report.readEnum16() == 0);
+	report.readString(checkString, 10);
+	CHECK(strcmp(checkString, reinterpret_cast<const char *>(eventReportData)) == 0);
+}
+
+TEST_CASE("Low Severity Anomaly Report TM[5,2]", "[service][st05]") {
+	EventReportService eventReportService;
+	const unsigned char eventReportData[] = "HelloWorld";
+	char checkString[255];
+	eventReportService.lowSeverityAnomalyReport(EventReportService::LowSeverityUnknownEvent,
+	                                            eventReportData, 10);
+	REQUIRE(ServiceTests::hasOneMessage());
+
+	Message report = ServiceTests::get(0);
+	// Checks for the data-members of the report Message created
+	CHECK(report.serviceType == 5);
+	CHECK(report.messageType == 2);
+	CHECK(report.packetType == Message::TM); // packet type(TM = 0, TC = 1)
+	REQUIRE(report.dataSize == 12);
+	// Check for the value that is stored in <<data>> array(data-member of object response)
+	CHECK(report.readEnum16() == 1);
+	report.readString(checkString, 10);
+	CHECK(strcmp(checkString, reinterpret_cast<const char *>(eventReportData)) == 0);
+}
+
+TEST_CASE("Medium Severity Anomaly Report TM[5,3]", "[service][st05]") {
+	EventReportService eventReportService;
+	const unsigned char eventReportData[] = "HelloWorld";
+	char checkString[255];
+	eventReportService.mediumSeverityAnomalyReport
+		(EventReportService::MediumSeverityUnknownEvent, eventReportData, 10);
+	REQUIRE(ServiceTests::hasOneMessage());
+
+	Message report = ServiceTests::get(0);
+	// Checks for the data-members of the report Message created
+	CHECK(report.serviceType == 5);
+	CHECK(report.messageType == 3);
+	CHECK(report.packetType == Message::TM); // packet type(TM = 0, TC = 1)
+	REQUIRE(report.dataSize == 12);
+	// Check for the value that is stored in <<data>> array(data-member of object response)
+	CHECK(report.readEnum16() == 2);
+	report.readString(checkString, 10);
+	CHECK(strcmp(checkString, reinterpret_cast<const char *>(eventReportData)) == 0);
+}
+
+TEST_CASE("High Severity Anomaly Report TM[5,4]", "[service][st05]") {
+	EventReportService eventReportService;
+	const unsigned char eventReportData[] = "HelloWorld";
+	char checkString[255];
+	eventReportService.highSeverityAnomalyReport(EventReportService::HighSeverityUnknownEvent,
+	                                             eventReportData, 10);
+	REQUIRE(ServiceTests::hasOneMessage());
+
+	Message report = ServiceTests::get(0);
+	// Checks for the data-members of the report Message created
+	CHECK(report.serviceType == 5);
+	CHECK(report.messageType == 4);
+	CHECK(report.packetType == Message::TM); // packet type(TM = 0, TC = 1)
+	REQUIRE(report.dataSize == 12);
+	// Check for the value that is stored in <<data>> array(data-member of object response)
+	CHECK(report.readEnum16() == 3);
+	report.readString(checkString, 10);
+	CHECK(strcmp(checkString, reinterpret_cast<const char *>(eventReportData)) == 0);
+}