Newer
Older
/*
* PacketLib.h
*
* Created on: Nov 24, 2022
* Author: valerio
*/
#ifndef INCLUDE_BASEPACKET_H_
#define INCLUDE_BASEPACKET_H_
#include <vector>
#include <map>
#include <string>
#include <cstring>
#include <algorithm>
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
class BasePacketStructure {
protected:
std::string source;
size_t byteSize;
std::vector<int> fieldSizes;
std::map<size_t, size_t> fieldNameToOffsetsMap;
std::map<std::string, int> fieldNameToIndexMap;
std::map<int, std::string> indexToFieldNameMap;
virtual std::vector<std::tuple<int, std::string, int>> readStructureFromSource(std::string source) = 0;
void updateFieldSizes(
const std::vector<std::tuple<int, std::string, int>> ¶msTuple) {
std::for_each(paramsTuple.begin(), paramsTuple.end(),
[&](const std::tuple<int, std::string, int> &tup) {
this->fieldSizes.push_back(std::get<2>(tup));
});
}
void updateFieldOffsets(
const std::vector<std::tuple<int, std::string, int>> ¶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<std::tuple<int, std::string, int>> ¶msTuple) {
std::for_each(paramsTuple.begin(), paramsTuple.end(),
[&](const std::tuple<int, std::string, int> &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<std::tuple<int, std::string, int>> 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<typename ValueType>
class bit_iterator: public std::iterator<std::random_access_iterator_tag,
ValueType> {
public:
bit_iterator(const uint8_t *data, int offset, BasePacketStructure *structure,
std::function<ValueType(const uint8_t*, size_t, int)> 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, m_structure, m_func);
return bit_iterator(m_data, m_offset - n, m_structure, m_func);
}
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<ValueType(const uint8_t*, size_t, int)> m_func;
template<typename ValueType>
class BasePacketTempl {
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;
public:
BasePacketTempl(BasePacketStructure *structure) {
this->structure = structure;
this->binaryPointer = new uint8_t[structure->getByteSize()];
}
virtual ~BasePacketTempl() = default;
void updateStructure(BasePacketStructure *structure) {
this->structure = structure;
}
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);
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);
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 bit_iterator<ValueType>(binaryPointer, 0, structure,
&_readValueFromBinaryAt_);
}
bit_iterator<ValueType> end() const {
return bit_iterator<ValueType>(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;
};
class BasePacket: public BasePacketTempl<valueType> {
BasePacket(BasePacketStructure *structure) :
BasePacketTempl<valueType>(structure) {
}
virtual ~BasePacket() = default;
};