diff --git a/ci/.clang-tidy b/ci/.clang-tidy
index f7f41f2c47d298f3f747b2ac1d0a1b2c5cf09be5..4ce5a961297d6a1ab3cb70979d18ef3ba15dead8 100644
--- a/ci/.clang-tidy
+++ b/ci/.clang-tidy
@@ -17,7 +17,7 @@ Checks:          >
   -misc-non-private-member-variables-in-classes,
   performance-*,
   readability-*,
-WarningsAsErrors: '*,-misc-unused-parameters,-llvm-header-guard,-cppcoreguidelines-pro-type-member-init,-google-runtime-references'
+WarningsAsErrors: '*,-misc-unused-parameters,-llvm-header-guard,-cppcoreguidelines-pro-type-member-init,-google-runtime-references,-clang-diagnostic-tautological-constant-out-of-range-compare'
 HeaderFilterRegex: '.*'
 AnalyzeTemporaryDtors: false
 ...
diff --git a/inc/ECSS_Definitions.hpp b/inc/ECSS_Definitions.hpp
index ffa707752fb49a5dc73255de90d3e13ce9f80eb6..1db5923dc5d2f3b692dc81061d993cd703edc328 100644
--- a/inc/ECSS_Definitions.hpp
+++ b/inc/ECSS_Definitions.hpp
@@ -4,6 +4,8 @@
 // Todo: Specify maximum size for regular messages
 #define ECSS_MAX_MESSAGE_SIZE 1024
 
+#define ECSS_MAX_STRING_SIZE 256
+
 // 7.4.4.1c
 #define ECSS_PUS_VERSION 2
 
diff --git a/inc/Message.hpp b/inc/Message.hpp
index d32e6ba9ed177cba93cecc447c6f543d65b82d25..268af02f6780a11e17d3a655e3fce29c96589358 100644
--- a/inc/Message.hpp
+++ b/inc/Message.hpp
@@ -7,6 +7,9 @@
 
 /**
  * A telemetry (TM) or telecommand (TC) message (request/report), as specified in ECSS-E-ST-70-41C
+ *
+ * @todo Make sure that a message can't be written to or read from at the same time, or make
+ *       readable and writable message different classes
  */
 class Message {
 public:
@@ -40,6 +43,9 @@ public:
 //private:
 	uint8_t currentBit = 0;
 
+	// Next byte to read for read...() functions
+	uint16_t readPosition = 0;
+
 	/**
 	 * Appends the least significant \p numBits from \p data to the message
 	 *
@@ -72,6 +78,36 @@ public:
 	 */
 	void appendString(uint8_t size, const char *value);
 
+	/**
+	 * Reads the next \p numBits bits from the the message in a big-endian format
+	 * @param numBits
+	 * @return A maximum number of 16 bits is returned (in big-endian format)
+	 */
+	uint16_t readBits(uint8_t numBits);
+
+	/**
+	 * Reads the next 1 byte from the message
+	 */
+	uint8_t readByte();
+
+	/**
+	 * Reads the next 2 bytes from the message
+	 */
+	uint16_t readHalfword();
+
+	/**
+	 * Reads the next 4 bytes from the message
+	 */
+	uint32_t readWord();
+
+	/**
+	 * Reads the next \p size bytes from the message, and stores them into the allocated \p string
+	 *
+	 * NOTE: We assume that \p string is already allocated, and its size is at least
+	 * ECSS_MAX_STRING_SIZE. This function does placs a \0 at the end of the created string.
+	 */
+	void readString(char *string, uint8_t size);
+
 public:
 	Message(uint8_t serviceType, uint8_t messageType, PacketType packetType,
 	        uint16_t applicationId);
@@ -190,7 +226,123 @@ public:
 		return appendWord(reinterpret_cast<uint32_t &>(value));
 	}
 
