diff --git a/container/FixedArrayList.h b/container/FixedArrayList.h index eeffcc870..5d93db90c 100644 --- a/container/FixedArrayList.h +++ b/container/FixedArrayList.h @@ -2,18 +2,44 @@ #define FIXEDARRAYLIST_H_ #include + /** - * \ingroup container + * @brief Array List with a fixed maximum size + * @ingroup container */ template class FixedArrayList: public ArrayList { private: T data[MAX_SIZE]; public: + /** + * (Robin) Maybe we should also implement move assignment and move ctor. + * Or at least delete them. + */ FixedArrayList() : ArrayList(data, MAX_SIZE) { } + // (Robin): We could create a constructor to initialize the fixed array list with data and the known size field + // so it can be used for serialization too (with SerialFixedArrrayListAdapter) + // is this feasible? + /** + * Initialize a fixed array list with data and number of data fields. + * Endianness of entries can be swapped optionally. + * @param data_ + * @param count + * @param swapArrayListEndianess + */ + FixedArrayList(T * data_, count_t count, + bool swapArrayListEndianess = false): + ArrayList(data, MAX_SIZE) { + memcpy(this->data, data_, count * sizeof(T)); + this->size = count; + if(swapArrayListEndianess) { + ArrayList::swapArrayListEndianness(); + } + } + FixedArrayList(const FixedArrayList& other) : ArrayList(data, MAX_SIZE) { memcpy(this->data, other.data, sizeof(this->data)); diff --git a/serialize/SerialArrayListAdapter.h b/serialize/SerialArrayListAdapter.h index 5ffbc3757..4f3b82e68 100644 --- a/serialize/SerialArrayListAdapter.h +++ b/serialize/SerialArrayListAdapter.h @@ -12,7 +12,8 @@ #include /** - * \ingroup serialize + * Also serializes length field ! + * @ingroup serialize */ template class SerialArrayListAdapter : public SerializeIF { @@ -20,13 +21,15 @@ public: SerialArrayListAdapter(ArrayList *adaptee) : adaptee(adaptee) { } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override { return serialize(adaptee, buffer, size, max_size, bigEndian); } - static ReturnValue_t serialize(const ArrayList* list, uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) { + static ReturnValue_t serialize(const ArrayList* list, + uint8_t** buffer, size_t* size, const size_t max_size, + bool bigEndian) { + // Serialize length field first ReturnValue_t result = SerializeAdapter::serialize(&list->size, buffer, size, max_size, bigEndian); count_t i = 0; @@ -38,7 +41,7 @@ public: return result; } - virtual uint32_t getSerializedSize() const { + virtual size_t getSerializedSize() const override { return getSerializedSize(adaptee); } @@ -53,16 +56,19 @@ public: return printSize; } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, - bool bigEndian) { + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override { return deSerialize(adaptee, buffer, size, bigEndian); } - static ReturnValue_t deSerialize(ArrayList* list, const uint8_t** buffer, int32_t* size, - bool bigEndian) { + static ReturnValue_t deSerialize(ArrayList* list, + const uint8_t** buffer, size_t* size, bool bigEndian) { count_t tempSize = 0; ReturnValue_t result = SerializeAdapter::deSerialize(&tempSize, buffer, size, bigEndian); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } if (tempSize > list->maxSize()) { return SerializeIF::TOO_MANY_ELEMENTS; } @@ -76,6 +82,11 @@ public: } return result; } + + + static void swapArrayListEndianness(ArrayList* list) { + list->swapArrayListEndianness(); + } private: ArrayList *adaptee; }; diff --git a/serialize/SerialBufferAdapter.cpp b/serialize/SerialBufferAdapter.cpp index 3ed083bf5..5fb5e3873 100644 --- a/serialize/SerialBufferAdapter.cpp +++ b/serialize/SerialBufferAdapter.cpp @@ -1,29 +1,33 @@ #include +#include #include +template +SerialBufferAdapter::SerialBufferAdapter(const void* buffer, + count_t bufferLength, bool serializeLength) : + serializeLength(serializeLength), + constBuffer(static_cast(buffer)), m_buffer(nullptr), + bufferLength(bufferLength) { - -template -SerialBufferAdapter::SerialBufferAdapter(const uint8_t* buffer, - T bufferLength, bool serializeLenght) : - serializeLength(serializeLenght), constBuffer(buffer), buffer(NULL), bufferLength( - bufferLength) { } -template -SerialBufferAdapter::SerialBufferAdapter(uint8_t* buffer, T bufferLength, - bool serializeLenght) : - serializeLength(serializeLenght), constBuffer(NULL), buffer(buffer), bufferLength( - bufferLength) { +template +SerialBufferAdapter::SerialBufferAdapter(void* buffer, + count_t bufferLength, bool serializeLength) : + serializeLength(serializeLength), bufferLength(bufferLength) { + uint8_t * member_buffer = static_cast(buffer); + m_buffer = member_buffer; + constBuffer = member_buffer; } -template -SerialBufferAdapter::~SerialBufferAdapter() { + +template +SerialBufferAdapter::~SerialBufferAdapter() { } -template -ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { +template +ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, + size_t* size, const size_t max_size, bool bigEndian) const { uint32_t serializedLength = bufferLength; if (serializeLength) { serializedLength += AutoSerializeAdapter::getSerializedSize( @@ -36,10 +40,10 @@ ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, uint32_t* size AutoSerializeAdapter::serialize(&bufferLength, buffer, size, max_size, bigEndian); } - if (this->constBuffer != NULL) { - memcpy(*buffer, this->constBuffer, bufferLength); - } else if (this->buffer != NULL) { - memcpy(*buffer, this->buffer, bufferLength); + if (constBuffer != nullptr) { + memcpy(*buffer, constBuffer, bufferLength); + } else if (m_buffer != nullptr) { + memcpy(*buffer, m_buffer, bufferLength); } else { return HasReturnvaluesIF::RETURN_FAILED; } @@ -49,43 +53,77 @@ ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, uint32_t* size } } -template -uint32_t SerialBufferAdapter::getSerializedSize() const { +template +size_t SerialBufferAdapter::getSerializedSize() const { if (serializeLength) { return bufferLength + AutoSerializeAdapter::getSerializedSize(&bufferLength); } else { return bufferLength; } } -template -ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, - int32_t* size, bool bigEndian) { + +template +ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, + size_t* size, bool bigEndian) { //TODO Ignores Endian flag! - if (buffer != NULL) { - if(serializeLength){ - T serializedSize = AutoSerializeAdapter::getSerializedSize( + // (Robin) the one of the buffer? wouldn't that be an issue for serialize + // as well? SerialFixedArrayListAdapter implements swapping of buffer + // fields (if buffer type is not uint8_t) + if (buffer != nullptr) { + if(serializeLength) { + count_t serializedSize = AutoSerializeAdapter::getSerializedSize( &bufferLength); - if((*size - bufferLength - serializedSize) >= 0){ + if(bufferLength + serializedSize >= *size) { *buffer += serializedSize; *size -= serializedSize; - }else{ + } + else { return STREAM_TOO_SHORT; } } //No Else If, go on with buffer - if (*size - bufferLength >= 0) { + if (bufferLength >= *size) { *size -= bufferLength; - memcpy(this->buffer, *buffer, bufferLength); + memcpy(m_buffer, *buffer, bufferLength); (*buffer) += bufferLength; return HasReturnvaluesIF::RETURN_OK; - } else { + } + else { return STREAM_TOO_SHORT; } - } else { + } + else { return HasReturnvaluesIF::RETURN_FAILED; } } +template +uint8_t * SerialBufferAdapter::getBuffer() { + if(m_buffer == nullptr) { + error << "Wrong access function for stored type !" + " Use getConstBuffer()" << std::endl; + return nullptr; + } + return m_buffer; +} + +template +const uint8_t * SerialBufferAdapter::getConstBuffer() { + if(constBuffer == nullptr) { + error << "Wrong access function for stored type !" + " Use getBuffer()" << std::endl; + return nullptr; + } + return constBuffer; +} + +template +void SerialBufferAdapter::setBuffer(void * buffer, + count_t buffer_length) { + m_buffer = static_cast(buffer); + bufferLength = buffer_length; +} + //forward Template declaration for linker template class SerialBufferAdapter; diff --git a/serialize/SerialBufferAdapter.h b/serialize/SerialBufferAdapter.h index 7cd75d556..d414573cb 100644 --- a/serialize/SerialBufferAdapter.h +++ b/serialize/SerialBufferAdapter.h @@ -5,31 +5,73 @@ #include /** + * This adapter provides an interface for SerializeIF to serialize or deserialize + * buffers with no length header but a known size. + * + * Additionally, the buffer length can be serialized too and will be put in + * front of the serialized buffer. + * + * Can be used with SerialLinkedListAdapter by declaring a SerializeElement with + * SerialElement>. + * Right now, the SerialBufferAdapter must always + * be initialized with the buffer and size ! + * * \ingroup serialize */ -template +template class SerialBufferAdapter: public SerializeIF { public: - SerialBufferAdapter(const uint8_t * buffer, T bufferLength, bool serializeLenght = false); - SerialBufferAdapter(uint8_t* buffer, T bufferLength, - bool serializeLenght = false); + + /** + * Constructor for constant uint8_t buffer. Length field can be serialized optionally. + * Type of length can be supplied as template type. + * @param buffer + * @param bufferLength + * @param serializeLength + */ + SerialBufferAdapter(const void* buffer, count_t bufferLength, + bool serializeLength = false); + + /** + * Constructor for non-constant uint8_t buffer. + * Length field can be serialized optionally. + * Type of length can be supplied as template type. + * @param buffer + * @param bufferLength + * @param serializeLength Length field will be serialized with size count_t + */ + SerialBufferAdapter(void* buffer, count_t bufferLength, bool serializeLength = false); virtual ~SerialBufferAdapter(); - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const; + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override; - virtual uint32_t getSerializedSize() const; + virtual size_t getSerializedSize() const; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, - bool bigEndian); + /** + * @brief This function deserializes a buffer into the member buffer. + * @details + * If a length field is present, it is ignored, as the size should have + * been set in the constructor. If the size is not known beforehand, + * consider using SerialFixedArrayListAdapter instead. + * @param buffer [out] Resulting buffer + * @param size remaining size to deserialize, should be larger than buffer + * + size field size + * @param bigEndian + * @return + */ + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override; + + uint8_t * getBuffer(); + const uint8_t * getConstBuffer(); + void setBuffer(void* buffer_, count_t bufferLength_); private: - bool serializeLength; - const uint8_t *constBuffer; - uint8_t *buffer; - T bufferLength; + bool serializeLength = false; + const uint8_t *constBuffer = nullptr; + uint8_t *m_buffer = nullptr; + count_t bufferLength = 0; }; - - #endif /* SERIALBUFFERADAPTER_H_ */ diff --git a/serialize/SerialFixedArrayListAdapter.h b/serialize/SerialFixedArrayListAdapter.h index 16919b623..6e13ff6f4 100644 --- a/serialize/SerialFixedArrayListAdapter.h +++ b/serialize/SerialFixedArrayListAdapter.h @@ -5,24 +5,62 @@ #include /** - * \ingroup serialize + * @brief This adapter provides an interface for SerializeIF to serialize and + * deserialize buffers with a header containing the buffer length. + * @details + * Can be used by SerialLinkedListAdapter by declaring + * as a linked element with SerializeElement>. + * The sequence of objects is defined in the constructor by + * using the setStart and setNext functions. + * + * 1. Buffers with a size header inside that class can be declared with + * @code + * SerialFixedArrayListAdapter mySerialFixedArrayList(...). + * @endcode + * 2. MAX_BUFFER_LENGTH specifies the maximum allowed number of elements + * in FixedArrayList. + * 3. LENGTH_FIELD_TYPE specifies the data type of the buffer header + * containing the buffer size (defaults to 1 byte length field) + * that follows. + * + * @ingroup serialize */ -template -class SerialFixedArrayListAdapter : public FixedArrayList, public SerializeIF { +template +class SerialFixedArrayListAdapter : + public FixedArrayList, + public SerializeIF { public: + /** + * Constructor Arguments are forwarded to FixedArrayList constructor. + * Refer to the fixed array list constructors for different options. + * @param args + */ template - SerialFixedArrayListAdapter(Args... args) : FixedArrayList(std::forward(args)...) { + SerialFixedArrayListAdapter(Args... args) : + FixedArrayList(std::forward(args)...) + {} + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override { + return SerialArrayListAdapter::serialize(this, + buffer, size, max_size, bigEndian); } - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - return SerialArrayListAdapter::serialize(this, buffer, size, max_size, bigEndian); + + size_t getSerializedSize() const { + return SerialArrayListAdapter:: + getSerializedSize(this); } - uint32_t getSerializedSize() const { - return SerialArrayListAdapter::getSerializedSize(this); + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override { + return SerialArrayListAdapter::deSerialize(this, + buffer, size, bigEndian); } - ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, - bool bigEndian) { - return SerialArrayListAdapter::deSerialize(this, buffer, size, bigEndian); + + void swapArrayListEndianness() { + SerialArrayListAdapter:: + swapArrayListEndianness(this); } }; diff --git a/serialize/SerialLinkedListAdapter.h b/serialize/SerialLinkedListAdapter.h index 29952c4a3..8cb9afc8b 100644 --- a/serialize/SerialLinkedListAdapter.h +++ b/serialize/SerialLinkedListAdapter.h @@ -13,26 +13,73 @@ #include //This is where we need the SerializeAdapter! -/** - * \ingroup serialize + /** + * @brief Implement the conversion of object data to data streams + * or vice-versa, using linked lists. + * @details + * An alternative to the AutoSerializeAdapter functions + * - All object members with a datatype are declared as + * SerializeElement members inside the class + * implementing this adapter. + * - The element type can also be a SerialBufferAdapter to + * de-/serialize buffers with a known size + * - The element type can also be a SerialFixedArrayListAdapter to + * de-/serialize buffers with a size header, which is scanned automatically. + * + * The sequence of objects is defined in the constructor by using + * the setStart and setNext functions. + * + * 1. The serialization process is done by instantiating the class and + * calling serialize after all SerializeElement entries have been set by + * using the constructor or setter functions. An additional size variable + * can be supplied which is calculated/incremented automatically. + * 2. The deserialization process is done by instantiating the class and + * supplying a buffer with the data which is converted into an object. + * The size of data to serialize can be supplied and is + * decremented in the function. Range checking is done internally. + * + * @ingroup serialize */ template class SerialLinkedListAdapter: public SinglyLinkedList, public SerializeIF { public: + /** + * Copying is forbidden by deleting the copy constructor and the copy + * assignment operator because of the pointers to the linked list members. + * Unless the child class implements an own copy constructor or + * copy assignment operator, these operation will throw a compiler error. + * @param + */ + SerialLinkedListAdapter(const SerialLinkedListAdapter &) = delete; + SerialLinkedListAdapter& operator=(const SerialLinkedListAdapter&) = delete; + SerialLinkedListAdapter(typename LinkedElement::Iterator start, bool printCount = false) : SinglyLinkedList(start), printCount(printCount) { } + SerialLinkedListAdapter(LinkedElement* first, bool printCount = false) : SinglyLinkedList(first), printCount(printCount) { } + SerialLinkedListAdapter(bool printCount = false) : SinglyLinkedList(), printCount(printCount) { } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { + /** + * Serialize object implementing this adapter into the supplied buffer + * and calculate the serialized size + * @param buffer [out] Object is serialized into this buffer. + * Note that the buffer pointer *buffer is incremented automatically + * inside the respective serialize functions + * @param size [out] Calculated serialized size. Don't forget to set to 0. + * @param max_size + * @param bigEndian Specify endianness + * @return + */ + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override{ if (printCount) { count_t mySize = SinglyLinkedList::getSize(); ReturnValue_t result = SerializeAdapter::serialize(&mySize, @@ -46,7 +93,7 @@ public: } static ReturnValue_t serialize(const LinkedElement* element, - uint8_t** buffer, uint32_t* size, const uint32_t max_size, + uint8_t** buffer, size_t* size, const size_t max_size, bool bigEndian) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { @@ -56,7 +103,9 @@ public: } return result; } - virtual uint32_t getSerializedSize() const { + + + virtual size_t getSerializedSize() const override { if (printCount) { return SerialLinkedListAdapter::getSerializedSize() + sizeof(count_t); @@ -64,6 +113,7 @@ public: return getSerializedSize(SinglyLinkedList::start); } } + static uint32_t getSerializedSize(const LinkedElement *element) { uint32_t size = 0; while (element != NULL) { @@ -73,13 +123,22 @@ public: return size; } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, - bool bigEndian) { + + /** + * Deserialize supplied buffer with supplied size into object + * implementing this adapter. + * @param buffer + * @param size Decremented in respective deSerialize functions automatically + * @param bigEndian Specify endianness + * @return + */ + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override { return deSerialize(SinglyLinkedList::start, buffer, size, bigEndian); } static ReturnValue_t deSerialize(LinkedElement* element, - const uint8_t** buffer, int32_t* size, bool bigEndian) { + const uint8_t** buffer, size_t* size, bool bigEndian) { ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { result = element->value->deSerialize(buffer, size, bigEndian); @@ -89,7 +148,6 @@ public: } bool printCount; - }; #endif /* SERIALLINKEDLISTADAPTER_H_ */ diff --git a/serialize/SerializeAdapter.h b/serialize/SerializeAdapter.h index fd9e1b6af..87e4457ae 100644 --- a/serialize/SerializeAdapter.h +++ b/serialize/SerializeAdapter.h @@ -1,82 +1,86 @@ #ifndef SERIALIZEADAPTER_H_ #define SERIALIZEADAPTER_H_ -#include #include -#include #include -#include +#include +#include -/** - * \ingroup serialize + /** + * @brief These adapters provides an interface to use the SerializeIF functions + * with arbitrary template objects to facilitate and simplify the + * serialization of classes with different multiple different data types + * into buffers and vice-versa. + * @details + * + * A report class is converted into a TM buffer. The report class implements a + * serialize functions and calls the AutoSerializeAdapter::serialize function + * repeatedly on all object data fields. The getSerializedSize function is + * implemented by calling the AutoSerializeAdapter::getSerializedSize function + * repeatedly on all data fields. + * + * The AutoSerializeAdapter functions can also be used as an alternative to + * memcpy to retrieve data out of a buffer directly into a class variable + * with data type T while being able to specify endianness. The boolean + * bigEndian specifies whether an endian swap is performed on the data before + * serialization or deserialization. + * + * There are three ways to retrieve data out of a buffer to be used in the FSFW + * to use regular aligned (big endian) data. Examples: + * + * 1. Use the AutoSerializeAdapter::deSerialize function + * The pointer *buffer will be incremented automatically by the typeSize + * of the object, so this function can be called on &buffer repeatedly + * without adjusting pointer position. Set bigEndian parameter to true + * to perform endian swapping, if necessary + * @code + * uint16_t data; + * int32_t dataLen = sizeof(data); + * ReturnValue_t result = + * AutoSerializeAdapter::deSerialize(&data,&buffer,&dataLen,true); + * @endcode + * + * 2. Perform a bitshift operation. Watch for for endianness: + * @code + * uint16_t data; + * data = buffer[targetByte1] << 8 | buffer[targetByte2]; + * data = EndianSwapper::swap(data); //optional, or swap order above + * @endcode + * + * 3. memcpy or std::copy can also be used, but watch out if system + * endianness is different from required data endianness. + * Perform endian-swapping if necessary. + * @code + * uint16_t data; + * memcpy(&data,buffer + positionOfTargetByte1,sizeof(data)); + * data = EndianSwapper::swap(data); //optional + * @endcode + * + * When serializing for downlink, the packets are generally serialized assuming + * big endian data format like seen in TmPacketStored.cpp for example. + * + * @ingroup serialize */ -template -class SerializeAdapter_ { + +// No type specification necessary here. +class AutoSerializeAdapter { public: + template static ReturnValue_t serialize(const T* object, uint8_t** buffer, - uint32_t* size, const uint32_t max_size, bool bigEndian) { - uint32_t ignoredSize = 0; - if (size == NULL) { - size = &ignoredSize; - } - if (sizeof(T) + *size <= max_size) { - T tmp; - if (bigEndian) { - tmp = EndianSwapper::swap(*object); - } else { - tmp = *object; - } - memcpy(*buffer, &tmp, sizeof(T)); - *size += sizeof(T); - (*buffer) += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } + size_t* size, const size_t max_size, bool bigEndian) { + SerializeAdapter_::Is> adapter; + return adapter.serialize(object, buffer, size, max_size, bigEndian); } - - ReturnValue_t deSerialize(T* object, const uint8_t** buffer, int32_t* size, - bool bigEndian) { - T tmp; - *size -= sizeof(T); - if (*size >= 0) { - memcpy(&tmp, *buffer, sizeof(T)); - if (bigEndian) { - *object = EndianSwapper::swap(tmp); - } else { - *object = tmp; - } - *buffer += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::STREAM_TOO_SHORT; - } + template + static size_t getSerializedSize(const T* object) { + SerializeAdapter_::Is> adapter; + return adapter.getSerializedSize(object); } - - uint32_t getSerializedSize(const T * object) { - return sizeof(T); - } - -}; - -template -class SerializeAdapter_ { -public: - ReturnValue_t serialize(const T* object, uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - uint32_t ignoredSize = 0; - if (size == NULL) { - size = &ignoredSize; - } - return object->serialize(buffer, size, max_size, bigEndian); - } - uint32_t getSerializedSize(const T* object) const { - return object->getSerializedSize(); - } - - ReturnValue_t deSerialize(T* object, const uint8_t** buffer, int32_t* size, - bool bigEndian) { - return object->deSerialize(buffer, size, bigEndian); + template + static ReturnValue_t deSerialize(T* object, const uint8_t** buffer, + size_t* size, bool bigEndian) { + SerializeAdapter_::Is> adapter; + return adapter.deSerialize(object, buffer, size, bigEndian); } }; @@ -84,7 +88,7 @@ template class SerializeAdapter { public: static ReturnValue_t serialize(const T* object, uint8_t** buffer, - uint32_t* size, const uint32_t max_size, bool bigEndian) { + size_t* size, const size_t max_size, bool bigEndian) { SerializeAdapter_::Is> adapter; return adapter.serialize(object, buffer, size, max_size, bigEndian); } @@ -94,29 +98,7 @@ public: } static ReturnValue_t deSerialize(T* object, const uint8_t** buffer, - int32_t* size, bool bigEndian) { - SerializeAdapter_::Is> adapter; - return adapter.deSerialize(object, buffer, size, bigEndian); - } -}; - - -class AutoSerializeAdapter { -public: - template - static ReturnValue_t serialize(const T* object, uint8_t** buffer, - uint32_t* size, const uint32_t max_size, bool bigEndian) { - SerializeAdapter_::Is> adapter; - return adapter.serialize(object, buffer, size, max_size, bigEndian); - } - template - static uint32_t getSerializedSize(const T* object) { - SerializeAdapter_::Is> adapter; - return adapter.getSerializedSize(object); - } - template - static ReturnValue_t deSerialize(T* object, const uint8_t** buffer, - int32_t* size, bool bigEndian) { + size_t* size, bool bigEndian) { SerializeAdapter_::Is> adapter; return adapter.deSerialize(object, buffer, size, bigEndian); } diff --git a/serialize/SerializeAdapterInternal.h b/serialize/SerializeAdapterInternal.h new file mode 100644 index 000000000..c57af0c95 --- /dev/null +++ b/serialize/SerializeAdapterInternal.h @@ -0,0 +1,118 @@ +/** + * @file SerializeAdapterInternal.h + * + * @date 13.04.2020 + * @author R. Mueller + */ + +#ifndef FRAMEWORK_SERIALIZE_SERIALIZEADAPTERINTERNAL_H_ +#define FRAMEWORK_SERIALIZE_SERIALIZEADAPTERINTERNAL_H_ +#include +#include +#include + +/** + * This template specialization will be chosen for fundamental types or + * anything else not implementing SerializeIF, based on partial + * template specialization. + * @tparam T + * @tparam + */ +template +class SerializeAdapter_ { +public: + /** + * + * @param object + * @param buffer + * @param size + * @param max_size + * @param bigEndian + * @return + */ + static ReturnValue_t serialize(const T* object, uint8_t** buffer, + size_t* size, const size_t max_size, bool bigEndian) { + // function eventuelly serializes structs here. + // does this work on every architecture? + // static_assert(std::is_fundamental::value); + size_t ignoredSize = 0; + if (size == nullptr) { + size = &ignoredSize; + } + if (sizeof(T) + *size <= max_size) { + T tmp; + if (bigEndian) { + tmp = EndianSwapper::swap(*object); + } else { + tmp = *object; + } + memcpy(*buffer, &tmp, sizeof(T)); + *size += sizeof(T); + (*buffer) += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } + } + + /** + * Deserialize buffer into object + * @param object [out] Object to be deserialized with buffer data + * @param buffer contains the data. Non-Const pointer to non-const + * pointer to const data. + * @param size Size to deSerialize. wil be decremented by sizeof(T) + * @param bigEndian Specify endianness + * @return + */ + ReturnValue_t deSerialize(T* object, const uint8_t** buffer, size_t* size, + bool bigEndian) { + T tmp; + if (*size >= sizeof(T)) { + *size -= sizeof(T); + memcpy(&tmp, *buffer, sizeof(T)); + if (bigEndian) { + *object = EndianSwapper::swap(tmp); + } else { + *object = tmp; + } + *buffer += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::STREAM_TOO_SHORT; + } + } + + size_t getSerializedSize(const T * object) { + return sizeof(T); + } +}; + +/** + * This template specialization will be chosen for class derived from + * SerializeIF, based on partial template specialization. + * @tparam T + * @tparam + */ +template +class SerializeAdapter_ { +public: + ReturnValue_t serialize(const T* object, uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + size_t ignoredSize = 0; + if (size == NULL) { + size = &ignoredSize; + } + return object->serialize(buffer, size, max_size, bigEndian); + } + + size_t getSerializedSize(const T* object) const { + return object->getSerializedSize(); + } + + ReturnValue_t deSerialize(T* object, const uint8_t** buffer, size_t* size, + bool bigEndian) { + return object->deSerialize(buffer, size, bigEndian); + } +}; + +#endif /* FRAMEWORK_SERIALIZE_SERIALIZEADAPTERINTERNAL_H_ */ diff --git a/serialize/SerializeElement.h b/serialize/SerializeElement.h index db7db20a9..4717ae17f 100644 --- a/serialize/SerializeElement.h +++ b/serialize/SerializeElement.h @@ -6,31 +6,47 @@ #include /** - * \ingroup serialize + * @brief This class is used to mark datatypes for serialization with the + * SerialLinkedListAdapter + * @details + * Used by declaring any arbitrary datatype with SerializeElement myVariable, + * inside a SerialLinkedListAdapter implementation and setting the sequence + * of objects with setNext() and setStart(). + * Serilization and Deserialization is then performed automatically in + * specified sequence order. + * @ingroup serialize */ template class SerializeElement : public SerializeIF, public LinkedElement { public: + /** + * Arguments are forwarded to the element datatype constructor + * @param args + */ template - SerializeElement(Args... args) : LinkedElement(this), entry(std::forward(args)...) { + SerializeElement(Args... args): + LinkedElement(this), + entry(std::forward(args)...) {} + + SerializeElement() : LinkedElement(this) {} - } - SerializeElement() : LinkedElement(this) { - } T entry; - ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const { - return SerializeAdapter::serialize(&entry, buffer, size, max_size, bigEndian); + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const override { + return SerializeAdapter::serialize(&entry, buffer, size, + max_size, bigEndian); } - uint32_t getSerializedSize() const { + size_t getSerializedSize() const { return SerializeAdapter::getSerializedSize(&entry); } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, - bool bigEndian) { + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + bool bigEndian) override { return SerializeAdapter::deSerialize(&entry, buffer, size, bigEndian); } + operator T() { return entry; } diff --git a/serialize/SerializeIF.h b/serialize/SerializeIF.h index 701fbf563..5f8102c86 100644 --- a/serialize/SerializeIF.h +++ b/serialize/SerializeIF.h @@ -2,15 +2,34 @@ #define SERIALIZEIF_H_ #include +#include /** - * \defgroup serialize Serialization + * @defgroup serialize Serialization * Contains serialisation services. */ /** - * Translation of objects into data streams. - * \ingroup serialize + * @brief An interface for alle classes which require + * translation of objects data into data streams and vice-versa. + * @details + * If the target architecture is little endian (e.g. ARM), any data types + * created might have the wrong endianess if they are to be used for the FSFW. + * Depending on the system architecture, endian correctness must be assured, + * This is important for incoming and outgoing data. The internal handling + * of data should be performed in the native system endianness. + * There are three ways to copy data (with different options to ensure + * endian correctness): + * + * 1. Use the @c AutoSerializeAdapter::deSerialize function (with + * the endian flag) + * 2. Perform a bitshift operation (with correct order) + * 3. @c memcpy (with @c EndianSwapper if necessary) + * + * When serializing for downlink, the packets are generally serialized + * assuming big endian data format like seen in TmPacketStored.cpp for example. + * + * @ingroup serialize */ class SerializeIF { public: @@ -22,12 +41,12 @@ public: virtual ~SerializeIF() { } - virtual ReturnValue_t serialize(uint8_t** buffer, uint32_t* size, - const uint32_t max_size, bool bigEndian) const = 0; + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const = 0; - virtual uint32_t getSerializedSize() const = 0; + virtual size_t getSerializedSize() const = 0; - virtual ReturnValue_t deSerialize(const uint8_t** buffer, int32_t* size, + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, bool bigEndian) = 0; };