#ifndef GRIFO_AESA_FW_IF_H
#define GRIFO_AESA_FW_IF_H

//#include "grifo_fw_blob.h"
#include "aesa_if_types.h"

#include <stdint.h>

namespace grifo_fw
{

class aesa_blob_t;

class aesa_raw_if_t;

void aesa_initialize_raw_default_blob(void* p);

aesa_blob_t* aesa_get_default_blob();

typedef enum
{
    sync_default=0,
    sync_immediately,
    sync_rise_edge_aesa_prog,
    sync_rise_edge_aesa_prog_after_batch
} sync_option_t;

struct aesa_tx_cw_fields_t
{
    unsigned int synch:          2;
    unsigned int response:       4;
    //unsigned int spare:       10;
    unsigned int timeout:        8;
    unsigned int timeout_weight: 1;  //0=10us, 1=100ms
    unsigned int spare:          1;
    unsigned int payload_len:   16;
};

union aesa_tx_cw_t
{
    uint32_t raw;
    aesa_tx_cw_fields_t fields;
};

struct aesa_tx_header_t
{
    aesa_tx_cw_t cw;
};

struct aesa_cti_comm_status_t
{
    unsigned int crc_error_counter;
    unsigned int cmd_error_counter;
    unsigned int good_message_counter;
    unsigned int last_tag;
};

struct aesa_message_descriptor_t
{
    enum sts_t {
        ok,
        crc_error,
        timeout,

        len_error
    };
    enum aesa_result_t {
        crc_mismatch_res=1,
        timeout_on_rx_res=2
    };

    const uint32_t* data;
    unsigned int len_word;
    uint32_t status_word;
    unsigned int payload_len;
    sts_t sts;
};

struct aesa_fw_comm_status_t
{
    unsigned int crc_error_counter;
    unsigned int tm_error_counter;
    unsigned int good_message_counter;

    aesa_message_descriptor_t::sts_t last_msg_status;
};

struct grifo_fw_block_raw_deserializer_t;

/*
 * AESA receive callback registration
 */
struct aesa_receive_info_t
{
    uint8_t                         *rx_buffer;
    unsigned int                     length;
    unsigned int                     payload_len;
    aesa_message_descriptor_t::sts_t status;
};
typedef int (*aesa_receive_callback_t)(const aesa_receive_info_t*);
int aesa_register_rx_callback(aesa_receive_callback_t rx_cb);
int aesa_deregister_rx_callback();

class aesa_deserializer
{
public:
   aesa_deserializer(const void* mem, unsigned int size);

   aesa_message_descriptor_t extract();

private:
   grifo_fw_block_raw_deserializer_t* raw_deserializer;
};

extern const grifo_fw::aesa_fw_comm_status_t& aesa_get_fw_comm_status();

extern uint8_t aesa_get_msg_counter();

extern void aesa_set_msg_counter(uint8_t counter);

extern void aesa_blob_initialize(aesa_blob_t* ld);
extern unsigned int aesa_blob_used_size(aesa_blob_t* ld);
extern int aesa_blob_clear(aesa_blob_t* ld);

extern int aesa_append_raw_message(aesa_blob_t* ld, unsigned int synch, unsigned int num_responses, const void* payload, unsigned int size_bytes);

extern int aesa_append_aesa_fw_status(aesa_blob_t* ld, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_aesa_read_status(aesa_blob_t* ld, uint8_t start_plank, uint8_t end_plank, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_aesa_download_map_all(aesa_blob_t* ld, sync_option_t synch, unsigned int timeout=0);
extern int aesa_append_calc_beam_pos(aesa_blob_t* ld, aesa::beam_calculation_t* beam_data, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_save_beam_pos(aesa_blob_t* ld, aesa::beam_calculation_t* beam_data, uint8_t index, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_index_beam_pos(aesa_blob_t* ld, uint8_t index, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_cti_read_status(aesa_blob_t* ld, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_cti_read_extend_status(aesa_blob_t* ld, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_cti_init_link(aesa_blob_t* ld, bool link_1_or_2, uint8_t init_msg_id, const char* init_bit_code1, const char* init_bit_code2, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_cti_nvm_write_enable(aesa_blob_t* ld, uint8_t key, uint8_t target, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_cti_array_error_log_write(aesa_blob_t* ld, uint8_t num_words, uint8_t* data, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_cti_time_sync(aesa_blob_t* ld, uint8_t* data, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_eti_readback(aesa_blob_t* ld, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_nvm_read_data(aesa_blob_t* ld, uint32_t start_address, uint16_t num_bytes, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_nvm_erase_data(aesa_blob_t* ld, uint32_t start_address, uint16_t num_bytes, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_nvm_write_data(aesa_blob_t* ld, uint32_t start_address, uint16_t num_bytes, const char* data, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_read_status(aesa_blob_t* ld, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_read_fw_status(aesa_blob_t* ld, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_read_bit_status(aesa_blob_t* ld, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_time_sync(aesa_blob_t* ld, const char* data, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_mode(aesa_blob_t* ld, aesa::rfif_mode_command_t* rfif_mode, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rf_end_to_end_test(aesa_blob_t* ld, aesa::rf_end_to_end_t* rf_etet, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_plank_read_extended_status(aesa_blob_t* ld, uint8_t plank_id, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_plank_vtx_control(aesa_blob_t* ld, uint8_t plank_id, aesa::plank_vtx_control_t data, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_plank_trc_initialise(aesa_blob_t* ld, uint8_t plank_id, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_plank_read_status(aesa_blob_t* ld, uint8_t plank_id, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_plank_ibit_start(aesa_blob_t* ld, uint8_t plank_id, sync_option_t synch=sync_immediately, unsigned int timeout=0);

extern int aesa_append_plank_trc_read_status(aesa_blob_t* ld, uint8_t plank_id, uint8_t trcn, sync_option_t synch=sync_immediately, unsigned int timeout=0);

extern void aesa_memory_updated(const void* src, unsigned int max_size);

extern void aesa_payload_swap(uint8_t* dst, const void* src, unsigned int size_bytes);

extern int aesa_append_rfif_cfgmem_read_data(aesa_blob_t* ld, uint32_t start_address, uint16_t num_bytes, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_cfgmem_erase_data(aesa_blob_t* ld, uint32_t start_address, uint16_t num_bytes, sync_option_t synch=sync_immediately, unsigned int timeout=0);
extern int aesa_append_rfif_cfgmem_write_data(aesa_blob_t* ld, uint32_t start_address, uint16_t num_bytes, const char* data, sync_option_t synch=sync_immediately, unsigned int timeout=0);


//RX I/F:
extern int aesa_decode_message_id(const char** msg_name, const void* src, unsigned int size);
extern int aesa_append_cti_imu_control(aesa_blob_t* ld, uint8_t data, sync_option_t synch, unsigned int timeout);

}

#endif // GRIFO_AESA_FW_IF_H
