#ifndef AVB_DRIVER_H_
#define AVB_DRIVER_H_

#include <stdint.h>

class QSettings;

typedef uint16_t avb_1553_word_t;

typedef int avb_microseconds_t;

typedef enum {
  avb_bus_default=0,
  avb_bus_A=1,
  avb_bus_B=2
} avb_1553_bus_t;

typedef struct {
  unsigned int wc: 5;
  unsigned int sa: 5;
  unsigned int tr: 1;
  unsigned int rt: 5;
} avb_1553_cw_structure_t;

typedef union {
  avb_1553_word_t raw;
  avb_1553_cw_structure_t str;
} avb_1553_cmd_word_t;

typedef struct {
    unsigned int tf: 1;
    unsigned int bca: 1;
    unsigned int sf: 1;
    unsigned int busy: 1;
    unsigned int brcs: 1;
    unsigned int reserved: 3;
    unsigned int sr: 1;
    unsigned int instr: 1;
    unsigned int me: 1;
    unsigned int rt: 5;
} avb_1553_sw_structure_t;

typedef union {
  avb_1553_word_t raw;
  avb_1553_sw_structure_t str;
} avb_1553_sts_word_t;

typedef struct {
  avb_1553_word_t data[32];
} avb_1553_data_buffer_t;

typedef enum {
  avb_term_real=0,
  avb_term_simulated,
  avb_term_disabled
} avb_1553_terminal_mode_t;

typedef struct {
  const char* nickName;
  const char* longName;
  unsigned int adr;
  avb_1553_terminal_mode_t mode;
} avb_1553_terminal_t;

typedef enum {
  avb_mc_synch_with_data_word=17
} avb_1553_rx_mode_codes_t;

typedef enum {
  avb_mc_synch_without_data_word=1
} avb_1553_tx_mode_codes_t;

typedef enum {
  avb_t_auto,
  avb_t_nop,
  avb_t_nop_skip_next,
  avb_t_rt,
  avb_t_rt_rt
} avb_msg_type_t;

typedef enum {
    avb_rx=0,
    avb_tx=1
} avb_rxtx_t;

//struct avb_reserved_msg_t;
typedef int avb_reserved_msg_t;

struct avb_1553_message_t;

class IAvbDriver;

typedef void (*avb_1553_major_frame_handler_t)(IAvbDriver* const drv, unsigned int frame_counter, avb_microseconds_t tt);
typedef avb_1553_major_frame_handler_t avb_1553_minor_frame_handler_t;
typedef avb_1553_major_frame_handler_t avb_1553_eof_of_frame_handler_t;

typedef void (*avb_1553_message_handler_t)(IAvbDriver* const drv, bool ok, avb_1553_message_t* const msg, avb_microseconds_t tt);

struct avb_1553_message_t {

  const char* nickName;
  const char* longName;

  avb_msg_type_t type;

  avb_1553_terminal_t* target;  //src==0 -> from BC
  avb_1553_terminal_t* target_rtrt_tx;  //dst==0 -> to BC, if both src and dst == 0 -> broadcast

  avb_rxtx_t tr;
  unsigned int sa;
  unsigned int wc;

  unsigned int moninal_frequency;  //-1: async

  avb_1553_message_handler_t msgHandler;

  avb_1553_data_buffer_t* buffer;

  avb_reserved_msg_t avbReserved_;
  avb_reserved_msg_t avbReserved_BcPos;

  unsigned int avbReservedBc_;
};

//struct avb_reserved_frame_t;
typedef int avb_reserved_frame_t;

typedef enum {
  avb_bc_no_interrupt=0,
  avb_bc_interrupt=1
} avb_1553_bc_intr_t;



typedef struct avb_1553_bc_message_tag_t {

  avb_1553_message_t* msg;

  avb_1553_bc_intr_t interrupt;
  bool conditional;

  avb_microseconds_t time_to_next;
  avb_1553_bus_t bus;
  unsigned int retry;

  avb_reserved_frame_t avbReserved_;
  avb_reserved_frame_t avbReserved_BcPos;
} avb_1553_bc_message_t;

//extern const avb_1553_message_t avb_frame_end_of_minor__;
//extern const avb_1553_message_t avb_frame_end_of_major__;
//extern const avb_1553_message_t avb_frame_skip_next_message__;

#define avb_frame_end_of_minor reinterpret_cast<avb_1553_message_t*>(0)
#define avb_frame_end_of_major reinterpret_cast<avb_1553_message_t*>(1)
#define avb_frame_skip_next_message reinterpret_cast<avb_1553_message_t*>(2)

