diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2d60013b3ee2fb8f46558d46b891e11be189d1c8..51091706143f679881f5743fe96f47001f63aa8a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,9 +37,11 @@ add_library(common OBJECT
         src/Services/RequestVerificationService.cpp
         src/Services/TestService.cpp
         src/Services/LargePacketTransferService.cpp
-    	src/Services/EventActionService.cpp
+        src/Services/EventActionService.cpp
         src/Services/TimeBasedSchedulingService.cpp
         src/Services/FunctionManagementService.cpp
+        src/Services/ParameterStatisticsService.cpp
+        src/Helpers/Statistic.cpp
         )
 
 # Specify the .cpp files for the executables
diff --git a/inc/ECSS_Definitions.hpp b/inc/ECSS_Definitions.hpp
index 3ae97055f0221c61079d2c14bf1d86af01f1b56f..216ea418d9ed7f8912a887ca00839fa939cde4b4 100644
--- a/inc/ECSS_Definitions.hpp
+++ b/inc/ECSS_Definitions.hpp
@@ -23,7 +23,6 @@
  */
 #define ECSS_MAX_MESSAGE_SIZE 1024U
 
-
 /**
  * The maximum size of a regular ECSS message, plus its headers and trailing data, in bytes
  */
@@ -144,11 +143,21 @@
 /**
  * @brief Size of the array holding the Parameter objects for the ST[20] parameter service
  */
-#define ECSS_PARAMETER_COUNT 3
+#define ECSS_PARAMETER_COUNT 4
 
 /**
  * @brief Defines whether the optional CRC field is included
  */
 #define ECSS_CRC_INCLUDED true
 
+/**
+ * Number of parameters whose statistics we need and are going to be stored into the statisticsMap
+ */
+#define ECSS_MAX_STATISTIC_PARAMETERS 4
+
+/**
+ * Whether the ST[04] statistics calculation supports the reporting of stddev
+ */
+#define SUPPORTS_STANDARD_DEVIATION true
+
 #endif // ECSS_SERVICES_ECSS_DEFINITIONS_H
diff --git a/inc/ErrorHandler.hpp b/inc/ErrorHandler.hpp
index 0c07fe079c4f98002cbcc7d17c56a17e93e521d2..d836ba26a95d90745c85c166699a65ef373294be 100644
--- a/inc/ErrorHandler.hpp
+++ b/inc/ErrorHandler.hpp
@@ -142,7 +142,25 @@ public:
 		/**
 		 * Attempt to access a non existing parameter (ST[20])
 		 */
-		GetNonExistingParameter = 8
+		GetNonExistingParameter = 8,
+		/**
+		 * Attempt to set a reporting rate which is smaller than the parameter sampling rate.
+		 * ST[04]
+		 */
+		InvalidReportingRateError = 9,
+		/**
+		 * Attempt to set a sampling rate which is greater than the parameter reporting rate.
+		 * ST[04]
+		 */
+		InvalidSamplingRateError = 10,
+		/**
+		 * Attempt to add definition to the struct map but its already full. (ST[19])
+		 */
+		EventActionDefinitionsMapIsFull = 11,
+		/**
+		 * Attempt to add new statistic definition but the maximum number is already reached (ST[04])
+		 */
+		MaxStatisticDefinitionsReached = 12,
 	};
 
 	/**
diff --git a/inc/Services/Parameter.hpp b/inc/Helpers/Parameter.hpp
similarity index 94%
rename from inc/Services/Parameter.hpp
rename to inc/Helpers/Parameter.hpp
index d2fbe07053aa21e514b3782cd14c109151b02116..7967011acf674d70453a84fa8b0990e6c902f983 100644
--- a/inc/Services/Parameter.hpp
+++ b/inc/Helpers/Parameter.hpp
@@ -34,6 +34,7 @@ class ParameterBase {
 public:
 	virtual void appendValueToMessage(Message& message) = 0;
 	virtual void setValueFromMessage(Message& message) = 0;
+	virtual double getValueAsDouble() = 0;
 };
 
 /**
@@ -57,6 +58,10 @@ public:
 		return currentValue;
 	}
 
+	inline double getValueAsDouble() override {
+		return static_cast<double>(currentValue);
+	}
+
 	/**
 	 * Given an ECSS message that contains this parameter as its first input, this loads the value from that paremeter
 	 */
@@ -72,4 +77,4 @@ public:
 	};
 };
 
-#endif //ECSS_SERVICES_PARAMETER_HPP
+#endif // ECSS_SERVICES_PARAMETER_HPP
diff --git a/inc/Helpers/Statistic.hpp b/inc/Helpers/Statistic.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8934b9fcc434346d57dd535b625e6177fd44b5dd
--- /dev/null
+++ b/inc/Helpers/Statistic.hpp
@@ -0,0 +1,56 @@
+#ifndef ECSS_SERVICES_STATISTIC_HPP
+#define ECSS_SERVICES_STATISTIC_HPP
+
+#include "ECSS_Definitions.hpp"
+#include "Service.hpp"
+#include "ErrorHandler.hpp"
+#include "etl/vector.h"
+#include <cmath>
+#include <cfloat>
+
+/**
+ * Class containing all the statistics for every parameter. Includes functions that calculate and append the
+ * statistics to messages
+ */
+class Statistic {
+public:
+	uint16_t selfSamplingInterval = 0;
+	uint16_t sampleCounter = 0;
+	uint32_t maxTime = 0;
+	uint32_t minTime = 0; // TODO: CUC Format timestamp
+	double max = -std::numeric_limits<double>::infinity();
+	double min = std::numeric_limits<double>::infinity();
+	double sumOfSquares = 0;
+	double mean = 0;
+
+	Statistic() = default;
+
+	/**
+	 * Gets the value from the sensor as argument and updates the statistics without storing it
+	 * @param value returned value from "getValue()" of Parameter.hpp, i.e. the last sampled value from a parameter
+	 */
+	void updateStatistics(double value);
+
+	/**
+	 * Resets all statistics calculated to default values
+	 */
+	void resetStatistics();
+
+	/**
+	 * Appends itself to the received Message
+	 * message.
+	 */
+	void appendStatisticsToMessage(Message& report);
+
+	/**
+	 * Setter function
+	 */
+	void setSelfSamplingInterval(uint16_t samplingInterval);
+
+	/**
+	 * Check if all the statistics are initialized
+	 */
+	bool statisticsAreInitialized();
+};
+
+#endif
\ No newline at end of file
diff --git a/inc/Message.hpp b/inc/Message.hpp
index 2ee8d3c85f0d302c6d2e71ff73d7cb3d110f2d43..0cb719c68b11c69b2788e4a4074da6f784de0b20 100644
--- a/inc/Message.hpp
+++ b/inc/Message.hpp
@@ -350,6 +350,15 @@ public:
 		return appendWord(reinterpret_cast<uint32_t&>(value));
 	}
 
+	/**
+	 * Adds a double to the end of the message
+	 */
+	void appendDouble(double value) {
+		static_assert(sizeof(uint64_t) == sizeof(value), "Double numbers must be 64 bits long");
+
+		return appendUint64(reinterpret_cast<uint64_t&>(value));
+	}
+
 	/**
 	 * Adds a N-byte string to the end of the message
 	 *
@@ -512,6 +521,13 @@ public:
 		return reinterpret_cast<float&>(value);
 	}
 
+	float readDouble() {
+		static_assert(sizeof(uint64_t) == sizeof(double), "Double numbers must be 64 bits long");
+
+		uint64_t value = readUint64();
+		return reinterpret_cast<double&>(value);
+	}
+
 	/**
 	 * Fetches a N-byte string from the current position in the message
 	 *
@@ -535,7 +551,7 @@ public:
 	 * https://www.fluentcpp.com/2017/08/15/function-templates-partial-specialization-cpp/
 	 * @tparam MAX_SIZE The memory size of the string in bytes, which corresponds to the max string size
 	 */
-	template<const size_t MAX_SIZE>
+	template <const size_t MAX_SIZE>
 	String<MAX_SIZE> readOctetString() {
 		String<MAX_SIZE> string("");
 
@@ -614,37 +630,108 @@ public:
 	}
 };
 
-template<> inline void Message::append(const uint8_t& value) { appendUint8(value); }
-template<> inline void Message::append(const uint16_t& value) { appendUint16(value); }
-template<> inline void Message::append(const uint32_t& value) { appendUint32(value); }
-template<> inline void Message::append(const uint64_t& value) { appendUint64(value); }
-
-template<> inline void Message::append(const int8_t& value) { appendSint8(value); }
-template<> inline void Message::append(const int16_t& value) { appendSint16(value); }
-template<> inline void Message::append(const int32_t& value) { appendSint32(value); }
-
-template<> inline void Message::append(const bool& value) { appendBoolean(value); }
-template<> inline void Message::append(const char& value) { appendByte(value); }
-template<> inline void Message::append(const float& value) { appendFloat(value); }
+template <>
+inline void Message::append(const uint8_t& value) {
+	appendUint8(value);
+}
+template <>
+inline void Message::append(const uint16_t& value) {
+	appendUint16(value);
+}
+template <>
+inline void Message::append(const uint32_t& value) {
+	appendUint32(value);
+}
+template <>
+inline void Message::append(const uint64_t& value) {
+	appendUint64(value);
+}
+
+template <>
+inline void Message::append(const int8_t& value) {
+	appendSint8(value);
+}
+template <>
+inline void Message::append(const int16_t& value) {
+	appendSint16(value);
+}
+template <>
+inline void Message::append(const int32_t& value) {
+	appendSint32(value);
+}
+
+template <>
+inline void Message::append(const bool& value) {
+	appendBoolean(value);
+}
+template <>
+inline void Message::append(const char& value) {
+	appendByte(value);
+}
+template <>
+inline void Message::append(const float& value) {
+	appendFloat(value);
+}
+template <>
+inline void Message::append(const double& value) {
+	appendDouble(value);
+}
 
 /**
  * Appends an ETL string to the message. ETL strings are handled as ECSS octet strings, meaning that the string size
  * is appended as a byte before the string itself. To append other string sequences, see the Message::appendString()
  * functions
  */
