/* * PacketLib.h * * Created on: Nov 24, 2022 * Author: valerio */ #ifndef INCLUDE_BASEPACKET_H_ #define INCLUDE_BASEPACKET_H_ #include #include #include #include #include #include #include #include #include namespace inaf::oasbo::PacketLib { template class bit_iterator: public std::iterator { public: bit_iterator(const uint8_t *data, int offset, std::vector fieldSizes, std::function func) : m_data(data), m_offset(offset), m_fieldSizes(fieldSizes), m_func(func) { } bit_iterator(const bit_iterator &other) : m_data(other.m_data), m_offset(other.m_offset), m_fieldSizes( other.m_fieldSizes), m_func(other.m_func) { } bit_iterator& operator++() { ++m_offset; return *this; } bit_iterator operator++(int) { bit_iterator temp(*this); ++m_offset; return temp; } bit_iterator& operator--() { --m_offset; return *this; } bit_iterator operator--(int) { bit_iterator temp(*this); --m_offset; return temp; } bit_iterator operator+(int n) const { return bit_iterator(m_data, m_offset + n); } bit_iterator operator-(int n) const { return bit_iterator(m_data, m_offset - n); } int operator-(const bit_iterator &other) const { return m_offset - other.m_offset; } bool operator==(const bit_iterator &other) const { return m_data == other.m_data && m_offset == other.m_offset; } bool operator!=(const bit_iterator &other) const { return !(*this == other); } ValueType operator*() const { size_t offset = std::accumulate(m_fieldSizes.begin(), m_fieldSizes.begin() + m_offset, 0); // offset from the beginning of the byte int num_bits = m_fieldSizes[m_offset]; return m_func(m_data,offset, num_bits); } private: const uint8_t *m_data; int m_offset; std::vector m_fieldSizes; std::function m_func; }; class BasePacketStructure { public: virtual ~BasePacketStructure() = default; virtual std::vector> getPacketStructure() = 0; }; template class BasePacketTempl { protected: uint8_t *binaryPointer; std::vector fieldSizes; std::map fieldNameToOffsetsMap; std::map fieldNameToIndexMap; std::map indexToFieldNameMap; void updateFieldSizes( const std::vector> ¶msTuple) { std::for_each(paramsTuple.begin(), paramsTuple.end(), [&](const std::tuple &tup) { this->fieldSizes.push_back(std::get < 2 > (tup)); }); } void updateFieldOffsets( const std::vector> ¶msTuple) { size_t offset = 0; for (size_t i = 0; i < paramsTuple.size(); i++) { fieldNameToOffsetsMap[i] = offset; offset += std::get < 2 > (paramsTuple[i]); } } void updateFieldNameAndIndexMap( const std::vector> ¶msTuple) { std::for_each(paramsTuple.begin(), paramsTuple.end(), [&](const std::tuple &tup) { this->fieldNameToIndexMap[std::get < 1 > (tup)] = std::get < 0 > (tup); this->indexToFieldNameMap[std::get < 0 > (tup)] = std::get < 1 > (tup); }); } public: BasePacketTempl(std::vector> paramsTuple) { this->updateFieldSizes(paramsTuple); this->updateFieldNameAndIndexMap(paramsTuple); this->updateFieldOffsets(paramsTuple); this->binaryPointer = new uint8_t[paramsTuple.size() * sizeof(ValueType)]; //tot number of field times the maximum bytesize of the value; } virtual ~BasePacketTempl() = default; void updateStructure(std::vector> paramsTuple){ this->updateFieldSizes(paramsTuple); this->updateFieldNameAndIndexMap(paramsTuple); this->updateFieldOffsets(paramsTuple); } static ValueType _readValueFromBinaryAt_(const uint8_t *binaryPointer, size_t offset, int num_bits) { int bit_offset = offset % 8; int byte_offset = offset / 8; ValueType value = 0; for (int i = 0; i < num_bits; i++) { int byte_index = byte_offset + (bit_offset + i) / 8; int bit_index = (bit_offset + i) % 8; uint8_t byte = binaryPointer[byte_index]; uint8_t bit_mask = 1 << (7 - bit_index); value |= (byte & bit_mask) ? (1 << (num_bits - i - 1)) : 0; } return value; } ValueType readValueFromBinaryAt(int index) { size_t offset = fieldNameToOffsetsMap.at(index); // offset from the beginning of the byte int num_bits = this->fieldSizes[index]; //remaining bits to read ValueType value = _readValueFromBinaryAt_(binaryPointer, offset, num_bits); return value; } std::vector const* getFieldSizes() const { return &fieldSizes; } uint8_t const* getBinaryPointer() const { return binaryPointer; } void copyToBinaryPointer(const uint8_t *from, uint size) { std::memcpy(binaryPointer, from, size); } void copyToBinaryPointer(const uint8_t *from, uint size, uint offset) { std::memcpy(&binaryPointer[offset], from, size); } size_t indexOfField(std::string fieldName) { return this->fieldNameToIndexMap.at(fieldName); } std::string fieldNameOfIndex(size_t index) { return this->indexToFieldNameMap.at(index); } ValueType operator[](int index) { return readValueFromBinaryAt(index); } ValueType operator[](std::string fieldName) { try{ int index = this->fieldNameToIndexMap.at(fieldName); return readValueFromBinaryAt(index); } catch(const std::out_of_range& oor){ std::cerr << "Error: no field with name '" << fieldName << "', returning 0" << std::endl; return 0; } } bit_iterator begin() const { return bit_iterator(binaryPointer, 0, fieldSizes, &_readValueFromBinaryAt_); } bit_iterator end() const { return bit_iterator(binaryPointer, fieldSizes.size(), fieldSizes, &_readValueFromBinaryAt_); } virtual size_t getHeaderSize()=0; virtual size_t getPayloadSize()=0; virtual size_t getTailSize()=0; virtual size_t getMaxPacketSize()=0; }; using valueType = size_t; class BasePacket : public BasePacketTempl { protected: public: BasePacket(std::vector> paramsTuple) : BasePacketTempl(paramsTuple) { } virtual ~BasePacket() = default; }; } #endif