/*
 * rex_udp_tunnelling.h
 *
 *  Created on: 29/mag/2018
 *      Author: chessaa
 */

#ifndef REX_UDP_TUNNELLING_H_
#define REX_UDP_TUNNELLING_H_

#include <stdint.h>

//Fragmentation Protocol on rex_msg_flow_control_t word
//  1. TX: First TX message alaways not jumbo, sender jumbo capacity, ack window don't care (0)
//  2. RX: First ACK always sent with receiver jumbo capacity and ack window
//  3. TX: send rest of message according with the min(jumbo_rx, jumbo_tx), waiting for acq only every rx ack_window messages
//  4. RX: receive and sent ACk every rx ack_window messages. If receive a new message with current_frag=0, drop  uncomplete message and restart
//There are more then one message on the "fly". A message is uniquely identified by:
//  (dst,src,mailboc,transaction_id)
//The fcs is relative to the channel id and is incremented for every message, regardless on the fragments and unique id

struct RexUdpMsgHeader	//WARNING: please guarantee alignment
{
	enum msg_class_t { t_msg=0, t_memory_write=1, memory_read=2};
	enum marker_value_t { marker_rexnet_protocol='!', marker_begin = '<', marker_body='+', marker_end='>', marker_ack='*', marker_hello='@'};
	enum { msg_mtu=4*1024};
	enum { msg_frag_mtu=1400};

	union flow_control_t
	{	//Warning: the bitfield must size exactly 32bits
		uint16_t raw;
		struct {
			unsigned int jumbo:	4;	//Jumbo packet support: size=1000*(jumbo+1), 0=default MTU (1500 other Ethernet, 4K over SRIO
			unsigned int ack_window: 6;	//max windows accepted for ACK. 0=ack only last

			unsigned int arp_ack: 1;		//reply to an arq_required
			unsigned int arp_required: 1;	//request an simple message to identify the source IP

			unsigned int ack_frag_required: 1;		//request a fragmentation ack
			unsigned int ack_frag: 1;				//reply to an acq_frag_required

			unsigned int spare: 2;
		} code;
	};

	//W0
	uint8_t marker_protocol;	//always=marker_rexnet_protocol
	uint8_t marker_value;
	//uint8_t marker_value;	//Always="!" - real type is msg_class_t
	//uint8_t fmt;	//So far, always=0

	uint8_t src;
	uint8_t dst;

	//W1
	//uint8_t op;	//0..127: op code, bit7=ack flag

	uint8_t msg_class;

	uint8_t transaction_id;
	uint8_t fcs;	//frame control sequence

	uint8_t extsize_bytes;		//size, in types, to skip for the payload
	flow_control_t flow_control;

	//W2
	uint32_t mailbox;	//This can be a mailbox+letter or a memory address (destination or source)
	//uint32_t source_address; //for memory read operation
    //uint8_t letter;
	uint32_t doorbell;

	//W4

	uint32_t total_message_size;

	uint32_t total_frags;
	uint32_t current_frags;

	//uint8_t spare;

	uint16_t payload_size_bytes;

	marker_value_t marker() const { return static_cast<marker_value_t>(marker_value);}
	msg_class_t messageClass() const { return static_cast<msg_class_t>(msg_class);}

	bool markerValid() const { return marker_protocol<=static_cast<uint8_t>(marker_rexnet_protocol);}//TODO: too simplified check

	void setSize(unsigned int bytes)
	{
		total_message_size=bytes;
		total_frags=(bytes+(msg_frag_mtu-1)) % msg_frag_mtu;
		current_frags=0;
		payload_size_bytes=0;
	}
};

template<typename T_> struct RexUdpMsgHeaderT
{
	typedef T_ payload_t;

	RexUdpMsgHeader header;

	payload_t payload;

	void setSize() { header.setSize(sizeof payload);}

};




#endif /* REX_UDP_TUNNELLING_H_ */
