#ifndef REX_UDPMSG_H
#define REX_UDPMSG_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

class RexUdpMessage
{
public:

    struct rex_msg_flow_control_t
    {	//Warning: the bitfiled must saek exactly 32bits
        unsigned int jumbo:	4;	//Jumbo packet support: size=1024*jumbo, 0=default MTU (1530 other Ethernet, 4K over SRIO
        unsigned int ack_window: 6;	//max windows accepted for ACK. 0=ack only last
        unsigned int spare: 16-12;
    };

    struct RexMsgHeader	//WARNING: please guarantee alignment
    {
        enum msg_class_t { t_msg=0, t_memory_write=1, memory_read=2};
        enum marker_value_t { marker_begin = '!', marker_body='+', marker_end='-'};
        enum { msg_mtu=4*1024};

        struct flow_control_t
        {	//Warning: the bitfiled must saek exactly 32bits
            unsigned int jumbo:	4;	//Jumbo packet support: size=1024*jumbo, 0=default MTU (1530 other Ethernet, 4K over SRIO
            unsigned int ack_window: 6;	//max windows accepted for ACK. 0=ack only last

            unsigned int ack: 1;
            unsigned int ack_required: 1;

            unsigned int spare: 16;
        };

        //W0
        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

        //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
        flow_control_t flow_control;

        uint32_t total_message_size;

        uint32_t total_frags;
        uint32_t current_frags;

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

        uint16_t payload_size_bytes;

        uint32_t payload[0];

        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_value<=static_cast<uint8_t>(marker_end);}
    };

    struct RexMsgDummyMessage
    {
        RexMsgHeader header;
        uint32_t payload[8];
    };    
};

template<typename T_> struct RexUdpMessageT
{
public:
    typedef T_ payload_t;

    RexUdpMessage::RexMsgHeader header;

    payload_t payload;
};

#endif // REX_UDPMSG_H
