#ifndef GRIFO_CTRLINK_IF_H
#define GRIFO_CTRLINK_IF_H

#include "grifo_ctrlink.h"

#include "grifo_fw_blob.h"

#include "grifo_fw_map.h"

#include <stdint.h>

namespace grifo_fw
{

struct ctrlink_raw_if_t: public grifo_fw_blob_size_t<grifo_fw::CTRLINK_RCV_TX_SIZE> //<16*1024>
{
    enum {k_max_size=paylad_size_words};

    uint32_t data[k_max_size];
};

struct ctrlink_tx_cw_fileds_t
{
    unsigned int rw: 1;    //0=read
    unsigned int synch: 1; //0=asynch
    unsigned int skip: 1; //0=no skip
    unsigned int spare: 5;
    unsigned int tag: 8;

    unsigned int payload_len: 16;
};

union ctrlink_tx_cw_t
{
    uint32_t raw;
    ctrlink_tx_cw_fileds_t fields;
};

struct ctrlink_tx_header_t
{
    uint32_t destination;
    ctrlink_tx_cw_t cw;
};

//typedef grifo_fw_blob_typed_t<ctrlink_raw_if_t, 0x4354524C/*="CTRL"*/> ctrlink_blob_t;
class ctrlink_blob_t: public grifo_fw_blob_typed_t<ctrlink_raw_if_t, 0x4354524C/*="CTRL"*/>
{
};


struct fpga_uc_ctrl_t
{
    uint32_t slot_address;
    uint32_t read_back;

    uint32_t dbg_reg[32];

};

struct fpga_uc_info_t
{
    enum { fpga_offset=0x00780};

    uint32_t sw_id[2];
    uint16_t sw_release[2];
    uint32_t sw_build;

    uint32_t slot_address;
    uint32_t spare[3];

    uint32_t supply_status[3];
    uint32_t temperature_status[1];

    int8_t temperature_value[8];

    enum sensor_status_t
    {
        sensor_status_ok,
        sensor_status_under_range,
        sensor_status_over_range,
        sensor_status_not_valid
    };

    sensor_status_t sensorStatus(unsigned int n) const
    {
        unsigned int w=n>>4;
        unsigned int s=n-(w<<4);
        uint32_t v=supply_status[w];
        v=v>>(2*s);
        v=v & 0x3;
        return static_cast<sensor_status_t>(v);
    }

    sensor_status_t temperatureStatus(unsigned int n) const
    {
        uint32_t v=temperature_status[0];
        v=v>>(n*2);
        v=v & 0x3;
        return static_cast<sensor_status_t>(v);
    }

    int temperature(unsigned int n) const
    {
        return temperature_value[n];
    }
};

struct fpga_fw_info_t
{
    uint32_t fw_id[2];
    uint32_t fw_release;
    uint32_t fw_build;

    uint32_t lock_link;
    uint32_t lock_link_latched;

    uint32_t cbit_result;
    uint32_t cbit_result_latched;

    uint32_t detector_status;
    uint32_t detector_presence;


};

struct fpga_info_t
{
    fpga_uc_info_t uc_info;

    uint8_t spare_uc[(32*4)-(sizeof(fpga_uc_info_t))];

    fpga_fw_info_t fw_info;

    uint8_t spare_fw[(32*4)-(sizeof(fpga_fw_info_t))];
};

struct ctrlink_reply_decode_t
{
    enum msg_sts_t { msg_ok, msg_err, msg_missed};
    int sts;
    unsigned int checked;
    unsigned int total_fails;
    unsigned int con_fails;
    unsigned int tag;
    unsigned int address;
    unsigned int function_id;
    const void* dayload;
    unsigned int payload_size;
    const void* next_msg; //=0 means nef of list or unrecoverable decoding error
    const char* err_msg;
};

//extern void ctrlink_initialize_default_blob(ctrlink_blob_t* ld);


extern int ctrlink_append_status_request(ctrlink_blob_t* ld, ctrlink_board_address_t board);
extern ctrlink_reply_decode_t::msg_sts_t ctrlink_status_payload(ctrlink_board_address_t board,fpga_info_t& fpga_info,bool& fail);
extern void ctrlink_bite_prepare();
extern int ctrlink_append_lo_frequency_operative_message(ctrlink_blob_t* ld, unsigned int board, unsigned int num_values, const unsigned int *frq /*[num_values]*/, ctrlink_pingpong_t pingpong=ctrlink_pingpong_auto);
extern int ctrlink_append_lo_frequency_asynch_message(ctrlink_blob_t* ld, unsigned int board, unsigned int frq);

enum ctrlink_dc_function_id_t
{
    //ctrlink_staus=0x1,
    ctrlink_ad_ctrl,
    ctrlink_test_port,
    ctrlink_dc_opeative,
    ctrlink_dc_asynch,
    ctrlink_lo_frequency,
    ctrlink_stc_asynch,
    ctrlink_stc_operative,
    ctrlink_nagc_asynch,
    ctrlink_nagc_opeative
};

enum ctrlink_append_mode_t
{
    ctrlink_append_write=0,
    ctrlink_append_read=1
};

extern void* ctrlink_append_raw_message(ctrlink_blob_t* ld, uint32_t dst, ctrlink_append_mode_t append_mode, const void* payload, unsigned int size_bytes, bool fw_synch=false);
    //WARNING: fw_synch should be always false. It is about the FPGA FW operation, not about the destination board operation

//extern int ctrlink_clear(ctrlink_blob_t* ld);

extern int ctrlink_check_reply(ctrlink_reply_decode_t* result, const void* p);

}   //namespace



#endif // GRIFO_CTRLINK_IF_H
