/* * 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 { class BasePacketStructure { protected: std::string source; size_t byteSize; std::vector fieldSizes; std::map fieldNameToOffsetsMap; std::map fieldNameToIndexMap; std::map indexToFieldNameMap; virtual std::vector> readStructureFromSource(std::string source) = 0; 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); }); } void updateStructure(std::string source){ this->source = source; std::vector> paramsTuple = readStructureFromSource(source); updateFieldSizes(paramsTuple); updateFieldOffsets(paramsTuple); updateFieldNameAndIndexMap(paramsTuple); this->byteSize = std::accumulate(fieldSizes.begin(), fieldSizes.end(), 0) / 8 + 1; // /8 +1 for byte size } public: virtual ~BasePacketStructure() = default; void changeSource(std::string source){ updateStructure(source); } size_t getByteSize() { return this->byteSize; } std::string getSource(){ return this->source; } size_t bitOffsetOf(int index){ return fieldNameToOffsetsMap.at(index);} size_t bitSizeOf(int index){ return this->fieldSizes[index];} size_t indexOfField(std::string fieldName) { return this->fieldNameToIndexMap.at(fieldName);} std::string fieldNameOfIndex(size_t index) { return this->indexToFieldNameMap.at(index);} size_t numberOfFields(){ return this->fieldSizes.size();} }; template class bit_iterator: public std::iterator { public: bit_iterator(const uint8_t *data, int offset, BasePacketStructure *structure, std::function func) : m_data(data), m_offset(offset), m_structure(structure), m_func( func) { } bit_iterator(const bit_iterator &other) : m_data(other.m_data), m_offset(other.m_offset), m_structure(other.m_structure), 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 = m_structure->bitOffsetOf(m_offset); // offset from the beginning of the byte int num_bits = m_structure->bitSizeOf(m_offset); return m_func(m_data, offset, num_bits); } private: const uint8_t *m_data; int m_offset; BasePacketStructure *m_structure; std::function m_func; }; template class BasePacketTempl { protected: BasePacketStructure *structure; uint8_t *binaryPointer; 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; } public: BasePacketTempl(BasePacketStructure *structure) { this->structure = structure; this->binaryPointer = new uint8_t[structure->getByteSize()]; } virtual ~BasePacketTempl() = default; void updateStructure(BasePacketStructure *structure) { this->structure = structure; } ValueType readValueFromBinaryAt(int index) { size_t offset = structure->bitOffsetOf(index); // offset from the beginning of the byte int num_bits = structure->bitSizeOf(index); //remaining bits to read ValueType value = _readValueFromBinaryAt_(binaryPointer, offset, num_bits); return value; } uint8_t const* getBinaryPointer() const { return binaryPointer; } void copyToBinaryPointer(const uint8_t *from, uint size) { if(size > this->structure->getByteSize()){ std::cerr << "Error: you are trying to copy " << size << "byte where the max size is: " << this->structure->getByteSize() << std::endl; std::cerr << "\tI copy only until " << this->structure->getByteSize() << " byte" << std::endl; std::memcpy(binaryPointer, from, this->structure->getByteSize()); } else std::memcpy(binaryPointer, from, size); } void copyToBinaryPointer(const uint8_t *from, uint size, uint offset) { if(size+offset > this->structure->getByteSize()){ std::cerr << "Error: you are trying to copy " << size+offset << "byte where the max size is: " << this->structure->getByteSize() << std::endl; std::cerr << "\tI copy only until " << this->structure->getByteSize() << " byte" << std::endl; std::memcpy(&binaryPointer[offset], from, this->structure->getByteSize()); } else std::memcpy(&binaryPointer[offset], from, size); } ValueType operator[](int index) { return readValueFromBinaryAt(index); } ValueType operator[](std::string fieldName) { try { int index = structure->indexOfField(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, structure, &_readValueFromBinaryAt_); } bit_iterator end() const { return bit_iterator(binaryPointer, structure->numberOfFields(), structure, &_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(BasePacketStructure *structure) : BasePacketTempl(structure) { } virtual ~BasePacket() = default; }; } #endif