diff --git a/src/fsfw/serialize.h b/src/fsfw/serialize.h index edd7c9c7..514e1e0c 100644 --- a/src/fsfw/serialize.h +++ b/src/fsfw/serialize.h @@ -1,10 +1,10 @@ #ifndef FSFW_INC_FSFW_SERIALIZE_H_ #define FSFW_INC_FSFW_SERIALIZE_H_ -#include "src/core/serialize/EndianConverter.h" -#include "src/core/serialize/SerialArrayListAdapter.h" -#include "src/core/serialize/SerialBufferAdapter.h" -#include "src/core/serialize/SerialLinkedListAdapter.h" -#include "src/core/serialize/SerializeElement.h" +#include "fsfw/serialize/EndianConverter.h" +#include "fsfw/serialize/SerialArrayListAdapter.h" +#include "fsfw/serialize/SerialBufferAdapter.h" +#include "fsfw/serialize/SerialLinkedListAdapter.h" +#include "fsfw/serialize/SerializeElement.h" #endif /* FSFW_INC_FSFW_SERIALIZE_H_ */ diff --git a/src/fsfw/serialize/EndianConverter.h b/src/fsfw/serialize/EndianConverter.h index 3beae46a..dc8944ca 100644 --- a/src/fsfw/serialize/EndianConverter.h +++ b/src/fsfw/serialize/EndianConverter.h @@ -4,7 +4,7 @@ #include #include -#include "../osal/Endiness.h" +#include "fsfw/osal/Endiness.h" /** * Helper class to convert variables or bitstreams between machine @@ -36,7 +36,7 @@ */ class EndianConverter { private: - EndianConverter(){}; + EndianConverter() = default; public: /** @@ -49,8 +49,8 @@ class EndianConverter { #error BYTE_ORDER_SYSTEM not defined #elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN T tmp; - uint8_t *pointerOut = (uint8_t *)&tmp; - uint8_t *pointerIn = (uint8_t *)∈ + auto *pointerOut = reinterpret_cast(&tmp); + auto *pointerIn = reinterpret_cast(&in); for (size_t count = 0; count < sizeof(T); count++) { pointerOut[sizeof(T) - count - 1] = pointerIn[count]; } @@ -73,10 +73,8 @@ class EndianConverter { for (size_t count = 0; count < size; count++) { out[size - count - 1] = in[count]; } - return; #elif BYTE_ORDER_SYSTEM == BIG_ENDIAN memcpy(out, in, size); - return; #endif } @@ -90,8 +88,8 @@ class EndianConverter { #error BYTE_ORDER_SYSTEM not defined #elif BYTE_ORDER_SYSTEM == BIG_ENDIAN T tmp; - uint8_t *pointerOut = (uint8_t *)&tmp; - uint8_t *pointerIn = (uint8_t *)∈ + auto *pointerOut = reinterpret_cast(&tmp); + auto *pointerIn = reinterpret_cast(&in); for (size_t count = 0; count < sizeof(T); count++) { pointerOut[sizeof(T) - count - 1] = pointerIn[count]; } @@ -113,10 +111,8 @@ class EndianConverter { for (size_t count = 0; count < size; count++) { out[size - count - 1] = in[count]; } - return; #elif BYTE_ORDER_SYSTEM == LITTLE_ENDIAN memcpy(out, in, size); - return; #endif } }; diff --git a/src/fsfw/serialize/SerializeIF.h b/src/fsfw/serialize/SerializeIF.h index d806c161..5e7a2fb9 100644 --- a/src/fsfw/serialize/SerializeIF.h +++ b/src/fsfw/serialize/SerializeIF.h @@ -3,7 +3,7 @@ #include -#include "../returnvalues/HasReturnvaluesIF.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" /** * @defgroup serialize Serialization @@ -34,7 +34,7 @@ class SerializeIF { static const ReturnValue_t TOO_MANY_ELEMENTS = MAKE_RETURN_CODE(3); // !< There are too many elements to be deserialized - virtual ~SerializeIF() {} + virtual ~SerializeIF() = default; /** * @brief * Function to serialize the object into a buffer with maxSize. Size represents the written @@ -59,14 +59,28 @@ class SerializeIF { * - @c RETURN_FAILED Generic error * - @c RETURN_OK Successful serialization */ - virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, - Endianness streamEndianness) const = 0; + [[nodiscard]] virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const = 0; + /** + * Forwards to regular @serialize call with big (network) endianness + */ + [[nodiscard]] virtual ReturnValue_t serializeBe(uint8_t **buffer, size_t *size, + size_t maxSize) const { + return serialize(buffer, size, maxSize, SerializeIF::Endianness::NETWORK); + } + /** + * If endianness is not explicitly specified, use machine endianness + */ + [[nodiscard]] virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, + size_t maxSize) const { + return serialize(buffer, size, maxSize, SerializeIF::Endianness::MACHINE); + } /** * Gets the size of a object if it would be serialized in a buffer * @return Size of serialized object */ - virtual size_t getSerializedSize() const = 0; + [[nodiscard]] virtual size_t getSerializedSize() const = 0; /** * @brief @@ -90,6 +104,76 @@ class SerializeIF { */ virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, Endianness streamEndianness) = 0; + /** + * Forwards to regular @deSerialize call with big (network) endianness + */ + virtual ReturnValue_t deSerializeBe(const uint8_t **buffer, size_t *size) { + return deSerialize(buffer, size, SerializeIF::Endianness::NETWORK); + } + /** + * If endianness is not explicitly specified, use machine endianness + */ + virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size) { + return deSerialize(buffer, size, SerializeIF::Endianness::MACHINE); + } + + /** + * Helper method which can be used if serialization should be performed without any additional + * pointer arithmetic on a passed buffer pointer + * @param buffer + * @param maxSize + * @param streamEndianness + * @return + */ + [[nodiscard]] virtual ReturnValue_t serialize(uint8_t *buffer, size_t &serLen, size_t maxSize, + Endianness streamEndianness) const { + size_t tmpSize = 0; + ReturnValue_t result = serialize(&buffer, &tmpSize, maxSize, streamEndianness); + serLen = tmpSize; + return result; + } + /** + * Forwards to regular @serialize call with big (network) endianness + */ + [[nodiscard]] virtual ReturnValue_t serializeBe(uint8_t *buffer, size_t &serLen, + size_t maxSize) const { + return serialize(buffer, serLen, maxSize, SerializeIF::Endianness::NETWORK); + } + /** + * If endianness is not explicitly specified, use machine endianness + */ + [[nodiscard]] virtual ReturnValue_t serialize(uint8_t *buffer, size_t &serLen, + size_t maxSize) const { + return serialize(buffer, serLen, maxSize, SerializeIF::Endianness::MACHINE); + } + + /** + * Helper methods which can be used if deserialization should be performed without any additional + * pointer arithmetic on a passed buffer pointer + * @param buffer + * @param maxSize + * @param streamEndianness + * @return + */ + virtual ReturnValue_t deSerialize(const uint8_t *buffer, size_t &deserSize, size_t maxSize, + Endianness streamEndianness) { + size_t deserLen = maxSize; + ReturnValue_t result = deSerialize(&buffer, &deserLen, streamEndianness); + deserSize = maxSize - deserLen; + return result; + } + /** + * Forwards to regular @serialize call with big (network) endianness + */ + virtual ReturnValue_t deSerializeBe(const uint8_t *buffer, size_t &deserSize, size_t maxSize) { + return deSerialize(buffer, deserSize, maxSize, SerializeIF::Endianness::NETWORK); + } + /** + * If endianness is not explicitly specified, use machine endianness + */ + virtual ReturnValue_t deSerialize(const uint8_t *buffer, size_t &deserSize, size_t maxSize) { + return deSerialize(buffer, deserSize, maxSize, SerializeIF::Endianness::MACHINE); + } }; #endif /* FSFW_SERIALIZE_SERIALIZEIF_H_ */ diff --git a/unittests/mocks/SimpleSerializable.h b/unittests/mocks/SimpleSerializable.h new file mode 100644 index 00000000..5c28a09a --- /dev/null +++ b/unittests/mocks/SimpleSerializable.h @@ -0,0 +1,40 @@ +#ifndef FSFW_TESTS_SIMPLESERIALIZABLE_H +#define FSFW_TESTS_SIMPLESERIALIZABLE_H + +#include "fsfw/serialize.h" +#include "fsfw/osal/Endiness.h" + +class SimpleSerializable : public SerializeIF { + public: + ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, + Endianness streamEndianness) const override { + if (*size + getSerializedSize() > maxSize) { + return SerializeIF::BUFFER_TOO_SHORT; + } + **buffer = someU8; + *buffer += 1; + *size += 1; + return SerializeAdapter::serialize(&someU16, buffer, size, maxSize, streamEndianness); + } + + [[nodiscard]] size_t getSerializedSize() const override { return 3; } + ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, + Endianness streamEndianness) override { + if (*size < getSerializedSize()) { + return SerializeIF::STREAM_TOO_SHORT; + } + someU8 = **buffer; + *size -= 1; + *buffer += 1; + return SerializeAdapter::deSerialize(&someU16, buffer, size, streamEndianness); + } + + [[nodiscard]] uint8_t getU8() const { return someU8; } + [[nodiscard]] uint16_t getU16() const { return someU16; } + + private: + uint8_t someU8 = 1; + uint16_t someU16 = 0x0203; +}; + +#endif // FSFW_TESTS_SIMPLESERIALIZABLE_H diff --git a/unittests/serialize/CMakeLists.txt b/unittests/serialize/CMakeLists.txt index 96c80f4a..be4301db 100644 --- a/unittests/serialize/CMakeLists.txt +++ b/unittests/serialize/CMakeLists.txt @@ -1,5 +1,6 @@ target_sources(${FSFW_TEST_TGT} PRIVATE - TestSerialBufferAdapter.cpp - TestSerialization.cpp - TestSerialLinkedPacket.cpp + testSerialBufferAdapter.cpp + testSerializeAdapter.cpp + testSerialLinkedPacket.cpp + testSerializeIF.cpp ) diff --git a/unittests/serialize/TestSerialLinkedPacket.h b/unittests/serialize/SerialLinkedListAdapterPacket.h similarity index 80% rename from unittests/serialize/TestSerialLinkedPacket.h rename to unittests/serialize/SerialLinkedListAdapterPacket.h index 0cfdd9ff..81268d28 100644 --- a/unittests/serialize/TestSerialLinkedPacket.h +++ b/unittests/serialize/SerialLinkedListAdapterPacket.h @@ -26,13 +26,13 @@ class TestPacket : public SerialLinkedListAdapter { setLinks(); } - uint32_t getHeader() const { return header.entry; } + [[nodiscard]] uint32_t getHeader() const { return header.entry; } - const uint8_t* getBuffer() { return buffer.entry.getConstBuffer(); } + [[nodiscard]] const uint8_t* getBuffer() const { return buffer.entry.getConstBuffer(); } size_t getBufferLength() { return buffer.getSerializedSize(); } - uint16_t getTail() const { return tail.entry; } + [[nodiscard]] uint16_t getTail() const { return tail.entry; } private: void setLinks() { @@ -47,4 +47,4 @@ class TestPacket : public SerialLinkedListAdapter { SerializeElement tail = 0; }; -#endif /* UNITTEST_TESTFW_NEWTESTS_TESTTEMPLATE_H_ */ +#endif /* UNITTEST_HOSTED_TESTSERIALLINKEDPACKET_H_ */ diff --git a/unittests/serialize/TestSerialBufferAdapter.cpp b/unittests/serialize/testSerialBufferAdapter.cpp similarity index 98% rename from unittests/serialize/TestSerialBufferAdapter.cpp rename to unittests/serialize/testSerialBufferAdapter.cpp index 2aa76ec8..f9fbece1 100644 --- a/unittests/serialize/TestSerialBufferAdapter.cpp +++ b/unittests/serialize/testSerialBufferAdapter.cpp @@ -92,7 +92,7 @@ TEST_CASE("Serial Buffer Adapter", "[single-file]") { testArray[3] = 1; testArray[4] = 1; testArray[5] = 0; - std::array test_recv_array; + std::array test_recv_array{}; arrayPtr = testArray.data(); // copy testArray[1] to testArray[4] into receive buffer, skip // size field (testArray[0]) for deSerialization. @@ -116,7 +116,7 @@ TEST_CASE("Serial Buffer Adapter", "[single-file]") { testArray[3] = 1; testArray[4] = 1; testArray[5] = 0; - std::array test_recv_array; + std::array test_recv_array{}; arrayPtr = testArray.data() + 2; // copy testArray[1] to testArray[4] into receive buffer, skip // size field (testArray[0]) diff --git a/unittests/serialize/TestSerialLinkedPacket.cpp b/unittests/serialize/testSerialLinkedPacket.cpp similarity index 98% rename from unittests/serialize/TestSerialLinkedPacket.cpp rename to unittests/serialize/testSerialLinkedPacket.cpp index 2d6e476f..40910efb 100644 --- a/unittests/serialize/TestSerialLinkedPacket.cpp +++ b/unittests/serialize/testSerialLinkedPacket.cpp @@ -1,11 +1,10 @@ -#include "TestSerialLinkedPacket.h" - #include #include #include #include "CatchDefinitions.h" +#include "SerialLinkedListAdapterPacket.h" TEST_CASE("Serial Linked Packet", "[SerLinkPacket]") { // perform set-up here diff --git a/unittests/serialize/TestSerialization.cpp b/unittests/serialize/testSerializeAdapter.cpp similarity index 100% rename from unittests/serialize/TestSerialization.cpp rename to unittests/serialize/testSerializeAdapter.cpp diff --git a/unittests/serialize/testSerializeIF.cpp b/unittests/serialize/testSerializeIF.cpp new file mode 100644 index 00000000..5200f8b7 --- /dev/null +++ b/unittests/serialize/testSerializeIF.cpp @@ -0,0 +1,201 @@ + +#include +#include + +#include "mocks/SimpleSerializable.h" + +using namespace std; + +TEST_CASE("Serialize IF Serialize", "[serialize-if-ser]") { + auto simpleSer = SimpleSerializable(); + array buf{}; + uint8_t* ptr = buf.data(); + size_t len = 0; + + SECTION("Little Endian Normal") { + REQUIRE(simpleSer.serialize(&ptr, &len, buf.size(), SerializeIF::Endianness::LITTLE) == + HasReturnvaluesIF::RETURN_OK); + CHECK(buf[0] == 1); + CHECK(buf[1] == 3); + CHECK(buf[2] == 2); + // Verify pointer arithmetic and size increment + CHECK(ptr == buf.data() + 3); + CHECK(len == 3); + } + + SECTION("Little Endian Simple") { + size_t serLen = 0xff; + REQUIRE(simpleSer.SerializeIF::serialize(buf.data(), serLen, buf.size(), + SerializeIF::Endianness::LITTLE) == + HasReturnvaluesIF::RETURN_OK); + CHECK(buf[0] == 1); + CHECK(buf[1] == 3); + CHECK(buf[2] == 2); + CHECK(serLen == 3); + } + + SECTION("Big Endian Normal") { + SECTION("Explicit") { + REQUIRE(simpleSer.serialize(&ptr, &len, buf.size(), SerializeIF::Endianness::BIG) == + HasReturnvaluesIF::RETURN_OK); + } + SECTION("Network 0") { + REQUIRE(simpleSer.serialize(&ptr, &len, buf.size(), SerializeIF::Endianness::NETWORK) == + HasReturnvaluesIF::RETURN_OK); + } + SECTION("Network 1") { + REQUIRE(simpleSer.serializeBe(&ptr, &len, buf.size()) == HasReturnvaluesIF::RETURN_OK); + } + + CHECK(buf[0] == 1); + CHECK(buf[1] == 2); + CHECK(buf[2] == 3); + // Verify pointer arithmetic and size increment + CHECK(ptr == buf.data() + 3); + CHECK(len == 3); + } + + SECTION("Big Endian Simple") { + size_t serLen = 0xff; + SECTION("Explicit") { + REQUIRE(simpleSer.SerializeIF::serialize(buf.data(), serLen, buf.size(), + SerializeIF::Endianness::BIG) == + HasReturnvaluesIF::RETURN_OK); + } + SECTION("Network 0") { + REQUIRE(simpleSer.SerializeIF::serialize(buf.data(), serLen, buf.size(), + SerializeIF::Endianness::NETWORK) == + HasReturnvaluesIF::RETURN_OK); + } + SECTION("Network 1") { + REQUIRE(simpleSer.SerializeIF::serializeBe(buf.data(), serLen, buf.size()) == + HasReturnvaluesIF::RETURN_OK); + } + CHECK(buf[0] == 1); + CHECK(buf[1] == 2); + CHECK(buf[2] == 3); + CHECK(serLen == 3); + } + + SECTION("Machine Endian Implicit") { + REQUIRE(simpleSer.SerializeIF::serialize(&ptr, &len, buf.size()) == + HasReturnvaluesIF::RETURN_OK); + CHECK(buf[0] == 1); +#if BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + CHECK(buf[1] == 3); + CHECK(buf[2] == 2); +#else + CHECK(buf[1] == 2); + CHECK(buf[2] == 3); +#endif + // Verify pointer arithmetic and size increment + CHECK(ptr == buf.data() + 3); + CHECK(len == 3); + } + + SECTION("Machine Endian Simple Implicit") { + size_t serLen = 0xff; + REQUIRE(simpleSer.SerializeIF::serialize(buf.data(), serLen, buf.size()) == + HasReturnvaluesIF::RETURN_OK); + CHECK(buf[0] == 1); +#if BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + CHECK(buf[1] == 3); + CHECK(buf[2] == 2); +#else + CHECK(buf[1] == 2); + CHECK(buf[2] == 3); +#endif + CHECK(serLen == 3); + } +} + +TEST_CASE("SerializeIF Deserialize", "[serialize-if-de]") { + auto simpleSer = SimpleSerializable(); + array buf = {5, 0, 1}; + const uint8_t* ptr = buf.data(); + size_t len = buf.size(); + + SECTION("Little Endian Normal") { + REQUIRE(simpleSer.deSerialize(&ptr, &len, SerializeIF::Endianness::LITTLE) == + HasReturnvaluesIF::RETURN_OK); + CHECK(simpleSer.getU8() == 5); + CHECK(simpleSer.getU16() == 0x0100); + CHECK(ptr == buf.data() + 3); + CHECK(len == 0); + } + + SECTION("Little Endian Simple") { + size_t deserLen = 0xff; + REQUIRE( + simpleSer.SerializeIF::deSerialize(ptr, deserLen, len, SerializeIF::Endianness::LITTLE) == + HasReturnvaluesIF::RETURN_OK); + CHECK(simpleSer.getU8() == 5); + CHECK(simpleSer.getU16() == 0x0100); + CHECK(deserLen == 3); + } + + SECTION("Big Endian Normal") { + SECTION("Explicit") { + REQUIRE(simpleSer.deSerialize(&ptr, &len, SerializeIF::Endianness::BIG) == + HasReturnvaluesIF::RETURN_OK); + } + SECTION("Network 0") { + REQUIRE(simpleSer.deSerialize(&ptr, &len, SerializeIF::Endianness::NETWORK) == + HasReturnvaluesIF::RETURN_OK); + } + SECTION("Network 1") { + REQUIRE(simpleSer.SerializeIF::deSerializeBe(&ptr, &len) == HasReturnvaluesIF::RETURN_OK); + } + CHECK(simpleSer.getU8() == 5); + CHECK(simpleSer.getU16() == 1); + CHECK(ptr == buf.data() + 3); + CHECK(len == 0); + } + + SECTION("Big Endian Simple") { + size_t deserLen = 0xff; + SECTION("Explicit") { + REQUIRE(simpleSer.SerializeIF::deSerialize(buf.data(), deserLen, buf.size(), + SerializeIF::Endianness::BIG) == + HasReturnvaluesIF::RETURN_OK); + } + SECTION("Network 0") { + REQUIRE(simpleSer.SerializeIF::deSerialize(buf.data(), deserLen, buf.size(), + SerializeIF::Endianness::NETWORK) == + HasReturnvaluesIF::RETURN_OK); + } + SECTION("Network 1") { + REQUIRE(simpleSer.SerializeIF::deSerializeBe(buf.data(), deserLen, buf.size()) == + HasReturnvaluesIF::RETURN_OK); + } + CHECK(simpleSer.getU8() == 5); + CHECK(simpleSer.getU16() == 1); + CHECK(deserLen == 3); + } + + SECTION("Machine Endian Implicit") { + REQUIRE(simpleSer.SerializeIF::deSerialize(&ptr, &len) == HasReturnvaluesIF::RETURN_OK); + CHECK(simpleSer.getU8() == 5); +#if BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + CHECK(simpleSer.getU16() == 0x0100); +#else + CHECK(simpleSer.getU16() == 1); +#endif + // Verify pointer arithmetic and size increment + CHECK(ptr == buf.data() + 3); + CHECK(len == 0); + } + + SECTION("Machine Endian Simple Implicit") { + size_t deserLen = 0xff; + REQUIRE(simpleSer.SerializeIF::deSerialize(buf.data(), deserLen, buf.size()) == + HasReturnvaluesIF::RETURN_OK); + CHECK(simpleSer.getU8() == 5); +#if BYTE_ORDER_SYSTEM == LITTLE_ENDIAN + CHECK(simpleSer.getU16() == 0x0100); +#else + CHECK(simpleSer.getU16() == 1); +#endif + CHECK(deserLen == 3); + } +} \ No newline at end of file