Skip to content
Base_Packet.h 6.18 KiB
Newer Older
Valerio Pastore's avatar
Valerio Pastore committed
/*
 * Packet.h
 *
 *  Created on: Mar 12, 2021
 *      Author: astrisw
 */

#ifndef BASE_PACKET_H_
#define BASE_PACKET_H_
#include <pugixml/src/pugixml.hpp>
#include <iostream>
#include <cstring>
#include <string>
#include <math.h>
#include <unordered_map>

/*
 * class Packet
 * Implementation of the packet
 *
 * @member field name: the packet name reported in the corresponding xml file.
 * @member field doc: the xml file representing the packet structure.
 * @member field header_size: the size of the header (in bytes).
 * @member field max_data_length: the max size of the data field (in bytes).
 * @member field tail size: the size of the tail (in bytes).
 * @member field max_packet_size: the maximum size of the whole packet (sum of the sizes of the header, data, tail)
 * @member field header_field_index: the map representing the "order" of the fields in the header,
 * 		es.	[0 :	"CRC FLAG" ]  // first element in the header
 * 			[1 :	"TelescopeID"]	// second element in the header and so on.
 * @member field header_field_size: the map representing the sizes of the fields in the header,
 * es.	["CRC FLAG",	1]  // bit size of the element CRC FLAG
 * 		["TelescopeID",	7]	// bit size of the element TelescopeID and so on.
 *
 * @member field header_map_values: a map where each key is the header field name and the value is
 * the actual value in the received buffer.
 * The lookup maps are used to access the buffer in the correct way.
 */

class BasePacket {
protected:
	std::string name;
	pugi::xml_document doc;
	int max_packet_size;
	int header_size;
	int payload_size;
	int tail_size;
	std::unordered_map<unsigned short, std::string> header_field_index;
	std::unordered_map<std::string, unsigned short> header_field_size;
	std::unordered_map<std::string, unsigned short> header_field_values;
	int ssc; //source sequence counter
	int crc;
	unsigned char *buffer;

	int computeMaxPacketSize(){
		return std::stoi((static_cast<std::string>(doc.first_child().attribute("maxsize").value())));
	}

	int computeHeaderSize(){
		int headerSize = 0;
		for( const std::pair<std::string, unsigned short> n : header_field_size) {
			headerSize += n.second;
		}
		return headerSize/8; //from bitsize to bytesize
	}

	int computeTailSize(){
		int tail_size = 0;
		pugi::xml_node root = doc.first_child();
		pugi::xml_node tail_node = root.child("tail");
		pugi::xml_node_iterator tail_it = tail_node.begin();
		while(tail_it != tail_node.end()){
			unsigned short field_size  = std::stoi((static_cast<std::string>((*tail_it).attribute("type").value()).substr(4)));
			tail_size += field_size;
			tail_it++;
		}
		return tail_size/8; //from bit size to byte
	}
	/*
	 * This function initializes the lookup maps of the header (see the class definition).
	 * @ param *header_field_index
	 * @ param *header_field_size
	 */
	void computeHeaderMaps(std::unordered_map<unsigned short, std::string> *header_field_index, std::unordered_map<std::string, unsigned short> *header_field_size){
		pugi::xml_node root = doc.first_child();
		pugi::xml_node header_node = root.child("header");
		pugi::xml_node_iterator header_it = header_node.begin();
		int i = 0;
		while(header_it != header_node.end()){
			std::string name = (*header_it).attribute("name").value();
			unsigned short size  = std::stoi((static_cast<std::string>((*header_it).attribute("type").value()).substr(4)));
			(*header_field_index)[i] = name;
			(*header_field_size)[name] = size;
			header_it++;
			i += 1;
		}
	}





public:

	BasePacket(std::string packetPath){
		if (!this->doc.load_file(packetPath.c_str())) {
			throw "Invalid packet path";
		}
		computeHeaderMaps(&this->header_field_index,&this->header_field_size);

		this->header_size = computeHeaderSize();
		this->tail_size = computeTailSize();
		this->max_packet_size = computeMaxPacketSize();
		unsigned char *buffer = new unsigned char[max_packet_size];
		memset(buffer, ' ', max_packet_size);
		this->buffer = buffer;
		this->payload_size = -1;
		this->name = doc.first_child().attribute("name").value();
	}

	std::string getName(){return name;}
	int getHeaderSize() {return header_size;}
	int getPayloadSize() {return payload_size;}
	int getTailSize() {return tail_size;}
	int getPacketSize() {return header_size + payload_size + tail_size;}
	int getSSC() {return ssc;}
	int getCRC() {return crc;}
	int getMaxPacketSize() {return max_packet_size;}
	unsigned char * getBufferPtr(){return buffer;}

	std::unordered_map<std::string,unsigned short> * getHeaderFieldValues() {return &header_field_values;}
	std::unordered_map<unsigned short, std::string> getHeaderFieldIndex() {return header_field_index;}
	std::unordered_map<std::string,unsigned short> getHeaderFieldSize() {return header_field_size;}


	/*
	 * This function fills the map of "header_field_values" where
	 * each key is the header field name and the value is
	 * the actual value in the received buffer.
	 * It uses the lookup maps in order to access the buffer in
	 * the correct way.
	 */
	inline void computeHeaderFieldValues(){
		int num_bit_read = 0; // offset from the beginning of the byte
		for(unsigned short i = 0; i < header_field_index.size(); i++) {
			std::string field_name = header_field_index[i];
			int bit_rem = header_field_size[field_name]; //remaining bits to read
			int val = 0; //final value of the field

			while(bit_rem > 0){
				unsigned short read = buffer[num_bit_read/8];
				unsigned short mask = pow(2,8-num_bit_read%8)-1;
				read = read & mask;

				bit_rem = bit_rem - 8 + num_bit_read%8;
				read = (bit_rem >= 0)*(read << bit_rem) +
						(bit_rem < 0) *(read >> -bit_rem);
				val += read;

				num_bit_read =  (bit_rem > 0)*(num_bit_read + 8 - num_bit_read%8)+
							   (bit_rem <= 0)*(num_bit_read + 8 - num_bit_read%8 + bit_rem);
			}
			header_field_values[field_name] = val;
		}
		updateFromBuffer();
		updatePayloadSize();
	}

	virtual void updateFromBuffer()=0;
	virtual void updatePayloadSize()=0;

	std::string toString(){
		std::string ret = "------------------\n";
		for( const std::pair<std::string, unsigned short> n : header_field_values) {
			ret += (n.first + " : " + std::to_string(n.second) + "\n");
		}
		ret+= "------------------";
		return ret;
	}
	virtual ~BasePacket(){
		std::cout << "Deleting Packet" << std::endl;
		delete buffer;
	}
};

#endif /* BASE_PACKET_H_ */