-template<> inline void Message::append(const etl::istring& value) { appendOctetString(value); }
-
-template<> inline uint8_t Message::read() { return readUint8(); }
-template<> inline uint16_t Message::read() { return readUint16(); }
-template<> inline uint32_t Message::read() { return readUint32(); }
-template<> inline uint64_t Message::read() { return readUint64(); }
-
-template<> inline int8_t Message::read() { return readSint8(); }
-template<> inline int16_t Message::read() { return readSint16(); }
-template<> inline int32_t Message::read() { return readSint32(); }
-
-template<> inline bool Message::read<bool>() { return readBoolean(); }
-template<> inline char Message::read() { return readByte(); }
-template<> inline float Message::read() { return readFloat(); }
+template <>
+inline void Message::append(const etl::istring& value) {
+	appendOctetString(value);
+}
+
+template <>
+inline uint8_t Message::read() {
+	return readUint8();
+}
+template <>
+inline uint16_t Message::read() {
+	return readUint16();
+}
+template <>
+inline uint32_t Message::read() {
+	return readUint32();
+}
+template <>
+inline uint64_t Message::read() {
+	return readUint64();
+}
+
+template <>
+inline int8_t Message::read() {
+	return readSint8();
+}
+template <>
+inline int16_t Message::read() {
+	return readSint16();
+}
+template <>
+inline int32_t Message::read() {
+	return readSint32();
+}
+
+template <>
+inline bool Message::read<bool>() {
+	return readBoolean();
+}
+template <>
+inline char Message::read() {
+	return readByte();
+}
+template <>
+inline float Message::read() {
+	return readFloat();
+}
+template <>
+inline double Message::read() {
+	return readDouble();
+}
 
 #endif // ECSS_SERVICES_PACKET_H
diff --git a/inc/MessageParser.hpp b/inc/MessageParser.hpp
index 82517e8203cd2eb0735e3625c82ef97b9eb0646f..5b89e20cb4925833e2a2541c88cda7d758df9acd 100644
--- a/inc/MessageParser.hpp
+++ b/inc/MessageParser.hpp
@@ -33,7 +33,7 @@
 class MessageParser {
 public:
 	/**
-     * This function takes as input TC packets and calls the proper services' functions that have been
+	 * This function takes as input TC packets and calls the proper services' functions that have been
 	 * implemented to handle TC packets.
 	 *
 	 * @param message Contains the necessary parameters to call the suitable subservice
diff --git a/inc/Platform/x86/ECSS_Configuration.hpp b/inc/Platform/x86/ECSS_Configuration.hpp
index a627d61ae8dcb1790d5c6db133c18096a1d6f7f4..d1ee738207484dd77aa4c4f8b53b3cbd0d77f811 100644
--- a/inc/Platform/x86/ECSS_Configuration.hpp
+++ b/inc/Platform/x86/ECSS_Configuration.hpp
@@ -30,6 +30,7 @@
 #define SERVICE_LARGEPACKET         ///<  Compile ST[13] large packet transfer
 #define SERVICE_MEMORY              ///<  Compile ST[06] memory management
 #define SERVICE_PARAMETER           ///<  Compile ST[20] parameter management
+#define SERVICE_PARAMETERSTATISTICS ///<  Compile ST[04] parameter statistics
 #define SERVICE_REQUESTVERIFICATION ///<  Compile ST[01] request verification
 #define SERVICE_TEST                ///<  Compile ST[17] test
 #define SERVICE_TIME                ///<  Compile ST[09] time management
diff --git a/inc/Platform/x86/Parameters/SystemParameters.hpp b/inc/Platform/x86/Parameters/SystemParameters.hpp
index 1e58687e46c5d39b4d374fcc68cb4d2aa8b8f564..45ee285d545754238cdea46883c03b03784c6521 100644
--- a/inc/Platform/x86/Parameters/SystemParameters.hpp
+++ b/inc/Platform/x86/Parameters/SystemParameters.hpp
@@ -1,4 +1,4 @@
-#include "Services/Parameter.hpp"
+#include "Helpers/Parameter.hpp"
 #include "etl/vector.h"
 /**
  * @author Athanasios Theocharis <athatheoc@gmail.com>
@@ -19,12 +19,12 @@ public:
 	Parameter<uint8_t> parameter1 = Parameter<uint8_t>(3);
 	Parameter<uint16_t> parameter2 = Parameter<uint16_t>(7);
 	Parameter<uint32_t> parameter3 = Parameter<uint32_t>(10);
+	Parameter<uint32_t> parameter4 = Parameter<uint32_t>(24);
 	/**
 	 * The key of the array is the ID of the parameter as specified in PUS
 	 */
-	etl::array<std::reference_wrapper<ParameterBase>, ECSS_PARAMETER_COUNT> parametersArray = {
-		parameter1, parameter2, parameter3
-	};
+	etl::array<std::reference_wrapper<ParameterBase>, ECSS_PARAMETER_COUNT> parametersArray = {parameter1, parameter2,
+	                                                                                           parameter3, parameter4};
 
 	SystemParameters() = default;
 };
diff --git a/inc/ServicePool.hpp b/inc/ServicePool.hpp
index 293b00c3b51ce2a33522dcb40a6d47214e4cd72d..bdfd7103c9527019641c1671be70806159b07f46 100644
--- a/inc/ServicePool.hpp
+++ b/inc/ServicePool.hpp
@@ -11,6 +11,7 @@
 #include "Services/TestService.hpp"
 #include "Services/MemoryManagementService.hpp"
 #include "Services/FunctionManagementService.hpp"
+#include "Services/ParameterStatisticsService.hpp"
 
 /**
  * Defines a class that contains instances of all Services.
@@ -22,8 +23,8 @@ class ServicePool {
 	 * A counter for messages
 	 *
 	 * Each key-value pair corresponds to one MessageType within a Service. For the key, the most significant 8 bits are
-     * the number of the service, while the least significant 8 bits are the number of the Message. The value is the
-     * counter of each MessageType.
+	 * the number of the service, while the least significant 8 bits are the number of the Message. The value is the
+	 * counter of each MessageType.
 	 */
 	etl::map<uint16_t, uint16_t, ECSS_TOTAL_MESSAGE_TYPES> messageTypeCounter;
 
