From a5b93847ba6f8c6bdda877e0853b3e295c3241ca Mon Sep 17 00:00:00 2001 From: kongr45gpen <electrovesta@gmail.com> Date: Thu, 15 Nov 2018 01:48:35 +0200 Subject: [PATCH] Add functions to fetch data from Messages Implements #2 --- ci/.clang-tidy | 2 +- inc/ECSS_Definitions.hpp | 2 + inc/Message.hpp | 154 ++++++++++++++++++++++++++++++++++++++- src/Message.cpp | 62 ++++++++++++++++ src/main.cpp | 5 ++ 5 files changed, 223 insertions(+), 2 deletions(-) diff --git a/ci/.clang-tidy b/ci/.clang-tidy index f7f41f2c..4ce5a961 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 ffa70775..1db5923d 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 d32e6ba9..268af02f 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 47ac5575..d17eb0f5 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 5d941648..cc24193a 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; -- GitLab