-		return appendWord(reinterpret_cast<uint32_t&>(value));
+	/**
+	 * Fetches a single-byte boolean value from the current position in the message
+	 *
+	 * PTC = 1, PFC = 0
+	 */
+	bool readBoolean() {
+		return static_cast<bool>(readByte());
+	}
+
+	/**
+	 * Fetches an enumerated parameter consisting of an arbitrary number of bits from the current
+	 * position in the message
+	 *
+	 * PTC = 2, PFC = \p bits
+	 */
+	uint32_t readEnumerated(uint8_t bits) {
+		return readBits(bits);
+	}
+
+	/**
+	 * Fetches an enumerated parameter consisting of 1 byte from the current position in the message
+	 *
+	 * PTC = 2, PFC = 8
+	 */
+	uint8_t readEnum8() {
+		return readByte();
+	}
+
+	/**
+	 * Fetches an enumerated parameter consisting of 2 bytes from the current position in the
+	 * message
+	 *
+	 * PTC = 2, PFC = 16
+	 */
+	uint16_t readEnum16() {
+		return readHalfword();
+	}
+
+	/**
+	 * Fetches an enumerated parameter consisting of 4 bytes from the current position in the
+	 * message
+	 *
+	 * PTC = 2, PFC = 32
+	 */
+	uint32_t readEnum32() {
+		return readWord();
+	}
+
+	/**
+	 * Fetches an 1-byte unsigned integer from the current position in the message
+	 *
+	 * PTC = 3, PFC = 4
+	 */
+	uint8_t readUint8() {
+		return readByte();
+	}
+
+	/**
+	 * Fetches a 2-byte unsigned integer from the current position in the message
+	 *
+	 * PTC = 3, PFC = 8
+	 */
+	uint16_t readUint16() {
+		return readHalfword();
+	}
+
+	/**
+	 * Fetches a 4-byte unsigned integer from the current position in the message
+	 *
+	 * PTC = 3, PFC = 14
+	 */
+	uint32_t readUint32() {
+		return readWord();
+	}
+
+	/**
+	 * Fetches an 1-byte signed integer from the current position in the message
+	 *
+	 * PTC = 4, PFC = 4
+	 */
+	int8_t readSint8() {
+		uint8_t value = readByte();
+		return reinterpret_cast<int8_t &>(value);
+	}
+
+	/**
+	 * Fetches a 2-byte unsigned integer from the current position in the message
+	 *
+	 * PTC = 4, PFC = 8
+	 */
+	int16_t readSint16() {
+		uint16_t value = readHalfword();
+		return reinterpret_cast<int16_t &>(value);
+	}
+
+	/**
+	 * Fetches a 4-byte unsigned integer from the current position in the message
+	 *
+	 * PTC = 4, PFC = 14
+	 */
+	int32_t readSint32() {
+		uint32_t value = readWord();
+		return reinterpret_cast<int32_t &>(value);
+	}
+
+	/**
+	 * Fetches an 4-byte single-precision floating point number from the current position in the
+	 * message
+	 *
+	 * PTC = 5, PFC = 1
+	 */
+	float readFloat() {
+		static_assert(sizeof(uint32_t) == sizeof(float),
+		              "Floating point numbers must be 32 bits long");
+
+		uint32_t value = readWord();
+		return reinterpret_cast<float &>(value);
 	}
 };
 
diff --git a/src/Message.cpp b/src/Message.cpp
index 47ac55756d15910d88a1cd4a2f2321bdfe904608..d17eb0f5c003792d37fe66975425ae15d4e7a92d 100644
--- a/src/Message.cpp
+++ b/src/Message.cpp
@@ -67,13 +67,75 @@ 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);
 
 	memcpy(data + dataSize, value, size);
 
 	dataSize += size;
 }
 
+uint16_t Message::readBits(uint8_t numBits) {
+	assert(numBits <= 16);
+	// TODO: Add assert
+
+	uint16_t value = 0x0;
+
+	while (numBits > 0) {
+		assert(readPosition < ECSS_MAX_MESSAGE_SIZE);
+
+		if (currentBit + numBits >= 8) {
+			auto bitsToAddNow = static_cast<uint8_t>(8 - currentBit);
+
+			auto maskedData = static_cast<uint8_t>(data[readPosition] & ((1 << bitsToAddNow) - 1));
+			value |= maskedData << (numBits - bitsToAddNow);
+
+			numBits -= bitsToAddNow;
+			currentBit = 0;
+			readPosition++;
+		} else {
+			value |= (data[readPosition] >> (8 - currentBit - numBits)) & ((1 << numBits) - 1);
+			currentBit = currentBit + numBits;
+			numBits = 0;
+		}
+	}
+
+	return value;
+}
+
+uint8_t Message::readByte() {
+	assert(readPosition < ECSS_MAX_MESSAGE_SIZE);
+
+	uint8_t value = data[readPosition];
+	readPosition++;
+
+	return value;
+}
+
+uint16_t Message::readHalfword() {
+	assert(readPosition + 2 < ECSS_MAX_MESSAGE_SIZE);
+
+	uint16_t value = (data[readPosition] << 8) | data[readPosition + 1];
+	readPosition += 2;
 
 	return value;
 }
 
+uint32_t Message::readWord() {
+	assert(readPosition + 4 < ECSS_MAX_MESSAGE_SIZE);
+
+	uint32_t value = (data[readPosition] << 24) | (data[readPosition + 1] << 16) |
+	                 (data[readPosition + 2] << 8) | data[readPosition + 3];
+	readPosition += 4;
+
+	return value;
+}
+
+void Message::readString(char *string, uint8_t size) {
+	assert(readPosition + size <= ECSS_MAX_MESSAGE_SIZE);
+	assert(size < ECSS_MAX_STRING_SIZE);
+
+	memcpy(string, data + readPosition, size);
+	string[size] = '\0';
+
+	readPosition += size;
+}
diff --git a/src/main.cpp b/src/main.cpp
index 5d94164819c2a6c5954faa2ca7916cdbd6b09350..cc24193a9f71cec7719e7ce55e85cecf1e3aa968 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -9,10 +9,15 @@ int main() {
 	packet.appendBits(15, 0x28a8);
 	packet.appendBits(1, 1);
 	packet.appendFloat(5.7);
+	packet.appendSint32(-123456789);
 
 	std::cout << "Hello, World!" << std::endl;
 	std::cout << std::hex << packet.data << std::endl; // packet data must be 'helloQQ'
 
+	char string[6];
+	packet.readString(string, 5);
+	std::cout << "Word: " << string << " " << packet.readBits(15) << packet.readBits(1) << std::endl;
+	std::cout << packet.readFloat() << " " << std::dec << packet.readSint32() << std::endl;
 
 	// ST[17] test
 	TestService testService;