@@ -31,7 +32,12 @@ class ServicePool {
 	 * A counter for messages that corresponds to the total number of TM packets sent from an APID
 	 */
 	uint16_t packetSequenceCounter = 0;
+
 public:
+#ifdef SERVICE_PARAMETERSTATISTICS
+	ParameterStatisticsService parameterStatistics;
+#endif
+
 #ifdef SERVICE_EVENTACTION
 	EventActionService eventAction;
 #endif
diff --git a/inc/Services/ParameterService.hpp b/inc/Services/ParameterService.hpp
index 45fd2fc59d7defed4c3d0faad6d65e62379c4712..eefbea6e0b487d61f53a8b9b61c709698a3cbeab 100644
--- a/inc/Services/ParameterService.hpp
+++ b/inc/Services/ParameterService.hpp
@@ -4,8 +4,7 @@
 #include "ECSS_Definitions.hpp"
 #include "Service.hpp"
 #include "ErrorHandler.hpp"
-#include "Parameter.hpp"
-#include "Parameters/SystemParameters.hpp"
+#include "Helpers/Parameter.hpp"
 
 /**
  * Implementation of the ST[20] parameter management service,
diff --git a/inc/Services/ParameterStatisticsService.hpp b/inc/Services/ParameterStatisticsService.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..cd6de679831b05ca947368c11c0464240db77ad6
--- /dev/null
+++ b/inc/Services/ParameterStatisticsService.hpp
@@ -0,0 +1,114 @@
+#ifndef ECSS_SERVICES_PARAMETERSTATISTICSSERVICE_HPP
+#define ECSS_SERVICES_PARAMETERSTATISTICSSERVICE_HPP
+
+#include "ECSS_Definitions.hpp"
+#include "Service.hpp"
+#include "ErrorHandler.hpp"
+#include "Parameters/SystemParameters.hpp"
+#include "Helpers/Statistic.hpp"
+#include "etl/deque.h"
+#include "etl/map.h"
+
+/**
+ * Implementation of the ST[04] parameter statistics reporting service, as defined in ECSS-E-ST-70-41C.
+ * @author Konstantinos Petridis <petridkon@gmail.com>
+ */
+class ParameterStatisticsService : public Service {
+public:
+	inline static const uint8_t ServiceType = 4;
+
+	enum MessageType : uint8_t {
+		ReportParameterStatistics = 1,
+		ParameterStatisticsReport = 2,
+		ResetParameterStatistics = 3,
+		EnablePeriodicParameterReporting = 4,
+		DisablePeriodicParameterReporting = 5,
+		AddOrUpdateParameterStatisticsDefinitions = 6,
+		DeleteParameterStatisticsDefinitions = 7,
+		ReportParameterStatisticsDefinitions = 8,
+		ParameterStatisticsDefinitionsReport = 9,
+	};
+
+	/**
+	 * Map containing parameters' IDs followed by the statistics that correspond to the specified parameter
+	 */
+	etl::map<uint16_t, Statistic, ECSS_MAX_STATISTIC_PARAMETERS> statisticsMap;
+
+	/**
+	 * true means that the periodic statistics reporting is enabled
+	 */
+	bool periodicStatisticsReportingStatus = false;
+	/**
+	 * If true, after every report reset the parameter statistics.
+	 */
+	bool hasAutomaticStatisticsReset = false; // todo: do const
+	/**
+	 * Indicates whether to append/read the sampling interval to/from message
+	 */
+	const bool supportsSamplingInterval = true;
+	/**
+	 * The parameter statistics reporting interval
+	 */
+	uint16_t reportingInterval = 5; // TODO: Must define units. Same as parameter sampling rates
+
+	/**
+	 * TC[4,1] report the parameter statistics, by calling parameterStatisticsReport()
+	 */
+	void reportParameterStatistics(Message& request);
+
+	/**
+	 * Constructs and stores a TM[4,2] packet containing the parameter statistics report.
+	 */
+	void parameterStatisticsReport();
+
+	/**
+	 * TC[4,3] reset parameter statistics, clearing all samples and values. This is the function called by TC from
+	 * the GS.
+	 */
+	void resetParameterStatistics(Message& request);
+
+	/**
+	 * This function clears all the samples.
+	 */
+	void resetParameterStatistics();
+
+	/**
+	 * TC[4,4] enable periodic parameter statistics reporting
+	 */
+	void enablePeriodicStatisticsReporting(Message& request);
+
+	/**
+	 * TC[4,5] disable periodic parameter statistics reporting
+	 */
+	void disablePeriodicStatisticsReporting(Message& request);
+
+	/**
+	 * TC[4,6] add or update parameter statistics definitions
+	 */
+	void addOrUpdateStatisticsDefinitions(Message& request);
+
+	/**
+	 * TC[4,7] delete parameter statistics definitions.
+	 */
+	void deleteStatisticsDefinitions(Message& request);
+
+	/**
+	 * TC[4,8] report the parameter statistics definitions, by calling statisticsDefinitionsReport()
+	 */
+	void reportStatisticsDefinitions(Message& request);
+	/**
+	 * Constructs and stores a TM[4,9] packet containing the parameter statistics definitions report.
+	 */
+	void statisticsDefinitionsReport();
+
+	/**
+	 * Calls the suitable function that executes a telecommand packet. The source of that packet
+	 * is the ground station.
+	 *
+	 * @note This function is called from the main execute() that is defined in the file MessageParser.hpp
+	 * @param message Contains the necessary parameters to call the suitable subservice
+	 */
+	void execute(Message& message);
+};
+
+#endif
\ No newline at end of file
diff --git a/src/Helpers/Statistic.cpp b/src/Helpers/Statistic.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..70af6e62bbb42b740ceee5e357b2aa5863c931c5
--- /dev/null
+++ b/src/Helpers/Statistic.cpp
@@ -0,0 +1,62 @@
+#include <iostream>
+#include "Helpers/Statistic.hpp"
+
+void Statistic::updateStatistics(double value) {
+	/*
+	 * TODO:
+	 *      if periodic, just calculate next time without the CUC
+	 *      function.
+	 * */
+
+	if (value > max) {
+		max = value;
+		// TODO: maxTime = as_CUC_timestamp();
+	}
+	if (value < min) {
+		min = value;
+		// TODO: minTime = as_CUC_timestamp();
+	}
+	if (sampleCounter + 1 > 0) {
+		mean = (mean * sampleCounter + value) / (sampleCounter + 1);
+	}
+	sumOfSquares += pow(value, 2);
+	sampleCounter++;
+}
+
+void Statistic::appendStatisticsToMessage(Message& report) {
+	report.appendFloat(static_cast<float>(max));
+	report.appendUint32(maxTime);
+	report.appendFloat(static_cast<float>(min));
+	report.appendUint32(minTime);
+	report.appendFloat(static_cast<float>(mean));
+
+	if (SUPPORTS_STANDARD_DEVIATION) {
+		double standardDeviation = 0;
+		if (sampleCounter == 0) {
+			standardDeviation = 0;
+		} else {
+			double meanOfSquares = sumOfSquares / sampleCounter;
+			standardDeviation = sqrt(abs(meanOfSquares - pow(mean, 2)));
+		}
+		report.appendFloat(static_cast<float>(standardDeviation));
+	}
+}
+
+void Statistic::setSelfSamplingInterval(uint16_t samplingInterval) {
+	this->selfSamplingInterval = samplingInterval;
+}
+
+void Statistic::resetStatistics() {
+	max = -std::numeric_limits<double>::infinity();
+	min = std::numeric_limits<double>::infinity();
+	maxTime = 0;
+	minTime = 0;
+	mean = 0;
+	sumOfSquares = 0;
+	sampleCounter = 0;
+}
+
+bool Statistic::statisticsAreInitialized() {
+	return (sampleCounter == 0 and mean == 0 and sumOfSquares == 0 and maxTime == 0 and minTime == 0 and
+	        max == -std::numeric_limits<double>::infinity() and min == std::numeric_limits<double>::infinity());
+}
diff --git a/src/Message.cpp b/src/Message.cpp
index 21732cb98ab8586e1fc26635dff5884da089328f..1a2ea7a593e4e8cb2f49c6f0512287d197849ae5 100644
--- a/src/Message.cpp
+++ b/src/Message.cpp
@@ -6,7 +6,7 @@
 #include <MessageParser.hpp>
 
 Message::Message(uint8_t serviceType, uint8_t messageType, Message::PacketType packetType, uint16_t applicationId)
-	: serviceType(serviceType), messageType(messageType), packetType(packetType), applicationId(applicationId) {}
+    : serviceType(serviceType), messageType(messageType), packetType(packetType), applicationId(applicationId) {}
 
 void Message::appendBits(uint8_t numBits, uint16_t data) {
 	// TODO: Add assertion that data does not contain 1s outside of numBits bits
@@ -174,7 +174,7 @@ void Message::appendString(const etl::istring& string) {
 void Message::appendFixedString(const etl::istring& string) {
 	ASSERT_INTERNAL((dataSize + string.max_size()) < ECSS_MAX_MESSAGE_SIZE, ErrorHandler::MessageTooLarge);
 	std::copy(string.data(), string.data() + string.size(), data + dataSize);
-	(void) memset(data + dataSize + string.size(), 0, string.max_size() - string.size());
+	(void)memset(data + dataSize + string.size(), 0, string.max_size() - string.size());
 	dataSize += string.max_size();
 }
 
diff --git a/src/MessageParser.cpp b/src/MessageParser.cpp
index da379e2ceeb681aff0a856fff0883a4c2236a7d3..b23235a42a39b777d2a4bdf95dae663f4b8ebb8d 100644
--- a/src/MessageParser.cpp
+++ b/src/MessageParser.cpp
@@ -7,42 +7,56 @@
 
 void MessageParser::execute(Message& message) {
 	switch (message.serviceType) {
+#ifdef SERVICE_PARAMETERSTATISTICS
+		case 4:
+			Services.parameterStatistics.execute(message);
+			break;
+#endif
+
 #ifdef SERVICE_EVENTREPORT
-		case 5: Services.eventReport.execute(message); // ST[05]
+		case 5:
+			Services.eventReport.execute(message); // ST[05]
 			break;
 #endif
 
 #ifdef SERVICE_MEMORY
-		case 6: Services.memoryManagement.execute(message); // ST[06]
+		case 6:
+			Services.memoryManagement.execute(message); // ST[06]
 			break;
 #endif
 
 #ifdef SERVICE_FUNCTION
-		case 8: Services.functionManagement.execute(message); // ST[08]
+		case 8:
+			Services.functionManagement.execute(message); // ST[08]
 			break;
 #endif
 
 #ifdef SERVICE_TIMESCHEDULING
-		case 11: Services.timeBasedScheduling.execute(message); // ST[11]
+		case 11:
+			Services.timeBasedScheduling.execute(message); // ST[11]
 			break;
 #endif
 
 #ifdef SERVICE_TEST
-		case 17: Services.testService.execute(message); // ST[17]
+		case 17:
+			Services.testService.execute(message); // ST[17]
 			break;
 #endif
 
 #ifdef SERVICE_EVENTACTION
-		case 19: Services.eventAction.execute(message); // ST[19]
+		case 19:
+			Services.eventAction.execute(message); // ST[19]
 			break;
 #endif
 
 #ifdef SERVICE_PARAMETER
-		case 20: Services.parameterManagement.execute(message); // ST[20]
+		case 20:
+			Services.parameterManagement.execute(message); // ST[20]
 			break;
 #endif
 
-		default: ErrorHandler::reportInternalError(ErrorHandler::OtherMessageType);
+		default:
+			ErrorHandler::reportInternalError(ErrorHandler::OtherMessageType);
 	}
 }
 
@@ -180,8 +194,7 @@ String<CCSDS_MAX_MESSAGE_SIZE> MessageParser::compose(const Message& message) {
 
 #if ECSS_CRC_INCLUDED
 	// Append CRC field
-	uint16_t crcField = CRCHelper::calculateCRC(reinterpret_cast<uint8_t*>(ccsdsMessage.data()), 6 +
-	                                                                                             packetDataLength);
+	uint16_t crcField = CRCHelper::calculateCRC(reinterpret_cast<uint8_t*>(ccsdsMessage.data()), 6 + packetDataLength);
 	ccsdsMessage.push_back(static_cast<uint8_t>(crcField >> 8U));
 	ccsdsMessage.push_back(static_cast<uint8_t>(crcField & 0xFF));
 #endif
@@ -189,7 +202,6 @@ String<CCSDS_MAX_MESSAGE_SIZE> MessageParser::compose(const Message& message) {
 	return ccsdsMessage;
 }
 
-
 void MessageParser::parseECSSTMHeader(const uint8_t* data, uint16_t length, Message& message) {
 	ErrorHandler::assertRequest(length >= 5, message, ErrorHandler::UnacceptableMessage);
 
diff --git a/src/Platform/x86/main.cpp b/src/Platform/x86/main.cpp
index b74c6eab60a719933816cb5a5ce68ede6f52d684..a9060ed119a802eaf0d1c580d4d34a39245f6c9e 100644
--- a/src/Platform/x86/main.cpp
+++ b/src/Platform/x86/main.cpp
@@ -1,5 +1,4 @@
 #include <iostream>
-#include <ServicePool.hpp>
 #include <Logger.hpp>
 #include "Helpers/CRCHelper.hpp"
 #include "Helpers/TimeHelper.hpp"
@@ -12,12 +11,14 @@
 #include "Services/EventActionService.hpp"
 #include "Services/LargePacketTransferService.hpp"
 #include "Services/TimeBasedSchedulingService.hpp"
-#include "ServicePool.hpp"
+#include "Services/ParameterStatisticsService.hpp"
+#include "Helpers/Statistic.hpp"
 #include "Message.hpp"
 #include "MessageParser.hpp"
-#include "Helpers/CRCHelper.hpp"
 #include "ErrorHandler.hpp"
 #include "etl/String.hpp"
+#include "ServicePool.hpp"
+#include <ctime>
 
 int main() {
 	LOG_NOTICE << "ECSS Services test application";
@@ -40,7 +41,8 @@ int main() {
 
 	// ST[17] test
 	TestService& testService = Services.testService;
-	Message receivedPacket = Message(TestService::ServiceType, TestService::MessageType::AreYouAliveTest, Message::TC, 1);
+	Message receivedPacket =
+	    Message(TestService::ServiceType, TestService::MessageType::AreYouAliveTest, Message::TC, 1);
 	testService.areYouAlive(receivedPacket);
 	receivedPacket = Message(TestService::ServiceType, TestService::MessageType::OnBoardConnectionTest, Message::TC, 1);
 	receivedPacket.appendUint16(7);
@@ -50,14 +52,16 @@ int main() {
 	ParameterService& paramService = Services.parameterManagement;
 
 	// Test code for reportParameter
-	Message sentPacket = Message(ParameterService::ServiceType, ParameterService::MessageType::ReportParameterValues, Message::TC, 1); // application id is a dummy number (1)
+	Message sentPacket = Message(ParameterService::ServiceType, ParameterService::MessageType::ReportParameterValues,
+	                             Message::TC, 1); // application id is a dummy number (1)
 	sentPacket.appendUint16(2); // number of contained IDs
 	sentPacket.appendUint16(0); // first ID
 	sentPacket.appendUint16(1); // second ID
 	paramService.reportParameters(sentPacket);
 
 	// Test code for setParameter
-	Message sentPacket2 = Message(ParameterService::ServiceType, ParameterService::MessageType::SetParameterValues, Message::TC, 1); // application id is a dummy number (1)
+	Message sentPacket2 = Message(ParameterService::ServiceType, ParameterService::MessageType::SetParameterValues,
+	                              Message::TC, 1); // application id is a dummy number (1)
 	sentPacket2.appendUint16(2); // number of contained IDs
 	sentPacket2.appendUint16(0); // first parameter ID
 	sentPacket2.appendUint32(63238); // settings for first parameter
@@ -76,7 +80,8 @@ int main() {
 	*(pStr + 2) = 0;
 
 	MemoryManagementService& memMangService = Services.memoryManagement;
-	Message rcvPack = Message(MemoryManagementService::ServiceType, MemoryManagementService::MessageType::DumpRawMemoryData, Message::TC, 1);
+	Message rcvPack = Message(MemoryManagementService::ServiceType,
+	                          MemoryManagementService::MessageType::DumpRawMemoryData, Message::TC, 1);
 	rcvPack.appendEnum8(MemoryManagementService::MemoryID::EXTERNAL); // Memory ID
 	rcvPack.appendUint16(3); // Iteration count
 	rcvPack.appendUint64(reinterpret_cast<uint64_t>(string)); // Start address
@@ -89,7 +94,8 @@ int main() {
 	rcvPack.appendUint16(sizeof(yetAnotherStr) / sizeof(yetAnotherStr[0]));
 	memMangService.rawDataMemorySubservice.dumpRawData(rcvPack);
 
-	rcvPack = Message(MemoryManagementService::ServiceType, MemoryManagementService::MessageType::LoadRawMemoryDataAreas, Message::TC, 1);
+	rcvPack = Message(MemoryManagementService::ServiceType,
+	                  MemoryManagementService::MessageType::LoadRawMemoryDataAreas, Message::TC, 1);
 
 	uint8_t data[2] = {'h', 'R'};
 	rcvPack.appendEnum8(MemoryManagementService::MemoryID::EXTERNAL); // Memory ID
@@ -102,7 +108,8 @@ int main() {
 	rcvPack.appendBits(16, CRCHelper::calculateCRC(data, 1)); // Append the CRC value
 	memMangService.rawDataMemorySubservice.loadRawData(rcvPack);
 
-	rcvPack = Message(MemoryManagementService::ServiceType, MemoryManagementService::MessageType::CheckRawMemoryData, Message::TC, 1);
+	rcvPack = Message(MemoryManagementService::ServiceType, MemoryManagementService::MessageType::CheckRawMemoryData,
+	                  Message::TC, 1);
 
 	rcvPack.appendEnum8(MemoryManagementService::MemoryID::EXTERNAL); // Memory ID
 	rcvPack.appendUint16(2); // Iteration count
@@ -116,33 +123,41 @@ int main() {
 
 	RequestVerificationService& reqVerifService = Services.requestVerification;
 
-	Message receivedMessage = Message(RequestVerificationService::ServiceType,
-		RequestVerificationService::MessageType::SuccessfulAcceptanceReport,
-		Message::TC, 3);
+	Message receivedMessage =
+	    Message(RequestVerificationService::ServiceType,
+	            RequestVerificationService::MessageType::SuccessfulAcceptanceReport, Message::TC, 3);
 	reqVerifService.successAcceptanceVerification(receivedMessage);
 
-	receivedMessage = Message(RequestVerificationService::ServiceType, RequestVerificationService::MessageType::FailedAcceptanceReport, Message::TC, 3);
+	receivedMessage = Message(RequestVerificationService::ServiceType,
+	                          RequestVerificationService::MessageType::FailedAcceptanceReport, Message::TC, 3);
 	reqVerifService.failAcceptanceVerification(receivedMessage, ErrorHandler::UnknownAcceptanceError);
 
-	receivedMessage = Message(RequestVerificationService::ServiceType, RequestVerificationService::MessageType::SuccessfulStartOfExecution, Message::TC, 3);
+	receivedMessage = Message(RequestVerificationService::ServiceType,
+	                          RequestVerificationService::MessageType::SuccessfulStartOfExecution, Message::TC, 3);
 	reqVerifService.successStartExecutionVerification(receivedMessage);
 
-	receivedMessage = Message(RequestVerificationService::ServiceType, RequestVerificationService::MessageType::FailedStartOfExecution, Message::TC, 3);
+	receivedMessage = Message(RequestVerificationService::ServiceType,
+	                          RequestVerificationService::MessageType::FailedStartOfExecution, Message::TC, 3);
 	reqVerifService.failStartExecutionVerification(receivedMessage, ErrorHandler::UnknownExecutionStartError);
 
-	receivedMessage = Message(RequestVerificationService::ServiceType, RequestVerificationService::MessageType::SuccessfulProgressOfExecution, Message::TC, 3);
+	receivedMessage = Message(RequestVerificationService::ServiceType,
+	                          RequestVerificationService::MessageType::SuccessfulProgressOfExecution, Message::TC, 3);
 	reqVerifService.successProgressExecutionVerification(receivedMessage, 0);
 
-	receivedMessage = Message(RequestVerificationService::ServiceType, RequestVerificationService::MessageType::FailedProgressOfExecution, Message::TC, 3);
+	receivedMessage = Message(RequestVerificationService::ServiceType,
+	                          RequestVerificationService::MessageType::FailedProgressOfExecution, Message::TC, 3);
 	reqVerifService.failProgressExecutionVerification(receivedMessage, ErrorHandler::UnknownExecutionProgressError, 0);
 
-	receivedMessage = Message(RequestVerificationService::ServiceType, RequestVerificationService::MessageType::SuccessfulCompletionOfExecution, Message::TC, 3);
+	receivedMessage = Message(RequestVerificationService::ServiceType,
+	                          RequestVerificationService::MessageType::SuccessfulCompletionOfExecution, Message::TC, 3);
 	reqVerifService.successCompletionExecutionVerification(receivedMessage);
 
-	receivedMessage = Message(RequestVerificationService::ServiceType, RequestVerificationService::MessageType::FailedCompletionOfExecution, Message::TC, 3);
+	receivedMessage = Message(RequestVerificationService::ServiceType,
+	                          RequestVerificationService::MessageType::FailedCompletionOfExecution, Message::TC, 3);
 	reqVerifService.failCompletionExecutionVerification(receivedMessage, ErrorHandler::UnknownExecutionCompletionError);
 
-	receivedMessage = Message(RequestVerificationService::ServiceType, RequestVerificationService::MessageType::FailedRoutingReport, Message::TC, 3);
+	receivedMessage = Message(RequestVerificationService::ServiceType,
+	                          RequestVerificationService::MessageType::FailedRoutingReport, Message::TC, 3);
 	reqVerifService.failRoutingVerification(receivedMessage, ErrorHandler::UnknownRoutingError);
 
 	// ST[05] (5,1 to 5,4) test [works]
@@ -169,16 +184,19 @@ int main() {
 	EventReportService::Event eventIDs[] = {EventReportService::HighSeverityUnknownEvent,
 	                                        EventReportService::MediumSeverityUnknownEvent};
 	EventReportService::Event eventIDs2[] = {EventReportService::HighSeverityUnknownEvent};
-	Message eventMessage(EventReportService::ServiceType, EventReportService::MessageType::DisableReportGenerationOfEvents, Message::TC, 1);
+	Message eventMessage(EventReportService::ServiceType,
+	                     EventReportService::MessageType::DisableReportGenerationOfEvents, Message::TC, 1);
 	eventMessage.appendUint16(2);
 	eventMessage.appendEnum16(eventIDs[0]);
 	eventMessage.appendEnum16(eventIDs[1]);
 
-	Message eventMessage2(EventReportService::ServiceType, EventReportService::MessageType::EnableReportGenerationOfEvents, Message::TC, 1);
+	Message eventMessage2(EventReportService::ServiceType,
+	                      EventReportService::MessageType::EnableReportGenerationOfEvents, Message::TC, 1);
 	eventMessage2.appendUint16(1);
 	eventMessage2.appendEnum16(eventIDs2[0]);
 
-	Message eventMessage3(EventReportService::ServiceType, EventReportService::MessageType::ReportListOfDisabledEvent, Message::TC, 1);
+	Message eventMessage3(EventReportService::ServiceType, EventReportService::MessageType::ReportListOfDisabledEvent,
+	                      Message::TC, 1);
 	eventReportService.disableReportGeneration(eventMessage);
 	eventReportService.listOfDisabledEventsReport();
 	eventReportService.enableReportGeneration(eventMessage2);
@@ -186,9 +204,10 @@ int main() {
 
 	// ST[19] test
 
-	EventActionService & eventActionService = Services.eventAction;
+	EventActionService& eventActionService = Services.eventAction;
 
-	Message eventActionDefinition(EventActionService::ServiceType, EventActionService::MessageType::AddEventAction, Message::TC, 1);
+	Message eventActionDefinition(EventActionService::ServiceType, EventActionService::MessageType::AddEventAction,
+	                              Message::TC, 1);
 	eventActionDefinition.appendEnum16(0);
 	eventActionDefinition.appendEnum16(2);
 	eventActionDefinition.appendEnum16(1);
@@ -196,7 +215,8 @@ int main() {
 	eventActionDefinition.appendString(TCdata);
 	eventActionService.addEventActionDefinitions(eventActionDefinition);
 
-	Message eventActionDefinition1(EventActionService::ServiceType, EventActionService::MessageType::AddEventAction, Message::TC, 1);
+	Message eventActionDefinition1(EventActionService::ServiceType, EventActionService::MessageType::AddEventAction,
+	                               Message::TC, 1);
 	eventActionDefinition1.appendEnum16(0);
 	eventActionDefinition1.appendEnum16(2);
 	eventActionDefinition1.appendEnum16(1);
@@ -205,7 +225,8 @@ int main() {
 	std::cout << "After this message there should be a failed start of execution error \n";
 	eventActionService.addEventActionDefinitions(eventActionDefinition1);
 
-	Message eventActionDefinition2(EventActionService::ServiceType, EventActionService::MessageType::AddEventAction, Message::TC, 1);
+	Message eventActionDefinition2(EventActionService::ServiceType, EventActionService::MessageType::AddEventAction,
+	                               Message::TC, 1);
 	eventActionDefinition2.appendEnum16(0);
 	eventActionDefinition2.appendEnum16(4);
 	eventActionDefinition2.appendEnum16(2);
@@ -213,7 +234,8 @@ int main() {
 	eventActionDefinition2.appendString(TCdata);
 	eventActionService.addEventActionDefinitions(eventActionDefinition2);
 
-	Message eventActionDefinition7(EventActionService::ServiceType, EventActionService::MessageType::AddEventAction, Message::TC, 1);
+	Message eventActionDefinition7(EventActionService::ServiceType, EventActionService::MessageType::AddEventAction,
+	                               Message::TC, 1);
 	eventActionDefinition7.appendEnum16(0);
 	eventActionDefinition7.appendEnum16(4);
 	eventActionDefinition7.appendEnum16(4);
@@ -222,11 +244,12 @@ int main() {
 	eventActionService.addEventActionDefinitions(eventActionDefinition7);
 
 	std::cout << "Status should be 000:";
-	for (auto& element : eventActionService.eventActionDefinitionMap){
+	for (auto& element : eventActionService.eventActionDefinitionMap) {
 		std::cout << element.second.enabled;
 	}
 
-	Message eventActionDefinition5(EventActionService::ServiceType, EventActionService::MessageType::EnableEventAction, Message::TC, 1);
+	Message eventActionDefinition5(EventActionService::ServiceType, EventActionService::MessageType::EnableEventAction,
+	                               Message::TC, 1);
 	eventActionDefinition5.appendUint16(3);
 	eventActionDefinition5.appendUint16(0);
 	eventActionDefinition5.appendUint16(2);
@@ -240,11 +263,12 @@ int main() {
 
 	eventActionService.enableEventActionDefinitions(eventActionDefinition5);
 	std::cout << "\nStatus should be 111:";
-	for (auto& element : eventActionService.eventActionDefinitionMap){
+	for (auto& element : eventActionService.eventActionDefinitionMap) {
 		std::cout << element.second.enabled;
 	}
 
-	Message eventActionDefinition3(EventActionService::ServiceType, EventActionService::MessageType::DisableEventAction, Message::TC, 1);
+	Message eventActionDefinition3(EventActionService::ServiceType, EventActionService::MessageType::DisableEventAction,
+	                               Message::TC, 1);
 	eventActionDefinition3.appendUint16(3);
 	eventActionDefinition3.appendUint16(0);
 	eventActionDefinition3.appendUint16(2);
@@ -257,13 +281,14 @@ int main() {
 	eventActionDefinition3.appendUint16(4);
 	eventActionService.disableEventActionDefinitions(eventActionDefinition3);
 	std::cout << "Status should be 000:";
-	for (auto& element : eventActionService.eventActionDefinitionMap){
+	for (auto& element : eventActionService.eventActionDefinitionMap) {
 		std::cout << element.second.enabled;
 	}
 
 	eventActionService.enableEventActionDefinitions(eventActionDefinition5);
 
-	Message eventActionDefinition4(EventActionService::ServiceType, EventActionService::MessageType::DeleteEventAction, Message::TC, 1);
+	Message eventActionDefinition4(EventActionService::ServiceType, EventActionService::MessageType::DeleteEventAction,
+	                               Message::TC, 1);
 	eventActionDefinition4.appendUint16(1);
 	eventActionDefinition4.appendUint16(0);
 	eventActionDefinition4.appendUint16(2);
@@ -272,7 +297,8 @@ int main() {
 	std::cout << "After this message there should be a failed start of execution error \n";
 	eventActionService.deleteEventActionDefinitions(eventActionDefinition4);
 
-	Message eventActionDefinition6(EventActionService::ServiceType, EventActionService::MessageType::DisableEventAction, Message::TC, 1);
+	Message eventActionDefinition6(EventActionService::ServiceType, EventActionService::MessageType::DisableEventAction,
+	                               Message::TC, 1);
 	eventActionDefinition6.appendUint16(1);
 	eventActionDefinition6.appendUint16(0);
 	eventActionDefinition6.appendUint16(2);
@@ -281,13 +307,13 @@ int main() {
 	std::cout << "After this message there should NOT be a failed start of execution error \n";
 	eventActionService.deleteEventActionDefinitions(eventActionDefinition4);
 
-
 	// ST13 test
 
 	LargePacketTransferService largePacketTransferService;
 	String<256> dataToTransfer = "12345678";
 	largePacketTransferService.firstDownlinkPartReport(LargePacketTransferService::ServiceType,
-		LargePacketTransferService::MessageType::FirstDownlinkPartReport, dataToTransfer);
+	                                                   LargePacketTransferService::MessageType::FirstDownlinkPartReport,
+	                                                   dataToTransfer);
 
 	// ST[11] test
 	TimeBasedSchedulingService timeBasedSchedulingService;
@@ -295,7 +321,9 @@ int main() {
 	std::cout << "\n\nST[11] service is running";
 	std::cout << "\nCurrent time in seconds (UNIX epoch): " << currentTime << std::endl;
 
-	Message receivedMsg = Message(TimeBasedSchedulingService::ServiceType, TimeBasedSchedulingService::MessageType::EnableTimeBasedScheduleExecutionFunction, Message::TC, 1);
+	Message receivedMsg =
+	    Message(TimeBasedSchedulingService::ServiceType,
+	            TimeBasedSchedulingService::MessageType::EnableTimeBasedScheduleExecutionFunction, Message::TC, 1);
 	Message testMessage1(6, 5, Message::TC, 1);
 	Message testMessage2(4, 5, Message::TC, 1);
 	testMessage1.appendUint16(4253); // Append dummy data
@@ -304,7 +332,8 @@ int main() {
 	timeBasedSchedulingService.enableScheduleExecution(receivedMsg); // Enable the schedule
 
 	// Insert activities in the schedule
-	receivedMsg = Message(TimeBasedSchedulingService::ServiceType, TimeBasedSchedulingService::MessageType::InsertActivities, Message::TC, 1);
+	receivedMsg = Message(TimeBasedSchedulingService::ServiceType,
+	                      TimeBasedSchedulingService::MessageType::InsertActivities, Message::TC, 1);
 	receivedMsg.appendUint16(2); // Total number of requests
 
 	receivedMsg.appendUint32(currentTime + 1556435U);
@@ -315,17 +344,20 @@ int main() {
 	timeBasedSchedulingService.insertActivities(receivedMsg);
 
 	// Time shift activities
-	receivedMsg = Message(TimeBasedSchedulingService::ServiceType, TimeBasedSchedulingService::MessageType::TimeShiftALlScheduledActivities, Message::TC, 1);
+	receivedMsg = Message(TimeBasedSchedulingService::ServiceType,
+	                      TimeBasedSchedulingService::MessageType::TimeShiftALlScheduledActivities, Message::TC, 1);
 	receivedMsg.appendSint32(-6789);
 	timeBasedSchedulingService.timeShiftAllActivities(receivedMsg);
 	std::cout << "Activities should be time shifted by: " << -6789 << " seconds." << std::endl;
 
 	// Report the activities
-	receivedMsg = Message(TimeBasedSchedulingService::ServiceType, TimeBasedSchedulingService::MessageType::DetailReportAllScheduledActivities, Message::TC, 1);
+	receivedMsg = Message(TimeBasedSchedulingService::ServiceType,
+	                      TimeBasedSchedulingService::MessageType::DetailReportAllScheduledActivities, Message::TC, 1);
 	timeBasedSchedulingService.detailReportAllActivities(receivedMsg);
 
 	// Report the activities by ID
-	receivedMsg = Message(TimeBasedSchedulingService::ServiceType, TimeBasedSchedulingService::MessageType::ActivitiesSummaryReportById, Message::TC, 1);
+	receivedMsg = Message(TimeBasedSchedulingService::ServiceType,
+	                      TimeBasedSchedulingService::MessageType::ActivitiesSummaryReportById, Message::TC, 1);
 	timeBasedSchedulingService.summaryReportActivitiesByID(receivedMsg);
 
 	LOG_NOTICE << "ECSS Services test complete";
diff --git a/src/Services/EventActionService.cpp b/src/Services/EventActionService.cpp
index bc739f745f55942eec3787944eec99dd5e540809..84c727bef38a330796aaa6c0da4d990828240ab4 100644
--- a/src/Services/EventActionService.cpp
+++ b/src/Services/EventActionService.cpp
@@ -35,7 +35,11 @@ void EventActionService::addEventActionDefinitions(Message& message) {
 		temp.eventDefinitionID = eventDefinitionID;
 		temp.eventActionDefinitionID = eventActionDefinitionID;
 		temp.request = String<ECSS_TC_REQUEST_STRING_SIZE>(data);
-		eventActionDefinitionMap.insert(std::make_pair(eventDefinitionID, temp));
+		if (eventActionDefinitionMap.size() == ECSS_EVENT_ACTION_STRUCT_MAP_SIZE) {
+			ErrorHandler::reportError(message,ErrorHandler::EventActionDefinitionsMapIsFull);
+		} else {
+			eventActionDefinitionMap.insert(std::make_pair(eventDefinitionID, temp));
+		}
 	}
 }
 
diff --git a/src/Services/ParameterService.cpp b/src/Services/ParameterService.cpp
index f951d42af3f991f6eb39c6d1073502c384100ebb..ee308a693d85d5ad269386385ee06560278603cc 100644
--- a/src/Services/ParameterService.cpp
+++ b/src/Services/ParameterService.cpp
@@ -2,7 +2,8 @@
 #ifdef SERVICE_PARAMETER
 
 #include "Services/ParameterService.hpp"
-#include "Services/Parameter.hpp"
+#include "Helpers/Parameter.hpp"
+#include "Parameters/SystemParameters.hpp"
 
 void ParameterService::reportParameters(Message& paramIds) {
 	// TM[20,2]
diff --git a/src/Services/ParameterStatisticsService.cpp b/src/Services/ParameterStatisticsService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..35c23b7cea2a2a15e6d7f759b38e01847740d5ae
--- /dev/null
+++ b/src/Services/ParameterStatisticsService.cpp
@@ -0,0 +1,207 @@
+#include <iostream>
+#include "ECSS_Configuration.hpp"
+#ifdef SERVICE_PARAMETER
+#include "Services/ParameterStatisticsService.hpp"
+
+void ParameterStatisticsService::reportParameterStatistics(Message& request) {
+	request.assertTC(ServiceType, MessageType::ReportParameterStatistics);
+	parameterStatisticsReport();
+
+	// TODO: append start time and end time to the report
+
+	if (hasAutomaticStatisticsReset) {
+		resetParameterStatistics();
+	} else {
+		bool resetFlagValue = request.readBoolean();
+		if (resetFlagValue) {
+			resetParameterStatistics();
+		}
+	}
+}
+
+void ParameterStatisticsService::parameterStatisticsReport() {
+	Message report(ServiceType, MessageType::ParameterStatisticsReport, Message::TM, 1);
+	report.appendUint16(1); // Dummy value for start and end time, will change in the end
+	report.appendUint16(1);
+	uint16_t numOfValidParameters = 0;
+
+	for (auto& currentStatistic : statisticsMap) {
+		uint16_t numOfSamples = currentStatistic.second.sampleCounter;
+		if (numOfSamples == 0) {
+			continue;
+		}
+		numOfValidParameters++;
+	}
+	report.appendUint16(numOfValidParameters);
+
+	for (auto& currentStatistic : statisticsMap) {
+		uint16_t currentId = currentStatistic.first;
+		uint16_t numOfSamples = currentStatistic.second.sampleCounter;
+		if (numOfSamples == 0) {
+			continue;
+		}
+		report.appendUint16(currentId);
+		report.appendUint16(numOfSamples);
+		currentStatistic.second.appendStatisticsToMessage(report);
+	}
+	storeMessage(report);
+}
+
+void ParameterStatisticsService::resetParameterStatistics(Message& request) {
+	request.assertTC(ServiceType, MessageType::ResetParameterStatistics);
+	resetParameterStatistics();
+}
+
+void ParameterStatisticsService::resetParameterStatistics() {
+	// TODO: Stop the evaluation of parameter statistics
+	for (auto& it : statisticsMap) {
+		it.second.resetStatistics();
+	}
+	// TODO: Restart the evaluation of parameter statistics
+}
+
+void ParameterStatisticsService::enablePeriodicStatisticsReporting(Message& request) {
+	/**
+	 * @todo: The sampling interval of each parameter. the "timeInterval" requested should not exceed it.
+	 * 		  It has to be defined as a constant.
+	 */
+	uint16_t SAMPLING_PARAMETER_INTERVAL = 5;
+
+	request.assertTC(ServiceType, MessageType::EnablePeriodicParameterReporting);
+
+	uint16_t timeInterval = request.readUint16();
+	if (timeInterval < SAMPLING_PARAMETER_INTERVAL) {
+		ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::InvalidSamplingRateError);
+		return;
+	}
+	periodicStatisticsReportingStatus = true;
+	reportingInterval = timeInterval;
+}
+
+void ParameterStatisticsService::disablePeriodicStatisticsReporting(Message& request) {
+	request.assertTC(ServiceType, MessageType::DisablePeriodicParameterReporting);
+
+	periodicStatisticsReportingStatus = false;
+	reportingInterval = 0;
+}
+
+void ParameterStatisticsService::addOrUpdateStatisticsDefinitions(Message& request) {
+	request.assertTC(ServiceType, MessageType::AddOrUpdateParameterStatisticsDefinitions);
+
+	uint16_t numOfIds = request.readUint16();
+	for (uint16_t i = 0; i < numOfIds; i++) {
+		uint16_t currentId = request.readUint16();
+		if (currentId >= systemParameters.parametersArray.size()) {
+			ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::SetNonExistingParameter);
+			if (supportsSamplingInterval) {
+				request.skipBytes(2);
+			}
+			continue;
+		}
+		bool exists = statisticsMap.find(currentId) != statisticsMap.end();
+		uint16_t interval = 0;
+		if (supportsSamplingInterval) {
+			interval = request.readUint16();
+			if (interval < reportingInterval) {
+				ErrorHandler::reportError(request, ErrorHandler::ExecutionStartErrorType::InvalidSamplingRateError);
+				continue;
+			}
+		}
+		if (not exists) {
+			if (statisticsMap.size() >= ECSS_MAX_STATISTIC_PARAMETERS) {
+				ErrorHandler::reportError(request,
+				                          ErrorHandler::ExecutionStartErrorType::MaxStatisticDefinitionsReached);
+				return;
+			}
+			Statistic newStatistic;
+			if (supportsSamplingInterval) {
+				newStatistic.setSelfSamplingInterval(interval);
+			}
+			statisticsMap.insert({currentId, newStatistic});
+			// TODO: start the evaluation of statistics for this parameter.
+		} else {
+			if (supportsSamplingInterval) {
+				statisticsMap.at(currentId).setSelfSamplingInterval(interval);
+			}
+			statisticsMap.at(currentId).resetStatistics();
+		}
+	}
+}
+
+void ParameterStatisticsService::deleteStatisticsDefinitions(Message& request) {
+	request.assertTC(ServiceType, MessageType::DeleteParameterStatisticsDefinitions);
+
+	uint16_t numOfIds = request.readUint16();
+	if (numOfIds == 0) {
+		statisticsMap.clear();
+		periodicStatisticsReportingStatus = false;
+		return;
+	}
+	for (uint16_t i = 0; i < numOfIds; i++) {
+		uint16_t currentId = request.readUint16();
+		if (currentId >= systemParameters.parametersArray.size()) {
+			ErrorHandler::reportError(request, ErrorHandler::GetNonExistingParameter);
+			continue;
+		}
+		statisticsMap.erase(currentId);
+	}
+	if (statisticsMap.empty()) {
+		periodicStatisticsReportingStatus = false;
+	}
+}
+
+void ParameterStatisticsService::reportStatisticsDefinitions(Message& request) {
+	request.assertTC(ServiceType, MessageType::ReportParameterStatisticsDefinitions);
+	statisticsDefinitionsReport();
+}
+
+void ParameterStatisticsService::statisticsDefinitionsReport() {
+	Message definitionsReport(ServiceType, MessageType::ParameterStatisticsDefinitionsReport, Message::TM, 1);
+
+	uint16_t currentReportingInterval = 0;
+	if (periodicStatisticsReportingStatus) {
+		currentReportingInterval = reportingInterval;
+	}
+	definitionsReport.appendUint16(currentReportingInterval);
+	definitionsReport.appendUint16(statisticsMap.size());
+
+	for (auto& currentParam : statisticsMap) {
+		uint16_t currentId = currentParam.first;
+		uint16_t samplingInterval = currentParam.second.selfSamplingInterval;
+		definitionsReport.appendUint16(currentId);
+		if (supportsSamplingInterval) {
+			definitionsReport.appendUint16(samplingInterval);
+		}
+	}
+	storeMessage(definitionsReport);
+}
+
+void ParameterStatisticsService::execute(Message& message) {
+	switch (message.messageType) {
+		case 1:
+			reportParameterStatistics(message);
+			break;
+		case 3:
+			resetParameterStatistics(message);
+			break;
+		case 4:
+			enablePeriodicStatisticsReporting(message);
+			break;
+		case 5:
+			disablePeriodicStatisticsReporting(message);
+			break;
+		case 6:
+			addOrUpdateStatisticsDefinitions(message);
+			break;
+		case 7:
+			deleteStatisticsDefinitions(message);
+			break;
+		case 8:
+			reportStatisticsDefinitions(message);
+			break;
+		default:
+			ErrorHandler::reportInternalError(ErrorHandler::OtherMessageType);
+	}
+}
+
+#endif
diff --git a/test/Helpers/Statistic.cpp b/test/Helpers/Statistic.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5db84a3876685ace98f57408b009d48e4eb8fb3f
--- /dev/null
+++ b/test/Helpers/Statistic.cpp
@@ -0,0 +1,84 @@
+#include "Helpers/Statistic.hpp"
+#include "Services/ParameterStatisticsService.hpp"
+#include "catch2/catch.hpp"
+
+TEST_CASE("Statistics updating function") {
+	SECTION("values in one by one") {
+		Statistic stat1;
+		CHECK(stat1.statisticsAreInitialized());
+
+		double value = 3.24;
+		stat1.updateStatistics(value);
+		CHECK(stat1.max == 3.24);
+		CHECK(stat1.min == 3.24);
+		CHECK(stat1.mean == 3.24);
+
+		value = 1.3;
+		stat1.updateStatistics(value);
+		CHECK(stat1.max == 3.24);
+		CHECK(stat1.min == 1.3);
+		CHECK(stat1.mean == Approx(2.27).epsilon(0.01));
+
+		value = 5.8;
+		stat1.updateStatistics(value);
+		CHECK(stat1.max == 5.8);
+		CHECK(stat1.min == 1.3);
+		CHECK(stat1.mean == Approx(3.446).epsilon(0.001));
+	}
+
+	SECTION("Multiple consecutive values") {
+		double values[10] = {8.3001, 2.3, 6.4, 1.1, 8.35, 3.4, 6, 8.31, 4.7, 1.09};
+		Statistic stat;
+		CHECK(stat.statisticsAreInitialized());
+		for (auto& value : values) {
+			stat.updateStatistics(value);
+		}
+		CHECK(stat.max == 8.35);
+		CHECK(stat.min == 1.09);
+		CHECK(stat.mean == Approx(4.99501).epsilon(0.00001));
+	}
+}
+
+TEST_CASE("Appending of statistics to message") {
+	SECTION("Successful appending of statistics") {
+		Message report(ParameterStatisticsService::ServiceType,
+		               ParameterStatisticsService::MessageType::ParameterStatisticsReport, Message::TM, 1);
+		double values[10] = {8.3001, 2.3, 6.4, 1.1, 8.35, 3.4, 6, 8.31, 4.7, 1.09};
+		Statistic stat;
+		CHECK(stat.statisticsAreInitialized());
+		for (auto& value : values) {
+			stat.updateStatistics(value);
+		}
+		stat.appendStatisticsToMessage(report);
+
+		REQUIRE(report.readFloat() == 8.35f);
+		REQUIRE(report.readUint32() == 0); // No CUC integration yet
+		REQUIRE(report.readFloat() == 1.09f);
+		REQUIRE(report.readUint32() == 0);
+		REQUIRE(report.readFloat() == Approx(4.99501).epsilon(0.00001));
+		REQUIRE(report.readFloat() == Approx(2.76527).epsilon(0.00001));
+	}
+}
+
+TEST_CASE("Change the value of the sampling interval") {
+	SECTION("Test the setter function") {
+		Statistic stat;
+		CHECK(stat.selfSamplingInterval == 0);
+		stat.setSelfSamplingInterval(4);
+		REQUIRE(stat.selfSamplingInterval == 4);
+	}
+}
+
+TEST_CASE("Reset statistics") {
+	SECTION("Successfully reset all the statistics of a parameter") {
+		double values[10] = {8.3001, 2.3, 6.4, 1.1, 8.35, 3.4, 6, 8.31, 4.7, 1.09};
+		Statistic stat;
+		CHECK(stat.statisticsAreInitialized());
+		for (auto& value : values) {
+			stat.updateStatistics(value);
+		}
+		CHECK(not stat.statisticsAreInitialized());
+		stat.resetStatistics();
+		REQUIRE(stat.statisticsAreInitialized());
+	}
+}
\ No newline at end of file
diff --git a/test/Message.cpp b/test/Message.cpp
index 4e1d12f56280bd21d2e122bd3544d42e716d03ea..84a0c58d2fe440b0aa5d7c1918a3608581d8145d 100644
--- a/test/Message.cpp
+++ b/test/Message.cpp
@@ -157,6 +157,15 @@ TEST_CASE("Requirement 7.3.6 (Real)", "[message][ecss]") {
 	CHECK(message.read<float>() == -9003.53135f);
 }
 
+TEST_CASE("Test appending double") {
+	Message message(0, 0, Message::TC, 0);
+	message.append<double>(2.324);
+
+	REQUIRE(message.dataSize == 8);
+
+	CHECK(message.read<double>() == Approx(2.324).epsilon(0.0001));
+}
+
 TEST_CASE("Requirement 7.3.8 (Octet-string)", "[message][ecss]") {
 	Message message(0, 0, Message::TC, 0);
 
diff --git a/test/MessageParser.cpp b/test/MessageParser.cpp
index e840b990044573bd0509c5e62777931db3614d84..325daf70304338ccda549c6cb1bf302e17192135 100644
--- a/test/MessageParser.cpp
+++ b/test/MessageParser.cpp
@@ -4,7 +4,6 @@
 #include "Helpers/CRCHelper.hpp"
 #include "MessageParser.hpp"
 
-
 TEST_CASE("TC message parsing", "[MessageParser]") {
 	uint8_t packet[] = {0x18, 0x07, 0xe0, 0x07, 0x00, 0x0a, 0x20, 0x81, 0x1f, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f};
 
@@ -19,8 +18,8 @@ TEST_CASE("TC message parsing", "[MessageParser]") {
 }
 
 TEST_CASE("TC Message parsing into a string", "[MessageParser]") {
-	uint8_t wantedPacket[] = {0x18, 0x07, 0xe0, 0x07, 0x00, 0x0a, 0x20, 0x81, 0x1f, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c,
-		0x6f};
+	uint8_t wantedPacket[] = {0x18, 0x07, 0xe0, 0x07, 0x00, 0x0a, 0x20, 0x81,
+	                          0x1f, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f};
 
 	Message message;
 	message.packetType = Message::TC;
@@ -48,7 +47,7 @@ TEST_CASE("TC Message parsing into a string", "[MessageParser]") {
 
 TEST_CASE("TM message parsing", "[MessageParser]") {
 	uint8_t packet[] = {0x08, 0x02, 0xc0, 0x4d, 0x00, 0x0c, 0x20, 0x16, 0x11,
-		0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x68, 0x69};
+	                    0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x68, 0x69};
 
 	Message message = MessageParser::parse(packet, 18);
 	CHECK(message.packetType == Message::TM);
@@ -62,7 +61,7 @@ TEST_CASE("TM message parsing", "[MessageParser]") {
 
 TEST_CASE("TM Message parsing into a string", "[MessageParser]") {
 	uint8_t wantedPacket[] = {0x08, 0x02, 0xc0, 0x4d, 0x00, 0x0c, 0x20, 0x16, 0x11,
-		0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x68, 0x69};
+	                          0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x68, 0x69};
 
 	Message message;
 	message.packetType = Message::TM;
diff --git a/test/Services/Parameter.cpp b/test/Services/Parameter.cpp
index 837be7643c39cb5021a261723bde9e5bb9d1488f..10c47ac78cebf73604199fa4aa3c4c56e6ee6fe0 100644
--- a/test/Services/Parameter.cpp
+++ b/test/Services/Parameter.cpp
@@ -1,11 +1,13 @@
+#include <iostream>
 #include "catch2/catch.hpp"
-#include "Services/Parameter.hpp"
+#include "Helpers/Parameter.hpp"
 #include "Services/ParameterService.hpp"
 #include "Message.hpp"
 
 TEST_CASE("Parameter Append") {
 	SECTION("Check correct appending") {
-		Message request = Message(ParameterService::ServiceType, ParameterService::MessageType::ReportParameterValues, Message::TC, 1);
+		Message request = Message(ParameterService::ServiceType, ParameterService::MessageType::ReportParameterValues,
+		                          Message::TC, 1);
 		auto parameter1 = Parameter<uint8_t>(1);
 		auto parameter2 = Parameter<uint16_t>(500);
 		auto parameter3 = Parameter<uint32_t>(70000);
@@ -22,7 +24,8 @@ TEST_CASE("Parameter Append") {
 
 TEST_CASE("Parameter Set") {
 	SECTION("Check correct setting") {
-		Message request = Message(ParameterService::ServiceType, ParameterService::MessageType::ReportParameterValues, Message::TC, 1);
+		Message request = Message(ParameterService::ServiceType, ParameterService::MessageType::ReportParameterValues,
+		                          Message::TC, 1);
 		auto parameter1 = Parameter<uint8_t>(1);
 		auto parameter2 = Parameter<uint16_t>(500);
 		auto parameter3 = Parameter<uint32_t>(70000);
@@ -40,3 +43,30 @@ TEST_CASE("Parameter Set") {
 		CHECK(parameter3.getValue() == 70001);
 	}
 }
+
+TEST_CASE("Get value as double") {
+	SECTION("uint8 to double") {
+		auto parameter1 = Parameter<uint8_t>(7);
+		uint8_t value = 13;
+		parameter1.setValue(value);
+		CHECK(parameter1.getValueAsDouble() == Approx(13.0).epsilon(0.1));
+	}
+	SECTION("uint16 to double") {
+		auto parameter2 = Parameter<uint32_t>(8);
+		uint16_t value = 264;
+		parameter2.setValue(value);
+		CHECK(parameter2.getValueAsDouble() == Approx(264.0).epsilon(0.1));
+	}
+	SECTION("uint32 to double") {
+		auto parameter3 = Parameter<uint32_t>(9);
+		uint32_t value = 544;
+		parameter3.setValue(value);
+		CHECK(parameter3.getValueAsDouble() == Approx(544.0).epsilon(0.1));
+	}
+	SECTION("float to double") {
+		auto parameter4 = Parameter<float>(10);
+		float value = 14.237;
+		parameter4.setValue(value);
+		CHECK(parameter4.getValueAsDouble() == Approx(14.237).epsilon(0.001));
+	}
+}
diff --git a/test/Services/ParameterStatisticsService.cpp b/test/Services/ParameterStatisticsService.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3a831c73fb6de9652c4408ee3981383cd754ec7c
--- /dev/null
+++ b/test/Services/ParameterStatisticsService.cpp
@@ -0,0 +1,385 @@
+#include <iostream>
+#include "catch2/catch.hpp"
+#include "Message.hpp"
+#include "ServiceTests.hpp"
+
+/**
+ * System-statistics initialization, so there are actual statistics in the map to work with.
+ */
+void initializeStatistics(uint16_t interval1, uint16_t interval2) {
+	Statistic stat1;
+	Statistic stat2;
+	stat1.selfSamplingInterval = interval1;
+	stat2.selfSamplingInterval = interval2;
+	uint16_t id1 = 7;
+	uint16_t id2 = 5;
+
+	int numOfSamples = 3;
+	for (int i = 0; i < numOfSamples; i++) { // Values of stat-1: [ 1, 3, 5 ]
+		stat1.updateStatistics(i * 2 + 1);
+	}
+	numOfSamples = 6;
+	for (int i = 0; i < numOfSamples; i++) { // Values of stat-2: [ 3, 5, 7, 9, 11, 13 ]
+		stat2.updateStatistics(i * 2 + 3);
+	}
+	Services.parameterStatistics.statisticsMap.insert({id1, stat1});
+	Services.parameterStatistics.statisticsMap.insert({id2, stat2});
+}
+
+void resetSystem() {
+	Services.parameterStatistics.statisticsMap.clear();
+}
+
+TEST_CASE("Reporting of statistics") {
+	SECTION("Report statistics, with auto statistic reset disabled") {
+		initializeStatistics(6, 7);
+		Message request = Message(ParameterStatisticsService::ServiceType,
+		                          ParameterStatisticsService::MessageType::ReportParameterStatistics, Message::TC, 1);
+		Services.parameterStatistics.hasAutomaticStatisticsReset = false;
+
+		MessageParser::execute(request);
+		CHECK(ServiceTests::count() == 1);
+
+		Message report = ServiceTests::get(0);
+		CHECK(report.serviceType == ParameterStatisticsService::ServiceType);
+		CHECK(report.messageType == ParameterStatisticsService::MessageType::ParameterStatisticsReport);
+		CHECK(report.readUint16() == 1); // start time
+		CHECK(report.readUint16() == 1); // end time
+		CHECK(report.readUint16() == 2); // number of parameters reported
+		// Parameter B
+		CHECK(report.readUint16() == 5); // ID-2
+		CHECK(report.readUint16() == 6); // number of samples
+		CHECK(report.readFloat() == 13); // max value
+		CHECK(report.readUint32() == 0); // max time
+		CHECK(report.readFloat() == 3); // min value
+		CHECK(report.readUint32() == 0); // min time
+		CHECK(report.readFloat() == 8); // mean
+		CHECK(report.readFloat() == Approx(3.41565).epsilon(0.01));
+		// Parameter A
+		CHECK(report.readUint16() == 7); // ID-1
+		CHECK(report.readUint16() == 3); // number of samples
+		CHECK(report.readFloat() == 5); // max value
+		CHECK(report.readUint32() == 0); // max time
+		CHECK(report.readFloat() == 1); // min value
+		CHECK(report.readUint32() == 0); // min time
+		CHECK(report.readFloat() == 3); // mean
+		CHECK(static_cast<int>(report.readFloat()) == 1); // stddev
+
+		CHECK(not Services.parameterStatistics.statisticsMap[5].statisticsAreInitialized());
+		CHECK(not Services.parameterStatistics.statisticsMap[7].statisticsAreInitialized());
+	}
+
+	SECTION("Report statistics, with auto statistics reset enabled") {
+		Message request = Message(ParameterStatisticsService::ServiceType,
+		                          ParameterStatisticsService::MessageType::ReportParameterStatistics, Message::TC, 1);
+		Services.parameterStatistics.hasAutomaticStatisticsReset = true;
+		MessageParser::execute(request);
+
+		CHECK(Services.parameterStatistics.statisticsMap[5].statisticsAreInitialized());
+		CHECK(Services.parameterStatistics.statisticsMap[7].statisticsAreInitialized());
+	}
+
+	SECTION("Report statistics, with auto statistics reset disabled, but reset is given by TC") {
+		Message request = Message(ParameterStatisticsService::ServiceType,
+		                          ParameterStatisticsService::MessageType::ReportParameterStatistics, Message::TC, 1);
+		request.appendBoolean(true);
+		Services.parameterStatistics.statisticsMap[5].mean = 5;
+		Services.parameterStatistics.statisticsMap[7].mean = 3;
+		Services.parameterStatistics.hasAutomaticStatisticsReset = false;
+
+		CHECK(not Services.parameterStatistics.statisticsMap[5].statisticsAreInitialized());
+		CHECK(not Services.parameterStatistics.statisticsMap[7].statisticsAreInitialized());
+
+		MessageParser::execute(request);
+
+		CHECK(Services.parameterStatistics.statisticsMap[5].statisticsAreInitialized());
+		CHECK(Services.parameterStatistics.statisticsMap[7].statisticsAreInitialized());
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+}
+
+TEST_CASE("Resetting the parameter statistics") {
+	SECTION("Reset via TC") {
+		initializeStatistics(6, 7);
+		Message request = Message(ParameterStatisticsService::ServiceType,
+		                          ParameterStatisticsService::MessageType::ResetParameterStatistics, Message::TC, 1);
+
+		CHECK(not Services.parameterStatistics.statisticsMap[5].statisticsAreInitialized());
+		CHECK(not Services.parameterStatistics.statisticsMap[7].statisticsAreInitialized());
+
+		MessageParser::execute(request);
+
+		CHECK(Services.parameterStatistics.statisticsMap[5].statisticsAreInitialized());
+		CHECK(Services.parameterStatistics.statisticsMap[7].statisticsAreInitialized());
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+
+	SECTION("Reset without TC") {
+		initializeStatistics(6, 7);
+
+		CHECK(not Services.parameterStatistics.statisticsMap[5].statisticsAreInitialized());
+		CHECK(not Services.parameterStatistics.statisticsMap[7].statisticsAreInitialized());
+
+		Services.parameterStatistics.resetParameterStatistics();
+
+		CHECK(Services.parameterStatistics.statisticsMap[5].statisticsAreInitialized());
+		CHECK(Services.parameterStatistics.statisticsMap[7].statisticsAreInitialized());
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+}
+
+TEST_CASE("Enable the periodic reporting of statistics") {
+	SECTION("Valid reporting interval requested") {
+		initializeStatistics(6, 7);
+		Message request =
+		    Message(ParameterStatisticsService::ServiceType,
+		            ParameterStatisticsService::MessageType::EnablePeriodicParameterReporting, Message::TC, 1);
+		request.appendUint16(6);
+		Services.parameterStatistics.periodicStatisticsReportingStatus = false;
+		CHECK(Services.parameterStatistics.reportingInterval == 5);
+
+		MessageParser::execute(request);
+		CHECK(ServiceTests::count() == 0);
+
+		CHECK(Services.parameterStatistics.periodicStatisticsReportingStatus == true);
+		CHECK(Services.parameterStatistics.reportingInterval == 6);
+	}
+
+	SECTION("Invalid reporting interval requested") {
+		Message request2 =
+		    Message(ParameterStatisticsService::ServiceType,
+		            ParameterStatisticsService::MessageType::EnablePeriodicParameterReporting, Message::TC, 1);
+		request2.appendUint16(3);
+		Services.parameterStatistics.periodicStatisticsReportingStatus = false;
+		CHECK(Services.parameterStatistics.reportingInterval == 6);
+
+		MessageParser::execute(request2);
+		CHECK(ServiceTests::count() == 1);
+		CHECK(ServiceTests::countThrownErrors(ErrorHandler::InvalidSamplingRateError) == 1);
+		CHECK(Services.parameterStatistics.periodicStatisticsReportingStatus == false);
+		CHECK(Services.parameterStatistics.reportingInterval == 6);
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+}
+
+TEST_CASE("Disabling the periodic reporting of statistics") {
+	SECTION("Successfully disable the periodic reporting") {
+		initializeStatistics(6, 7);
+		Message request =
+		    Message(ParameterStatisticsService::ServiceType,
+		            ParameterStatisticsService::MessageType::DisablePeriodicParameterReporting, Message::TC, 1);
+		Services.parameterStatistics.periodicStatisticsReportingStatus = true;
+
+		MessageParser::execute(request);
+		REQUIRE(Services.parameterStatistics.periodicStatisticsReportingStatus == false);
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+}
+
+TEST_CASE("Add/Update statistics definitions") {
+	SECTION("Update existing parameter statistic definition") {
+		initializeStatistics(7, 6);
+		Statistic newStatistic;
+		newStatistic.setSelfSamplingInterval(0);
+		Services.parameterStatistics.statisticsMap.insert({0, newStatistic});
+
+		Message request =
+		    Message(ParameterStatisticsService::ServiceType,
+		            ParameterStatisticsService::MessageType::AddOrUpdateParameterStatisticsDefinitions, Message::TC, 1);
+		uint16_t numOfIds = 1;
+		request.appendUint16(numOfIds);
+
+		uint16_t paramId1 = 0;
+		uint16_t interval1 = 14;
+		request.appendUint16(paramId1);
+		request.appendUint16(interval1);
+
+		CHECK(Services.parameterStatistics.statisticsMap.size() == 3);
+
+		MessageParser::execute(request);
+
+		REQUIRE(ServiceTests::count() == 0);
+		CHECK(Services.parameterStatistics.statisticsMap.size() == 3);
+		CHECK(Services.parameterStatistics.statisticsMap[0].selfSamplingInterval == 14);
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+
+	SECTION("Add new statistic definition") {
+		initializeStatistics(7, 6);
+		Message request =
+		    Message(ParameterStatisticsService::ServiceType,
+		            ParameterStatisticsService::MessageType::AddOrUpdateParameterStatisticsDefinitions, Message::TC, 1);
+		uint16_t numOfIds = 1;
+		request.appendUint16(numOfIds);
+
+		uint16_t paramId1 = 1;
+		uint16_t interval1 = 32;
+		request.appendUint16(paramId1);
+		request.appendUint16(interval1);
+
+		CHECK(Services.parameterStatistics.statisticsMap.size() == 2);
+
+		MessageParser::execute(request);
+
+		REQUIRE(ServiceTests::count() == 0);
+		CHECK(Services.parameterStatistics.statisticsMap.size() == 3);
+		CHECK(Services.parameterStatistics.statisticsMap[1].selfSamplingInterval == 32);
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+
+	SECTION("All possible invalid requests combined with add/update") {
+		initializeStatistics(7, 6);
+		Statistic newStatistic;
+		newStatistic.setSelfSamplingInterval(0);
+		Services.parameterStatistics.statisticsMap.insert({0, newStatistic});
+
+		Message request =
+		    Message(ParameterStatisticsService::ServiceType,
+		            ParameterStatisticsService::MessageType::AddOrUpdateParameterStatisticsDefinitions, Message::TC, 1);
+		uint16_t numOfIds = 6;
+		request.appendUint16(numOfIds);
+
+		uint16_t paramId1 = 0;
+		uint16_t paramId2 = 1;
+		uint16_t paramId3 = 2;
+		uint16_t paramId4 = 7;
+		uint16_t paramId5 = 11;
+		uint16_t paramId6 = 3;
+
+		uint16_t interval1 = 14;
+		uint16_t interval2 = 32;
+		uint16_t interval3 = 2;
+		uint16_t interval4 = 7;
+		uint16_t interval5 = 8;
+		uint16_t interval6 = 9;
+
+		request.appendUint16(paramId1);
+		request.appendUint16(interval1);
+		request.appendUint16(paramId2);
+		request.appendUint16(interval2);
+		request.appendUint16(paramId3);
+		request.appendUint16(interval3);
+		request.appendUint16(paramId4);
+		request.appendUint16(interval4);
+		request.appendUint16(paramId5);
+		request.appendUint16(interval5);
+		request.appendUint16(paramId6);
+		request.appendUint16(interval6);
+
+		CHECK(Services.parameterStatistics.statisticsMap.size() == 3);
+
+		MessageParser::execute(request);
+
+		REQUIRE(ServiceTests::count() == 4);
+		CHECK(Services.parameterStatistics.statisticsMap.size() == 4);
+		CHECK(ServiceTests::countThrownErrors(ErrorHandler::InvalidSamplingRateError) == 1);
+		CHECK(ServiceTests::countThrownErrors(ErrorHandler::SetNonExistingParameter) == 2);
+		CHECK(ServiceTests::countThrownErrors(ErrorHandler::MaxStatisticDefinitionsReached) == 1);
+		CHECK(Services.parameterStatistics.statisticsMap[0].selfSamplingInterval == 14);
+		CHECK(Services.parameterStatistics.statisticsMap[1].selfSamplingInterval == 32);
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+}
+
+TEST_CASE("Delete statistics definitions") {
+	SECTION("Delete specified definitions") {
+		Statistic stat1;
+		Statistic stat2;
+		Statistic stat3;
+		Services.parameterStatistics.statisticsMap.insert({0, stat1});
+		Services.parameterStatistics.statisticsMap.insert({1, stat2});
+		Services.parameterStatistics.statisticsMap.insert({2, stat3});
+
+		REQUIRE(Services.parameterStatistics.statisticsMap.size() == 3);
+		REQUIRE(Services.parameterStatistics.statisticsMap.find(0) != Services.parameterStatistics.statisticsMap.end());
+		REQUIRE(Services.parameterStatistics.statisticsMap.find(1) != Services.parameterStatistics.statisticsMap.end());
+		REQUIRE(Services.parameterStatistics.statisticsMap.find(2) != Services.parameterStatistics.statisticsMap.end());
+
+		Message request =
+		    Message(ParameterStatisticsService::ServiceType,
+		            ParameterStatisticsService::MessageType::DeleteParameterStatisticsDefinitions, Message::TC, 1);
+		uint16_t numIds = 2;
+		uint16_t id1 = 0;
+		uint16_t id2 = 255; // Invalid ID
+		request.appendUint16(numIds);
+		request.appendUint16(id1);
+		request.appendUint16(id2);
+
+		Services.parameterStatistics.periodicStatisticsReportingStatus = true;
+		MessageParser::execute(request);
+
+		CHECK(Services.parameterStatistics.periodicStatisticsReportingStatus == true);
+		CHECK(ServiceTests::countThrownErrors(ErrorHandler::GetNonExistingParameter) == 1);
+		CHECK(Services.parameterStatistics.statisticsMap.size() == 2);
+	}
+
+	SECTION("Delete all definitions") {
+		Message request =
+		    Message(ParameterStatisticsService::ServiceType,
+		            ParameterStatisticsService::MessageType::DeleteParameterStatisticsDefinitions, Message::TC, 1);
+		uint16_t numIds = 0;
+		request.appendUint16(numIds);
+
+		MessageParser::execute(request);
+
+		CHECK(Services.parameterStatistics.periodicStatisticsReportingStatus == false);
+		CHECK(ServiceTests::countThrownErrors(ErrorHandler::GetNonExistingParameter) == 1);
+		CHECK(Services.parameterStatistics.statisticsMap.empty());
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+}
+
+TEST_CASE("Parameter statistics definition report") {
+	SECTION("Check if the stored report is valid") {
+		initializeStatistics(0, 12);
+		REQUIRE(Services.parameterStatistics.statisticsMap.size() == 2);
+		REQUIRE(Services.parameterStatistics.statisticsMap.find(7) != Services.parameterStatistics.statisticsMap.end());
+		REQUIRE(Services.parameterStatistics.statisticsMap.find(5) != Services.parameterStatistics.statisticsMap.end());
+
+		Message request =
+		    Message(ParameterStatisticsService::ServiceType,
+		            ParameterStatisticsService::MessageType::ReportParameterStatisticsDefinitions, Message::TC, 1);
+
+		MessageParser::execute(request);
+
+		CHECK(ServiceTests::count() == 1);
+		Message report = ServiceTests::get(0);
+		CHECK(report.readUint16() == 0); // Reporting interval
+		CHECK(report.readUint16() == 2); // Num of valid Ids
+		CHECK(report.readUint16() == 5); // Valid parameter ID
+		CHECK(report.readUint16() == 12); // Sampling interval
+		CHECK(report.readUint16() == 7);
+		CHECK(report.readUint16() == 0);
+
+		resetSystem();
+		ServiceTests::reset();
+		Services.reset();
+	}
+}
diff --git a/test/TestPlatform.cpp b/test/TestPlatform.cpp
index 6833d3edeb9222d5d106f0ddf5dcac0e4f7ad5a7..68c6ecf4fbae55e9e8cf87f116c5b9fda8d83b45 100644
--- a/test/TestPlatform.cpp
+++ b/test/TestPlatform.cpp
@@ -35,7 +35,7 @@ void ErrorHandler::logError(ErrorType errorType) {
 	ServiceTests::addError(ErrorHandler::findErrorSource(errorType), errorType);
 }
 
-void Logger::log(Logger::LogLevel level, etl::istring & message) {
+void Logger::log(Logger::LogLevel level, etl::istring& message) {
 	// Logs while testing are completely ignored
 }