typedef struct {
  int num_of_message;
  avb_1553_bc_message_t** msg;  //the message table
  avb_1553_bc_message_t** oob_msg;  //out-of-band messages

  avb_microseconds_t minor_frame_time;

} avb_1553_bc_frame_t;

typedef struct {
  unsigned int major_frames;
  unsigned int major_frame_tt;
  unsigned int raised;
  unsigned int served;
} avb_1553_intr_status_t;

typedef struct {
    int rt;
    int sa;
    int tr;
    int error;

    avb_1553_data_buffer_t data;
} avb_1553_message_info_t;


typedef void (*avb_1553_isr_t)(avb_1553_message_info_t*);

typedef struct {
    unsigned int total_message;
    unsigned int processed_message;

    unsigned int size;
    avb_1553_word_t* buffer;
} avb_1553_monitor_info_t;

typedef struct {
  bool err;
  bool invalid;
  bool no_response;
  bool bit_in_status_err;
  bool broadcast;
  bool modecode;

  unsigned int internal_eror_code;
  bool tx_sts_received;
  bool rx_sts_received;
  bool tr;
  unsigned int bus;

  unsigned int rt;
  unsigned int sa;

  avb_1553_cmd_word_t cmd;
  avb_1553_sts_word_t sts;

  avb_1553_cmd_word_t rtrt_tx_cmd;
  avb_1553_sts_word_t rtrt_tx_sts;

  unsigned long timetag;
  unsigned int wc;
  //avb_1553_word_t* data;
  avb_1553_word_t data[32];

  void* next;
} avb_1553_mon_decoded_t;

typedef void (*avb_1553_monitor_isr_t)(avb_1553_monitor_info_t*);

extern avb_1553_bc_message_t avb_1553_end_of_minor_frame;
extern avb_1553_bc_message_t avb_1553_nop_message;

class IAvbDriverClient
{
public:
    virtual ~IAvbDriverClient() {}

    virtual void logError(const char* fmt, ...)=0;
    virtual bool getSettingsBool(const char* name)=0;
    virtual int getSettingsInt(const char* name)=0;
};

class IAvbDriver
{
public:
  virtual ~IAvbDriver() {}

  virtual bool initialize()=0;
  virtual bool shutdown()=0;

  //virtual bool setUpMessages(unsigned int num_of_message, const avb_1553_message_t* const msg_table)=0;
  virtual void set_begin_of_major_frame_handler(avb_1553_major_frame_handler_t handler)=0;
  virtual void set_minor_frame_handler(avb_1553_major_frame_handler_t handler)=0;
  virtual void set_end_of_frame_handler(avb_1553_major_frame_handler_t handler)=0;

  virtual const char* getDeviceName()=0;

  virtual bool setUpBcFrame(avb_1553_bc_frame_t& frame)=0;

  virtual void set_isr(avb_1553_isr_t)=0;

  enum { mode_mon=1, mode_bc=2, mode_rt=4};
  virtual bool go(int times)=0;
  virtual bool stop()=0;
  virtual bool go_mon()=0;
  virtual bool halt_mon()=0;

  enum run_status_t { sts_halt=0, sts_bc_run=1, sts_mon_run=2, sts_bc_mon_run };

  virtual run_status_t getRunState()=0;

  virtual void niceInterrupt(bool enable)=0;

  virtual void enableMonitorIsr(bool enable=true)=0;
  virtual void set_mon_isr(avb_1553_monitor_isr_t)=0;
  virtual bool getMonitorRawBuffer(avb_1553_monitor_info_t* const buffer)=0;

  virtual int getLastDriverError()=0;
  virtual const char* getDriverErrrorMessage(int error_code)=0;

  virtual bool readDataBuffer(avb_1553_message_t* const, void* const dst, unsigned int wc=0)=0;
  virtual bool writeDataBuffer(const avb_1553_message_t* const, void* const src, unsigned int wc=0)=0;

  virtual void writeSyncWord(avb_1553_word_t)=0;

  virtual bool enableSkipMessage(bool enable=true)=0;

  //virtual bool adjustMinorFrameTimer();
  virtual avb_1553_intr_status_t getIntrStatus()=0;

  virtual bool mon_decode_msg(avb_1553_mon_decoded_t* const decoded, void* const buffer)=0;

  virtual avb_microseconds_t getTimetag()=0;

  virtual void simulateBcTick()=0;

  virtual bool insertMessage(const avb_1553_bc_message_t* const)=0;
};

#define AVBDRIVER_CREATOR_FUNCTION_NAME "AvbDriverCreate"
typedef IAvbDriver* (*AvbDriverCreator_function_t)(const char* subtype,IAvbDriverClient*);

extern "C" {

extern IAvbDriver* Avb_DriverCreate(QSettings* settings=0);

}

#endif /*AVB_DRIVER_H_*/
