Skip to content
Base_Packet.h 7.52 KiB
Newer Older
Valerio Pastore's avatar
Valerio Pastore committed
/*
 * 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>
Valerio Pastore's avatar
Valerio Pastore committed
#include <numeric>
Valerio Pastore's avatar
Valerio Pastore committed
#include <iostream>
#include <cmath>
Valerio Pastore's avatar
Valerio Pastore committed
#include <functional>
Valerio Pastore's avatar
Valerio Pastore committed
namespace inaf::oasbo::PacketLib {

Valerio Pastore's avatar
Valerio Pastore committed

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>> &paramsTuple) {
		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>> &paramsTuple) {
		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>> &paramsTuple) {
		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();}
};


Valerio Pastore's avatar
Valerio Pastore committed
template<typename ValueType>
class bit_iterator: public std::iterator<std::random_access_iterator_tag,
		ValueType> {
public:
Valerio Pastore's avatar
Valerio Pastore committed
	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) {
Valerio Pastore's avatar
Valerio Pastore committed
	}

	bit_iterator(const bit_iterator &other) :
Valerio Pastore's avatar
Valerio Pastore committed
			m_data(other.m_data), m_offset(other.m_offset), m_structure(other.m_structure), m_func(other.m_func) {
Valerio Pastore's avatar
Valerio Pastore committed
	}

	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 {
Valerio Pastore's avatar
Valerio Pastore committed
		return bit_iterator(m_data, m_offset + n, m_structure, m_func);
Valerio Pastore's avatar
Valerio Pastore committed
	}

	bit_iterator operator-(int n) const {
Valerio Pastore's avatar
Valerio Pastore committed
		return bit_iterator(m_data, m_offset - n, m_structure, m_func);
Valerio Pastore's avatar
Valerio Pastore committed
	}

	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 {
Valerio Pastore's avatar
Valerio Pastore committed
		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);
Valerio Pastore's avatar
Valerio Pastore committed
	}

private:
	const uint8_t *m_data;
	int m_offset;
Valerio Pastore's avatar
Valerio Pastore committed
	BasePacketStructure *m_structure;
	std::function<ValueType(const uint8_t*, size_t, int)> m_func;
Valerio Pastore's avatar
Valerio Pastore committed
template<typename ValueType>
class BasePacketTempl {
Valerio Pastore's avatar
Valerio Pastore committed
protected:
Valerio Pastore's avatar
Valerio Pastore committed
	BasePacketStructure *structure;
Valerio Pastore's avatar
Valerio Pastore committed
	uint8_t *binaryPointer;
Valerio Pastore's avatar
Valerio Pastore committed
	static ValueType _readValueFromBinaryAt_(const uint8_t *binaryPointer,
			size_t offset, int num_bits) {
Valerio Pastore's avatar
Valerio Pastore committed
		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;
Valerio Pastore's avatar
Valerio Pastore committed
		}
		return value;
	}
Valerio Pastore's avatar
Valerio Pastore committed
public:

	BasePacketTempl(BasePacketStructure *structure) {
		this->structure = structure;
		this->binaryPointer = new uint8_t[structure->getByteSize()];
	}

	virtual ~BasePacketTempl() = default;

	void updateStructure(BasePacketStructure *structure) {
		this->structure = structure;
	}
Valerio Pastore's avatar
Valerio Pastore committed

Valerio Pastore's avatar
Valerio Pastore committed
	ValueType readValueFromBinaryAt(int index) {
Valerio Pastore's avatar
Valerio Pastore committed
		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);
Valerio Pastore's avatar
Valerio Pastore committed
		return value;
	}

Valerio Pastore's avatar
Valerio Pastore committed
	uint8_t const* getBinaryPointer() const {
		return binaryPointer;
	}
Valerio Pastore's avatar
Valerio Pastore committed

Valerio Pastore's avatar
Valerio Pastore committed
	void copyToBinaryPointer(const uint8_t *from, uint size) {
Valerio Pastore's avatar
Valerio Pastore committed
		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);
Valerio Pastore's avatar
Valerio Pastore committed
	}
	void copyToBinaryPointer(const uint8_t *from, uint size, uint offset) {
Valerio Pastore's avatar
Valerio Pastore committed
		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);
Valerio Pastore's avatar
Valerio Pastore committed
	ValueType operator[](int index) {
Valerio Pastore's avatar
Valerio Pastore committed
		return readValueFromBinaryAt(index);
Valerio Pastore's avatar
Valerio Pastore committed
	ValueType operator[](std::string fieldName) {
Valerio Pastore's avatar
Valerio Pastore committed
		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;
Valerio Pastore's avatar
Valerio Pastore committed
			return 0;
		}
Valerio Pastore's avatar
Valerio Pastore committed
	bit_iterator<ValueType> begin() const {
Valerio Pastore's avatar
Valerio Pastore committed
		return bit_iterator<ValueType>(binaryPointer, 0, structure,
Valerio Pastore's avatar
Valerio Pastore committed
				&_readValueFromBinaryAt_);
	}

	bit_iterator<ValueType> end() const {
Valerio Pastore's avatar
Valerio Pastore committed
		return bit_iterator<ValueType>(binaryPointer, structure->numberOfFields(),
				structure, &_readValueFromBinaryAt_);
Valerio Pastore's avatar
Valerio Pastore committed
	virtual size_t getHeaderSize()=0;
	virtual size_t getPayloadSize()=0;
	virtual size_t getTailSize()=0;
	virtual size_t getMaxPacketSize()=0;
};
Valerio Pastore's avatar
Valerio Pastore committed

using valueType = size_t;
Valerio Pastore's avatar
Valerio Pastore committed
class BasePacket: public BasePacketTempl<valueType> {
Valerio Pastore's avatar
Valerio Pastore committed

protected:

public:
Valerio Pastore's avatar
Valerio Pastore committed
	BasePacket(BasePacketStructure *structure) :
			BasePacketTempl<valueType>(structure) {
Valerio Pastore's avatar
Valerio Pastore committed
	}
	virtual ~BasePacket() = default;

};
Valerio Pastore's avatar
Valerio Pastore committed
}
#endif