#include "ads_widgets.h"

#include "ads_workbench.h"

#include "mcs_g346.h"

#include <QDebug>
#include <QToolBar>
#include <QLabel>
#include <QMessageBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QDockWidget>
#include <QComboBox>
#include <QPushButton>
#include <QGridLayout>
#include <QCheckBox>
#include <QScrollArea>
#include <QToolBox>
#include <QHBoxLayout>
#include <QMap>
#include <QSettings>
#include <QElapsedTimer>

#include "grifosnuform.h"
#include "grifordrcontrolform.h"
#include "grifotgtform.h"
#include "grifogfxform.h"
#include "grifosettingsform.h"
#include "grifocmddock.h"
#include "grifodltgtform.h"
#include "rdrstatusform.h"
#include "grifobiteform.h"
#include "time_metrics.h"

#include "icd_g346.h"

#include "g346_common.h"
#include "g346_a4a5.h"
#include "g346_b9b10.h"
#include "g346_a1a2.h"
#include "g346_a3.h"

#include <map>

typedef QMap<unsigned int, IGrifoMode*> mode_map_t;

static mode_map_t mode_map;
static IGrifoMode* current_mode;

class GrifoModeSAR: public IGrifoMode
{

};

struct GrifoModesInstance {
  IGrifoMode defaultMode;

  GrifoModeSAR sar;
  IGrifoMode rbm;

  int sar_if_gain;
  int default_if_gain;
};

static GrifoModesInstance* modeOperation;

static metricRegistered mG346Sync("SYNC", 4500000, 100, &G346Metric);

#define AVB_1553_REAL_DEVICE

#ifndef AVB_1553_REAL_DEVICE

#define RT_SIM_RDR avb_term_simulated
#define RT_SIM_INU avb_term_simulated
#define GRIFO_USE_INU

#else

#define GRIFO_USE_INU
#define RT_SIM_RDR avb_term_real
#define RT_SIM_INU avb_term_real
#ifdef GRIFO_USE_INU
#define RT_SIM_INU avb_term_real /*avb_term_simulated*/
#else
//#define RT_SIM_INU avb_term_disabled
#endif

#endif

#define AVB_SYNCH_USE_INSERT
//#define AVB_SKIP_BUG

#pragma GCC diagnostic ignored "-Wmissing-field-initializers"

static avb_1553_terminal_t bc_term={"BC", "MCS", 0};
static avb_1553_terminal_t rdr_term={"RDR", "Radar", 20, RT_SIM_RDR};

static avb_1553_terminal_t inu_term={"INU", "INU", 11, RT_SIM_INU};

static avb_1553_terminal_t* terminal_list[]=
{
  &bc_term,
  &rdr_term,
  &inu_term,
  0
};


extern void B5_track_async_message_routine(Ads1553MsgQ* msg);
extern void B4_track_async_message_routine(Ads1553MsgQ* msg);
extern void B11_track_async_message_routine(Ads1553MsgQ* msg);
extern void B12_track_async_message_routine(Ads1553MsgQ* msg);
extern void B13_track_async_message_routine(Ads1553MsgQ* msg);
extern void B14_track_async_message_routine(Ads1553MsgQ* msg);
extern void B15_track_async_message_routine(Ads1553MsgQ* msg);
extern void B16_track_async_message_routine(Ads1553MsgQ* msg);
extern void B17_track_async_message_routine(Ads1553MsgQ* msg);
extern void B18_track_async_message_routine(Ads1553MsgQ* msg);

using namespace grifo_icd;

static void B7_rdr_status_async_message_routine(Ads1553MsgQ* msg);
static void B6_rdr_settings_tellback_async_message_routine(Ads1553MsgQ* msg);
static void B8_bite_async_message_routine(Ads1553MsgQ* msg);
static void B6_bite_sync_message_routine(IAvbDriver* const drv, ads_1553msg_t* const msg, avb_microseconds_t tt);

static void wraparound_tx_routine(Ads1553MsgQ* msg);
static void wraparound_rx_routine(Ads1553MsgQ* msg);

static void tt_synch_routine(IAvbDriver* const drv, ads_1553msg_t* const msg, avb_microseconds_t tt);
static void tt_asynch_routine(Ads1553MsgQ* msg);

static ads_1553msg_t A1={{"A1", "Settings", avb_t_auto, &rdr_term, &bc_term, avb_rx, 1, 10, 10}};
static ads_1553msg_t A2={{"A2", "Ctrl", avb_t_auto, &rdr_term, &bc_term, avb_rx, 2, ICD_MSGLEN(msg_rdr_operation_command_t), 20}};
static ads_1553msg_t A3={{"A3", "Graphic", avb_t_auto, &rdr_term, &bc_term, avb_rx, 3, 32, 5}};
static ads_1553msg_t A4={{"A4", "Nav1", avb_t_auto, &rdr_term, &bc_term, avb_rx, 4, /*31*/ICD_MSGLEN(msg_nav_data_and_cursor_t), 20}, 0, GrifoMsg_A4A5::a4_asynchronous_message_routine};
static ads_1553msg_t A5={{"A5", "Nav2", avb_t_auto, &rdr_term, &bc_term/*&inu_term*/, avb_rx, 5, /*23*/ICD_MSGLEN(msg_inu_high_speed_t), 20}, 0, GrifoMsg_A4A5::a5_asynchronous_message_routine};
static ads_1553msg_t A7={{"A7", "DL1", avb_t_auto, &rdr_term, &bc_term, avb_rx, 7, 31, 20}};
static ads_1553msg_t A8={{"A8", "DL2", avb_t_auto, &rdr_term, &bc_term, avb_rx, 8, 30, 20}};

//#define AM346
#ifdef AM346
#define B4_WORDS    24
#define B5_WORDS    26
#define HPT_MSG_NAME    "B5-346"
#else
#define B4_WORDS    27
#define B5_WORDS    27
#define HPT_MSG_NAME    "B5"
#endif

static ads_1553msg_t B1={{"B1", "TWS1", avb_t_auto, &rdr_term, &bc_term, avb_tx, 11, 29}};
static ads_1553msg_t B2={{"B2", "TWS2", avb_t_auto, &rdr_term, &bc_term, avb_tx, 12, 27}};
static ads_1553msg_t B3={{"B3", "TWS3", avb_t_auto, &rdr_term, &bc_term, avb_tx, 13, 27}};
static ads_1553msg_t B4={{"B4", "SPT", avb_t_auto, &rdr_term, &bc_term, avb_tx, 14, B4_WORDS}, 0, B4_track_async_message_routine};
static ads_1553msg_t B5={{HPT_MSG_NAME, "HPT", avb_t_auto, &rdr_term, &bc_term, avb_tx, 15, B5_WORDS}, 0, B5_track_async_message_routine};
static ads_1553msg_t B6={{"B6", "SettTB", avb_t_auto, &rdr_term, &bc_term, avb_tx, 16, 23}, B6_bite_sync_message_routine, B6_rdr_settings_tellback_async_message_routine};
static ads_1553msg_t B7={{"B7", "CtrlTB", avb_t_auto, &rdr_term, &bc_term, avb_tx, 17, 3}, 0, B7_rdr_status_async_message_routine};
static ads_1553msg_t B8={{"B8", "BITE", avb_t_auto, &rdr_term, &bc_term, avb_tx, 18, 32}, 0, B8_bite_async_message_routine};

static ads_1553msg_t B9={{"B9"  , "DBG1", avb_t_auto, &rdr_term, &bc_term, avb_tx, 19, 32}};
static ads_1553msg_t B10={{"B10", "DBG2", avb_t_auto, &rdr_term, &bc_term, avb_tx, 20, 32}};

static ads_1553msg_t B11={{"B11", "MTT3", avb_t_auto, &rdr_term, &bc_term, avb_tx, 21, 27}, 0, B11_track_async_message_routine};
static ads_1553msg_t B12={{"B12", "MTT4", avb_t_auto, &rdr_term, &bc_term, avb_tx, 22, 27}, 0, B12_track_async_message_routine};
static ads_1553msg_t B13={{"B13", "MTT5", avb_t_auto, &rdr_term, &bc_term, avb_tx, 23, 27}, 0, B13_track_async_message_routine};
static ads_1553msg_t B14={{"B14", "MTT6", avb_t_auto, &rdr_term, &bc_term, avb_tx, 24, 27}, 0, B14_track_async_message_routine};
static ads_1553msg_t B15={{"B15", "MTT7", avb_t_auto, &rdr_term, &bc_term, avb_tx, 25, 27}, 0, B15_track_async_message_routine};
static ads_1553msg_t B16={{"B16", "MTT8", avb_t_auto, &rdr_term, &bc_term, avb_tx, 26, 27}, 0, B16_track_async_message_routine};
static ads_1553msg_t B17={{"B17", "MTT9", avb_t_auto, &rdr_term, &bc_term, avb_tx, 27, 27}, 0, B17_track_async_message_routine};
static ads_1553msg_t B18={{"B18", "MTT10", avb_t_auto, &rdr_term, &bc_term, avb_tx, 28, 27}, 0, B18_track_async_message_routine};

static ads_1553msg_t WT_RX={{"WT-RX"  , "Wrap-aorund test RX", avb_t_auto, &rdr_term, &bc_term, avb_rx, 30, 32}, 0, wraparound_tx_routine};
static ads_1553msg_t WT_TX={{"WT-TX"  , "Wrap-aorund test TX", avb_t_auto, &rdr_term, &bc_term, avb_tx, 30, 32}, 0, wraparound_rx_routine};

static ads_1553msg_t RDRTT={{"RDRTT", "RDR Timetag Sync", avb_t_auto, &rdr_term, &bc_term, avb_rx, 0, avb_mc_synch_with_data_word}};
static ads_1553msg_t RDRTT0={{"RDRSYNCH0", "RDR Timetag Sync zero", avb_t_auto, &rdr_term, &bc_term, avb_tx, 0, avb_mc_synch_without_data_word}};

static ads_1553msg_t SKIP={{"FSKIP", "Skip Next Message", avb_t_nop_skip_next, &rdr_term, &bc_term, avb_rx, 1, 10}};
static ads_1553msg_t BCNOP={{"FNOP", "NOP", avb_t_nop, &rdr_term, &bc_term, avb_rx, 1, 10}};

#ifdef GRIFO_USE_INU
#define INU_AVB_OP  avb_t_nop /*avb_t_auto*/
#else
#define INU_AVB_OP  avb_t_nop
#endif

static ads_1553msg_t C01={{"C01", "C01", INU_AVB_OP, &inu_term, &bc_term, avb_rx, 0x1E, 10}};
static ads_1553msg_t D01={{"D01", "D01", INU_AVB_OP, &inu_term, &bc_term, avb_rx, 0x1A,  7}};
static ads_1553msg_t I01={{"I01", "I01", INU_AVB_OP, &inu_term, &bc_term, avb_tx, 0x10, 32}};
static ads_1553msg_t I06={{"I06", "I06", INU_AVB_OP, &inu_term, &bc_term, avb_tx, 0x19, 32}};
static ads_1553msg_t I07={{"I07", "I07", INU_AVB_OP, &inu_term, &bc_term, avb_tx, 0x1B, 32}};
static ads_1553msg_t I09={{"I09", "I09", INU_AVB_OP, &inu_term, &bc_term, avb_tx, 0x13, 32}};
static ads_1553msg_t I14={{"I14", "I14", INU_AVB_OP, &inu_term, &bc_term, avb_tx, 0x17, 32}};
//static ads_1553msg_t INUTT={{"INUTT", "INU Timetag Sync", INU_AVB_OP, &inu_term, &bc_term, avb_rx, 0, avb_mc_synch_with_data_word}};
static ads_1553msg_t INUTT={{"INUTT", "INU Timetag Sync", /*avb_t_auto*/INU_AVB_OP, &inu_term, &bc_term, avb_tx, 0, avb_mc_synch_without_data_word}, 0, tt_asynch_routine};

static ads_1553msg_t* myMsgList[]=
{
    &A1, &A2, &A3, &A4, &A5, &A7, &A8,

    &B1, &B2, &B3, &B4, &B5, &B6, &B7, &B8, &B9, &B10,

    &B11, &B12, &B13, &B14, &B15, &B16, &B17, &B18,

    &WT_RX, &WT_TX,

    &RDRTT, &RDRTT0,

    &INUTT,

#ifdef GRIFO_USE_INU
    &C01, &D01, &I01, &I06, &I07, &I09, &I14,
#endif

    0
};


static avb_1553_bc_message_t mEND={avb_frame_end_of_minor};
static avb_1553_bc_message_t mFEND={avb_frame_end_of_major};
static avb_1553_bc_message_t mSKIP={&SKIP.desc};
static avb_1553_bc_message_t mNOP={&BCNOP.desc};

static avb_1553_bc_message_t mA1={&A1.desc};
static avb_1553_bc_message_t mA2={&A2.desc};
static avb_1553_bc_message_t mA3={&A3.desc};
static avb_1553_bc_message_t mA4={&A4.desc};
static avb_1553_bc_message_t mA5={&A5.desc};
static avb_1553_bc_message_t mA7={&A7.desc};
static avb_1553_bc_message_t mA8={&A8.desc};
static avb_1553_bc_message_t mB1={&B1.desc};
static avb_1553_bc_message_t mB2={&B2.desc};
static avb_1553_bc_message_t mB3={&B3.desc};
static avb_1553_bc_message_t mB4={&B4.desc};
static avb_1553_bc_message_t mB5={&B5.desc};
static avb_1553_bc_message_t mB6={&B6.desc};
static avb_1553_bc_message_t mB7={&B7.desc};
static avb_1553_bc_message_t mB8={&B8.desc};
static avb_1553_bc_message_t mB9={&B9.desc};
static avb_1553_bc_message_t mB10={&B10.desc};

static avb_1553_bc_message_t mB11={&B11.desc};
static avb_1553_bc_message_t mB12={&B12.desc};
static avb_1553_bc_message_t mB13={&B13.desc};
static avb_1553_bc_message_t mB14={&B14.desc};
static avb_1553_bc_message_t mB15={&B15.desc};
static avb_1553_bc_message_t mB16={&B16.desc};
static avb_1553_bc_message_t mB17={&B17.desc};
static avb_1553_bc_message_t mB18={&B18.desc};


static avb_1553_bc_message_t mWRX={&WT_RX.desc};
static avb_1553_bc_message_t mWTX={&WT_TX.desc};

static avb_1553_bc_message_t mRDRTT={&RDRTT.desc};
static avb_1553_bc_message_t mRDRTT0={&RDRTT0.desc};
static avb_1553_bc_message_t mINUTT={&INUTT.desc};

static avb_1553_bc_message_t mC01={&C01.desc};
static avb_1553_bc_message_t mD01={&D01.desc};
static avb_1553_bc_message_t mI01={&I01.desc};
static avb_1553_bc_message_t mI06={&I06.desc};
static avb_1553_bc_message_t mI07={&I07.desc};
static avb_1553_bc_message_t mI09={&I09.desc};
static avb_1553_bc_message_t mI14={&I14.desc};

#ifdef AVB_SYNCH_USE_INSERT

#define mRDRTT_STUB mNOP
#define mINUTT_STUB mNOP
#define mRDRTT_ASYNCH mRDRTT
#define mINUTT_ASYNCH mINUTT

#define mSKIP_STUB  mNOP

static void enableSkip(IAvbDriver* const /*drv*/, bool /*skip*/)
{
    return;
}

#else
#define mRDRTT_STUB mRDRTT
#define mINUTT_STUB mINUTT
#define mRDRTT_ASYNCH mNOP
#define mINUTT_ASYNCH mNOP

#ifdef AVB_SKIP_BUG

#define mSKIP_STUB  mNOP

static void enableSkip(IAvbDriver* const /*drv*/, bool /*skip*/)
{
}

#else

#define mSKIP_STUB  mSKIP

static void enableSkip(IAvbDriver* const drv, bool skip)
{
    drv->enableSkipMessage(skip);
}
#endif
#endif

#if 0
static avb_1553_bc_message_t* myFrame[]=
{
/*   ms */
/*    0 */ &mC01, &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mI01, &mA2,  &mA3,           &mEND,
/*   10 */                                                              &mEND,
/*   20 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mB7,  &mI01, &mA1,                &mEND,
/*   30 */                                                              &mEND,
/*   40 */ &mC01, &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mA2,  &mI01, &mB1,  &mB2,  &mB3, &mEND,
/*   50 */ &mWRX,                                                             &mEND,
/*   60 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mI01, &mB7,  &mB6,                &mEND,
/*   70 */ &mSKIP, &mRDRTT, &mSKIP, &mINUTT,                                             &mEND,
/*   80 */ &mC01, &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mA2,  &mI01, &mA7,  &mA8,      &mEND,
/*   90 */ &mWTX,                                                             &mEND,
/*  100 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mA3,  &mI01, &mB7,                &mEND,
/*  110 */                                                             &mEND,
/*  120 */ &mC01, &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mI01, &mA2,  &mA1,           &mEND,
/*  130 */                                                             &mEND,
/*  140 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mB7,  &mB1,  &mB2,  &mI01, &mB3,      &mEND,
/*  150 */                                                              &mEND,
/*  160 */ &mC01, &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mI01, &mA2,  &mB6,           &mEND,
/*  170 */                          &mEND,
/*  180 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mB7,  &mA7,  &mA8,  &mI14,          &mEND,
/*  190 */ &mC01, &mD01, &mI06, &mI07, &mI09, &mI01, &mB8,                          &mFEND,

           0
};
#else

#if 0
static avb_1553_bc_message_t* myFrame[]=
{
/*   ms */
/*    0 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, &mA2,  &mA3,           &mEND,
/*   10 */ &mC01, &mI01,                                                                  &mEND,
/*   20 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, &mB7, &mA1,                &mEND,
/*   30 */ &mI01,                                                                       &mEND,
/*   40 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mA2,  &mB1,  &mB2,  &mB3, &mEND,
/*   50 */ &mWRX, &mC01, &mI01,                                                             &mEND,
/*   60 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mB7,  &mB6,               &mEND,
/*   70 */ &mB8, &mI01, /*&mSKIP, &mRDRTT, &mSKIP, &mINUTT,*/                                             &mEND,
/*   80 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mA2,  &mA7,  &mA8,      &mEND,
/*   90 */ &mWTX, &mC01, &mI01,                                                             &mEND,
/*  100 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mA3,  &mB7,                &mEND,
/*  110 */ &mI01,                                                            &mEND,
/*  120 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mA2,  &mA1,           &mEND,
/*  130 */ &mC01, &mI01,                                                            &mEND,
/*  140 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mB7,  &mB1,  &mB2,  &mB3,      &mEND,
/*  150 */ &mI01, /*&mSKIP_STUB, &mRDRTT_STUB, &mSKIP_STUB, &mINUTT_STUB,*/                           &mEND,
/*  160 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mA2,  &mB6,          &mEND,
/*  170 */ &mB8, &mC01, &mI01, /*&mRDRTT_ASYNCH,*/                        &mEND,
/*  180 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5,  &mB7,  &mA7,  &mA8,           &mEND,
/*  190 */ &mC01, &mD01, &mI06, &mI07, &mI09, &mI01, &mI14,  &mINUTT, &mRDRTT0, /*&mRDRTT_ASYNCH,*/ /*&mINUTT_ASYNCH,*/    &mFEND,

/*Asynch*/
//   &mRDRTT_ASYNCH,  &mRDRTT_ASYNCH, &mRDRTT_ASYNCH, &mINUTT_ASYNCH, &mRDRTT_ASYNCH,
           0
};
#endif

#define B_MTT   &mB11,&mB12,&mB13,&mB14,&mB15,&mB16,&mB17,&mB18,
//#define B_TWS   &mB1,  &mB2,  &mB3,
#define B_TWS

static avb_1553_bc_message_t* myFrame[]=
{
/*   ms */
/*    0 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mA2,  &mA3,           &mEND,
/*   10 */ &mC01, &mI01,                                                                  &mEND,
/*   20 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mB7, &mA1,                &mEND,
/*   30 */ &mI01,                                                                       &mEND,
/*   40 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mA2,  B_TWS &mEND,
/*   50 */ &mWRX, &mC01, &mI01,                                                             &mEND,
/*   60 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mB7,  &mB6,               &mEND,
/*   70 */ &mB8, &mI01, /*&mSKIP, &mRDRTT, &mSKIP, &mINUTT,*/                                             &mEND,
/*   80 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mA2,  &mA7,  &mA8,      &mEND,
/*   90 */ &mWTX, &mC01, &mI01,                                                             &mEND,
/*  100 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mA3,  &mB7,                &mEND,
/*  110 */ &mI01,                                                            &mEND,
/*  120 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mA2,  &mA1,           &mEND,
/*  130 */ &mC01, &mI01,                                                            &mEND,
/*  140 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mB7,  B_TWS      &mEND,
/*  150 */ &mI01, /*&mSKIP_STUB, &mRDRTT_STUB, &mSKIP_STUB, &mINUTT_STUB,*/                           &mEND,
/*  160 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mA2,  &mB6,          &mEND,
/*  170 */ &mB8, &mC01, &mI01, /*&mRDRTT_ASYNCH,*/                        &mEND,
/*  180 */ &mA4,  &mA5,  &mB9,  &mB10, &mB4,  &mB5, B_MTT &mB7,  &mA7,  &mA8,           &mEND,
/*  190 */ &mC01, &mD01, &mI06, &mI07, &mI09, &mI01, &mI14,  &mINUTT, &mRDRTT0, /*&mRDRTT_ASYNCH,*/ /*&mINUTT_ASYNCH,*/    &mFEND,

/*Asynch*/
//   &mRDRTT_ASYNCH,  &mRDRTT_ASYNCH, &mRDRTT_ASYNCH, &mINUTT_ASYNCH, &mRDRTT_ASYNCH,
           0
};

#endif


static McsG346ApplicationQ* g346Q;



class Msg_Set
{
public:
  GrifoMsg_A1B6 A1;
  GrifoMsg_A2B7 A2B7;
  GrifoMsg_B09B10 B09B10;
  GrifoMsg_A4A5 a4a5;
  GrifoMsg_A3 a3;
};

static Msg_Set* theMsg;

static avb_1553_data_buffer_t wraparound_tx_buffer;

static void wraparound_tx_routine(Ads1553MsgQ* msg)
{
#if 0
    static uint16_t base=0;
    for(int i=0; i<32; ++i)
    {
       wraparound_tx_buffer.data[i]=base+i;
    }
    ++base;
    Ads1553Manager::instance().writeDeviceBuffer(*msg, wraparound_tx_buffer);
#endif
}

static unsigned int last_insert;

static void wraparound_rx_routine(Ads1553MsgQ* msg)
{
    static Ads1553MsgQ* msgTT=Ads1553Manager::instance().getMsgObj("RDRTT");

    static unsigned int fail_signaled;
    static unsigned int total_fails;
    static unsigned int fails_led=10;
    static unsigned int total_msg;

    const avb_1553_word_t* d=msg->getBuffer();
    avb_1553_word_t received=d[0];
    avb_1553_word_t expected=wraparound_tx_buffer.data[0];
    avb_1553_word_t delay=expected-received;

    {
        static uint16_t base=0;
        static Ads1553MsgQ* wrapRx=Ads1553Manager::instance().getMsgObj("WT-RX");
        for(int i=0; i<32; ++i)
        {
           wraparound_tx_buffer.data[i]=base+i;
        }
        ++base;
        Ads1553Manager::instance().writeDeviceBuffer(*msg, wraparound_tx_buffer);
    }


    ++total_msg;

    if (delay>1)
    {
        ++total_fails;
        if (total_fails>60000)
            total_fails=1;
        if (fail_signaled==0)
        {
            qWarning()<<"Bus1553 Wraparound fail at"<<0<<received<<"!="<<expected;
            //qWarning()<<"AVB: last insert:"<<last_insert;
        }
        ++fail_signaled;
        if (fail_signaled>100)
            fail_signaled=0;
        msgTT->setDataNoSignal(2,total_fails);
        if (fails_led<10)
        {
            fails_led=10;
            msgTT->setDataNoSignal(3, 0);
        }
    }
    else
    {
        //if (fail_signaled || total_msg==1)
        //    qInfo()<<"Bus1553 Wraparound PASSED";
        fail_signaled=0;
        if (fails_led>=1)
        {
            --fails_led;
            if (fails_led==0)
            {
                msgTT->setDataNoSignal(3, 1);
                fails_led=9;
            }
        }
    }
/*
    for(int i=1; i<32; ++i)
    {
        if (d[i]!=wraparound_tx_buffer.data[i])
        {
            qWarning()<<"Wraparound fail at"<<i<<d[i]<<"!="<<wraparound_tx_buffer.data[i];
            break;
        }
    }
*/
}

static void B6_rdr_settings_tellback_async_message_routine(Ads1553MsgQ* msg)
{
  GrifoMsg_A1B6::b6_rdr_status_async_message_routine(msg);
}

static void B8_bite_async_message_routine(Ads1553MsgQ* msg)
{
  GrifoMsg_A1B6::b8_bite_async_message_routine(msg);
}

static void B6_bite_sync_message_routine(IAvbDriver* const /*drv*/, ads_1553msg_t* const msg, avb_microseconds_t tt)
{
    GrifoMsg_A1B6::b6_rdr_status_sync_message_routine(&(msg->desc.buffer->data[0]));
}

static unsigned int rdr_mode;
static QComboBox* rdrModeIndicator;

static void B7_rdr_status_async_message_routine(Ads1553MsgQ* msg)
{
  static unsigned int p_md_code;

  const msg_rdr_status_tellback_t& ststb=
      *reinterpret_cast<const msg_rdr_status_tellback_t*>(msg->getBuffer());

  rdr_mode=ststb.mode.master_mode.get();

  unsigned int m_code=ststb.mode.master_mode.get();
  unsigned int d_code=ststb.mode.design_sts.get();
  unsigned int md_code=m_code|(d_code<<16);

  {
    int n=int(m_code);
    switch(n)
    {
      case RWS:
        n+=(ststb.param1.rws_submode.get()) ? 17 : 16;
        break;
      case GM:
        n+=(ststb.param1.gm_submode.get()) ? 14 : 13;
        break;
      case ACM:
        n+=18+(ststb.param1.acm_submode.get());
        break;
      case BCN:
        n+=19+((ststb.param1.bars_num.get()==0) ? 0 : 1);
        break;
      default:
        break;
    }
    rdrModeIndicator->setCurrentIndex(n);
  }

  if (md_code!=p_md_code)
  {
    IGrifoMode* new_mode=&(modeOperation->defaultMode);
    if (mode_map.contains(md_code))
      new_mode=mode_map.value(md_code);

    if (current_mode)
    {
      current_mode->on_ModeExit();
      if (current_mode->if_gain)
      {
        *(current_mode->if_gain)=theMsg->A1.dIfGain.getValue();
      }
    }
    current_mode=new_mode;
    current_mode->on_ModeEnter();
    //if (current_mode->if_gain)
    //  theMsg->A1.dIfGain.setFromUser(*(current_mode->if_gain));
    //g346Q->setAutoPanels(current_mode->panel, current_mode->ctrlDock);
  }
  p_md_code=md_code;

  GrifoMsg_A2B7::b7_rdr_status_async_message_routine(msg);
}

class CursorMotion: public IAdsMouseGrabber, public QObject
{
public:
  int tid;

  int x;
  int y;
  int sx;
  int sy;

  int gx;
  int gy;
  bool gxy;

  GrifoCmdDock& cmdDock;

  AdsDataAction* act_left;
  AdsDataAction* act_right;
  AdsDataAction* act_middle;
  AdsDataAction* act_middle_release;

  QElapsedTimer crsTimer;

  CursorMotion(QMainWindow* parent, GrifoCmdDock& cmdDockRef):
      QObject(parent),
    cmdDock(cmdDockRef),
      act_left(0),
      act_right(0),
      act_middle(0),
      act_middle_release(0)
  {
    x=256;
    y=265;
    gxy=false;
    tid=0;
    setPos();
    cursor.setShape(Qt::SizeAllCursor);
  }
  void setPos()
  {
  }
  QPoint startPos;

  bool activate(const QPoint& /*p*/)
  {
    startPos=QCursor::pos();
    sx=0;
    sy=0;

    if (tid)
      killTimer(tid);
    tid=startTimer(100);
    return true;
  }
  bool mouseMove(QMouseEvent* /*e*/)
  {
    return true;
  }
  bool mousePress(QMouseEvent* e)
  {
    Qt::MouseButton b=e->button();
    if (b==Qt::LeftButton)
    {
      if (current_mode && current_mode->actLeftButton)
        current_mode->actLeftButton->execute();
      else if (act_left)
        act_left->execute();
    }
    if (b==Qt::RightButton)
    {
      if (current_mode && current_mode->actRightButton)
        current_mode->actRightButton->execute();
      else if (act_right)
        act_right->execute();
    }
    if (b==Qt::MiddleButton)
    {
      if (current_mode && current_mode->actMiddleButtonPress)
        current_mode->actMiddleButtonPress->execute();
      else if (act_middle)
        act_middle->execute();
    }
    return true;
  }
  bool mouseRelease(QMouseEvent* e)
  {
    Qt::MouseButton b=e->button();
    if (b==Qt::MiddleButton)
    {
      if (current_mode && current_mode->actMiddleButtonRelease)
        current_mode->actMiddleButtonRelease->execute();
      else if (act_middle_release)
        act_middle_release->execute();
    }
    return true;
  }

  bool mouseWheel(QWheelEvent *evn)
  {
    int delta=evn->delta();
    //qDebug()<<"Wheel:"<<delta;
    if (delta==0)
      return true;

    double d=delta>0 ? 0.5 : -0.5;
    if (!cmdDock.smartAntenna())
      theMsg->a4a5.move_antenna_el(true, d);
    else
    {
      double el=theMsg->A1.dElCentreTB.getValue()*theMsg->A1.dElCentreTB.getLsb();
      el+=d;
      theMsg->a4a5.set_antenna_el(true, el);
    }

    return true;
  }

  void cursorGotoXY(int x, int y)
  {
      if (tid==0)
      {
        //int curr_x=theMsg->A1.dCrsTbX.getValue();
        //int curr_y=theMsg->A1.dCrsTbY.getValue();
        //gx=x;
        //gy=y;
        gxy=true;
        activate(QPoint());
        //startPos.setX(curr_x);
        //startPos.setY(curr_y);
      }
      if (gxy)
      {
          int curr_x=theMsg->A1.dCrsTbX.getValue();
          int curr_y=theMsg->A1.dCrsTbY.getValue();
          gx=x;
          gy=y;
          startPos.setX(curr_x);
          startPos.setY(curr_y);
          //qDebug()<<"GXY"<<curr_x<<curr_y<<x<<y;
      }
  }

  void timerEvent(QTimerEvent *)
  {

    QPoint p=startPos;
    startPos=gxy ? QPoint(gx, gy) : QCursor::pos();
    QPoint d=startPos-p;

    //if (!d.isNull()) qDebug()<<"DXY"<<d;

    sx+=d.x();
    sy+=d.y();

    int idx=0;
    int idy=0;

    if (sx || sy)
    {
      float scale=gxy ? 1 : 0.100;      
      float rate=0.100;

      scale=0.100;

      double dx=double(sx)/scale;
      double dy=double(sy)/scale;


      idx=int(dx);
      idy=int(dy);

      if (idx>255)
        idx=255;
      else if (idx<-255)
        idx=-255;
      if (idy>255)
        idy=255;
      else if (idy<-255)
        idy=-255;

      theMsg->a4a5.move_cursor(true, idx, idy);

      if (crsTimer.isValid())
      {
          rate=crsTimer.restart()/1000.0;
      }

      dx=idx; //*rate;
      dy=idy; //*rate;

      if (dx<0)
          dx-=0.5;
      else
          dy+=0.5;
      if (dy<0)
          dy-=0.5;
      else
          dy+=0.5;
      int tmpx=sx;
      int tmpy=sy;

      sx-=dx;
      sy-=dy;

      tmpx=tmpx ^ sx;
      tmpy=tmpy ^ sy;
      if (tmpx<0)
          sx=0;
      if (tmpy<0)
          sy=0;
    }
    else
    {
      if (gxy)
      {
          deactivate();
      }
      else
          theMsg->a4a5.move_cursor(false);
    }

    if (theMsg->a4a5.a4_ant_slew.getValue()!=0)
      theMsg->a4a5.a4_ant_slew.setFromUser((int)0);
  }

  void abort()
  {
    deactivate();
  }

  void deactivate()
  {
    gxy=false;
    theMsg->a4a5.move_cursor(false);
    killTimer(tid);
    tid=0;
    crsTimer.invalidate();
  }
};


class AlertLedWidget: public QToolButton
{
public:
  AlertLedWidget(const char* const lbl, bool inverted=false, QWidget* parent=0):
      QToolButton(parent),
      inverted_logic(inverted)
  {
    static const QString style_direct(
      ":disabled { color: black; } "
      ":!checked { background-color: red; border: solid; font-weight: bold;} "
      ":checked  { background-color: green; color: black; border: solid;} "
      );
    static const QString style_inverted(
      ":disabled { color: black; } "
      ":pressed { background-color: yellow; border: solid; font-weight: bold;} "
      ":checked { background-color: red; border: solid; font-weight: bold;} "
      ":!checked  { background-color: green; color: black; border: solid; font-weight: bold;} "
      );
    setText(lbl);
    setStyleSheet(inverted ? style_inverted : style_direct);
    setDisabled(true);
    setCheckable(true);
    setChecked(true);
    setDown(true);
  }
  void setYellow()
  {
      static const QString style_direct_yellow(
        ":disabled { color: black; } "
        ":!checked { background-color: yellow; border: solid; font-weight: bold;} "
        ":checked  { background-color: green; color: black; border: solid;} "
        );
      static const QString style_inverted_yellow(
        ":disabled { color: black; } "
        ":checked { background-color: yellow; border: solid; font-weight: bold;} "
        ":!checked  { background-color: green; color: black; border: solid; font-weight: bold;} "
        );

      setStyleSheet(inverted_logic ? style_inverted_yellow : style_direct_yellow);
  }

  bool inverted_logic;
};

class AlertsToolBar: public QToolBar
{
public:
  AlertLedWidget& emergency;
  AlertLedWidget& overt;

  AlertLedWidget& stby;
  AlertLedWidget& fail;
  AlertLedWidget& ppsFail;
  AlertLedWidget& lcuFail;
  AlertLedWidget& pxFail;
  AlertLedWidget& aesaFail;

  AlertLedWidget& radiation;
  AlertLedWidget& overtempPx;
  AlertLedWidget& overtempAC;
  AlertLedWidget& overtempTX;
  AlertLedWidget& underpressure;
  AlertLedWidget& b1553_wraparound;
  AlertsToolBar():
    overt(*new AlertLedWidget("OVRT")),
    emergency(*new AlertLedWidget("EMERG", true)),
    stby(*new AlertLedWidget("STBY")),
    fail(*new AlertLedWidget("FAIL", true)),
    ppsFail(*new AlertLedWidget("PPS", true)),
    lcuFail(*new AlertLedWidget("LCU", true)),
    pxFail(*new AlertLedWidget("REP", true)),
    aesaFail(*new AlertLedWidget("AESA", true)),
    radiation(*new AlertLedWidget("RAD")),
    overtempPx(*new AlertLedWidget("PX", true)),
    overtempAC(*new AlertLedWidget("AC", true)),
    overtempTX(*new AlertLedWidget("PPS", true)), //old TX
    underpressure(*new AlertLedWidget("LCU", true)), //old Press
    b1553_wraparound(*new AlertLedWidget("WR"))
  {
    setObjectName("tb_Alarms");
    setWindowTitle("Radar Alarms");

    stby.setObjectName("led_ads_stby_tb");
    stby.setYellow();
    emergency.setObjectName("led_ads_emergency_tb");

    radiation.setObjectName("led_ads_rf_status");
    radiation.setYellow();

    fail.setObjectName("led_ads_rdr_fail");
    ppsFail.setObjectName("led_ads_pps_fail");
    lcuFail.setObjectName("led_ads_lcu_fail");
    pxFail.setObjectName("led_ads_px_fail");
    aesaFail.setObjectName("led_ads_aesa_fail");
    overtempPx.setObjectName("led_ads_rep_overt");
    overtempAC.setObjectName("led_ads_ant_overt");
    overtempTX.setObjectName("led_ads_pps_overt");
    underpressure.setObjectName("led_ads_lcu_overt");

    b1553_wraparound.setObjectName("led_ads_wraparound");
    b1553_wraparound.setToolTip("1553 Wraparound test");

    layout()->setSpacing(2);

    addWidget(&radiation);
    addWidget(&stby);
    addSeparator();
    addWidget(&fail);
    addSeparator();
    addWidget(&pxFail);
    addWidget(&ppsFail);
    addWidget(&lcuFail);
    addWidget(&aesaFail);
    //addSeparator();
    QLabel* lbl_ovt=new QLabel("Overtemp:");
    addWidget(lbl_ovt);
    addWidget(&overtempPx);
    addWidget(&overtempAC);
    addWidget(&overtempTX);
    addWidget(&underpressure);
    addSeparator();
    addWidget(&emergency);
    addSeparator();
    addWidget(&b1553_wraparound);
  }
};

static void fbegin_handler(IAvbDriver* const drv, unsigned int /*counter*/, avb_microseconds_t tt);

class Avio1553Initializer
{
public:
   Ads1553Manager& manager;

   Avio1553Initializer():
       manager(Ads1553Manager::instance())
   {
       manager.installTerminalList(terminal_list);
       manager.installMessages(myMsgList);
       manager.installFrame(myFrame, 10000);
       manager.setBeginOfMajorFrameHandler(fbegin_handler);
   }

};

class ConcreteMcsG346: public IAdsApplication
{
public:
  IAdsWorkBench& pWb;

  Avio1553Initializer avio1553Initializer;

  GrifoCmdDock& cmdDock;
  RdrStatusForm& stsForm;

  GrifoRdrControlForm& ctrlForm;
  GrifoTgtForm& tgtForm;
  GrifoSNUForm& snuForm;
  GrifoGfxForm& gfxForm;
  GrifoDlTgtForm& dlForm;
  GrifoSettingsForm& settForm;
  GrifoBiteForm& biteForm;

  CursorMotion crsGrabber;

  QToolBar& tbStatus;
  AlertsToolBar& tbAlerts;

  AdsLogicData dSynchRdr16;
  AdsLogicData dSynchInu16;
  AdsLogicData dSyncCounter;
  AdsLogicData dWraparoundFails;
  AdsLogicData dLedWraparound;

  //Widget

  ConcreteMcsG346(IAdsWorkBench& wb):
      pWb(wb),
      cmdDock(*new GrifoCmdDock),
      stsForm(*new RdrStatusForm),
      ctrlForm(*new GrifoRdrControlForm),
      tgtForm(*new GrifoTgtForm),
      snuForm(*new GrifoSNUForm),
      gfxForm(*new GrifoGfxForm),
      dlForm(*new GrifoDlTgtForm),
      settForm(*new GrifoSettingsForm),
      biteForm(*new GrifoBiteForm),
      crsGrabber(&wb.mainWindow(), cmdDock),
      tbStatus(*new QToolBar),
      tbAlerts(*new AlertsToolBar),
      dSynchRdr16("RdrSyncTimetag"),
      dSynchInu16("InuSyncTimetag"),
      dSyncCounter("CounterRdrSyncTimetag"),
      dWraparoundFails("WrapAroundFailsCounter"),
      dLedWraparound("wraparound")
  {
    //Ads1553Manager::instance().installTerminalList(terminal_list);
    //Ads1553Manager::instance().installMessages(myMsgList);
    //Ads1553Manager::instance().installFrame(myFrame, 10000);
    //Ads1553Manager::instance().setBeginOfMajorFrameHandler(fbegin_handler);

    dSynchRdr16.setLsb(relative_timetag_t::lsb());
    dSynchRdr16.attachToMsg(Ads1553Manager::instance().getMsgObj("RDRTT"), 0);

    dSynchInu16.setLsb(relative_timetag_t::lsb());
    dSynchInu16.attachToMsg(Ads1553Manager::instance().getMsgObj("INUTT"), 0);

    dSyncCounter.setLsb(1);
    dSyncCounter.attachToMsg(Ads1553Manager::instance().getMsgObj("RDRTT"), 1);

    dWraparoundFails.setLsb(1);
    dWraparoundFails.attachToMsg(Ads1553Manager::instance().getMsgObj("RDRTT"), 2);
    dWraparoundFails.setLsb(1);
    dLedWraparound.attachToMsg(Ads1553Manager::instance().getMsgObj("RDRTT"), 3);
    dLedWraparound.setFormat(0, 0x1);

    theMsg=new Msg_Set;

    AdsWidgetsManager::installForm(&cmdDock);
    AdsWidgetsManager::installForm(&ctrlForm);
    AdsWidgetsManager::installForm(&tgtForm);
    AdsWidgetsManager::installForm(&snuForm);
    AdsWidgetsManager::installForm(&stsForm);
    AdsWidgetsManager::installForm(&gfxForm);
    AdsWidgetsManager::installForm(&dlForm);

    AdsWidgetsManager::installForm(&settForm);
    AdsWidgetsManager::installForm(&biteForm);

    AdsWidgetsManager::installForm(&tbAlerts);

    //wb.mainWindow().addDockWidget(Qt::LeftDockWidgetArea, &cmdDock);
    wb.addAppDockWidget(&cmdDock, "Cmd");

    //wb.getTabArea()->addTab(&ctrlForm, QIcon(":/images/images/pilot-icon.png"), "Controls and Settings");
    {
        typedef std::map<const char*, QWidget*> wmap_t;
        wmap_t wmap
        {
            {"BITE", &biteForm},
            {"Settings", &settForm},
            {"Graphic", &gfxForm},
            {"DL", &dlForm},
            {"Targets", &tgtForm},
            {"SNU", &snuForm},
            {"Control", &ctrlForm}
        };
        for(auto i: wmap)
        {
            wb.addAppDockWidget(i.second, i.first);
        }

        wb.addAppDockWidget(0, QString());

#if 0
        QDockWidget* wdock0=0;
        auto dlist=wb.mainWindow().findChildren<QDockWidget*>();
        for(auto i: dlist)
        {
            if (i->)
        }
        QDockWidget* wdock=0;
        for(auto i: wmap)
        {
           wdock= new QDockWidget(i.first);
           wdock->setWidget(i.second);
           if (wdock0==0)
               wb.mainWindow().addDockWidget(Qt::RightDockWidgetArea, wdock);
           else
               wb.mainWindow().tabifyDockWidget(wdock0, wdock);
           wdock0=wdock;
        }
#endif
    }
#if 0
    QDockWidget* wdock0=new QDockWidget("Control & Settings");
    wdock0->setWidget(&ctrlForm);
    wb.mainWindow().addDockWidget(Qt::RightDockWidgetArea, wdock0);

    //wb.getTabArea()->addTab(&snuForm, QIcon(":/images/images/Safari-Aircraft-32.png"), "SNU");
    QDockWidget* wdock=new QDockWidget("SNU");
    wdock->setWidget(&snuForm);
    wb.mainWindow().tabifyDockWidget(wdock0, wdock);
    wock0=wdock;

    wb.getTabArea()->addTab(&tgtForm, QIcon(":/images/images/Recon-icon.png"), "Targets");
    wb.getTabArea()->addTab(&gfxForm, QIcon(), "Graphic");
    wb.getTabArea()->addTab(&settForm, QIcon(), "Settings");
    wb.getTabArea()->addTab(&biteForm, QIcon(), "BITE");
#endif

    crsGrabber.act_left=&(theMsg->A2B7.actLockon);
    crsGrabber.act_right=&(theMsg->A2B7.actReject);
    crsGrabber.act_middle=theMsg->A2B7.actSmartLockonBegin;
    crsGrabber.act_middle_release=theMsg->A2B7.actSmartLockonEnd; //&(theMsg->A2B7.actLockonStt);

    wb.installMouseGrabber(Qt::Key_Control, crsGrabber);

    tbStatus.setObjectName("tbGrifoStatus");
    tbStatus.setWindowTitle("Radar Status");
    tbStatus.addWidget(&stsForm);

    {
      rdrModeIndicator=&stsForm.rdrModeIndicator();
      rdrModeIndicator->addItems(
        QStringList()
            <<"RWS"
            <<"VS"
            <<"ACM"
            <<"TWS"
            <<"NV4"
            <<"GM"
            <<"SEA1"<<"SEA2"
            <<"GMTI"
            <<"BCN"
            <<"AGR"
            <<"TA"<<"WA"
            <<"NV13"<<"(ETET)"
            <<"DLY"
            <<"RWS/NAM"<<"RWS/ASM"
            <<"GM/RBM"<<"GM/DBS"
            <<"ACM/BORE"<<"ACM/ANRROW"<<"ACM/HUD"<<"ACM/WIDE"<<"ACM/VERT"<<"ACM/SLEW"<<"ACM/6"<<"ACM/7"
            <<"BCN/AS"<<"BCN/AA"
            );
      rdrModeIndicator->setStyleSheet(
        "  QComboBox { padding: 0 0 0 2px;} "
        "  :disabled { color: black;}"
        "  ::drop-down { "
        "  position: absolute;"
        "  left: 0;"
        "  subcontrol-origin: content;"
        "  border-style: none;"
        "  width: 0px;"
        "  border-width: 0;"
        " }"
        );
      QFont f=rdrModeIndicator->font();
      f.setBold(true);
      rdrModeIndicator->setFont(f);
    }
    wb.mainWindow().addToolBar(&tbAlerts);
    wb.mainWindow().addToolBar(&tbStatus);
    wb.mainWindow().insertToolBarBreak(&tbStatus);


    modeOperation=new GrifoModesInstance;

    modeOperation->defaultMode.if_gain=&(modeOperation->default_if_gain);
    modeOperation->defaultMode.panel=&ctrlForm;

    modeOperation->sar.if_gain=&(modeOperation->sar_if_gain);
    modeOperation->rbm.if_gain=&(modeOperation->default_if_gain);
    modeOperation->default_if_gain=30;
    modeOperation->sar_if_gain=30;
    modeOperation->sar.ctrlDock=1;

    modeOperation->sar.panel=&tgtForm;

    mode_map.insert(DS_STT, &modeOperation->sar);

    if (g346Q)
    {
      g346Q->connect(wb.getTabArea(), SIGNAL(currentChanged(int)), SLOT(tabChanged(int)));
      //g346Q->connect(&theMsg->A2B7.dMode, SIGNAL(sigUpdated()), SLOT(setTabByMode()));
      //g346Q->connect(&ctrlTB, SIGNAL(currentChanged(int)), SLOT(toolChanged(int)));
    }

    QAction* qStby=new QAction(&wb.mainWindow());
    qStby->setShortcutContext(Qt::ApplicationShortcut);
    qStby->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_F1));
    qStby->setStatusTip("STBY!");
    qStby->setText("STBY");
    AdsWidgetsManager::mapAction(theMsg->A2B7.actSTBY, *qStby);
    //wb.mainWindow().addAction(qStby);
    //theMsg->A2B7.actModeCycle.connect(qStby, SIGNAL(triggered()), SLOT(onQAction()));
    //(void)new AdsDataActionMap(&theMsg->A2B7.actModeCycle, qStby);

    grifo_sim_enable.rdr=rdr_term.mode==avb_term_simulated;
    grifo_sim_enable.inu=inu_term.mode==avb_term_simulated;
    grifo_sim_enable.ac=false;

  }


  virtual const char* getAppTitle()
  {
    return "G346-SCI50XXX-48.1.1";
  }

  virtual const char* getIcdName()
  {
      IcdInfo& info=Icd_GetInfo();
      return info.pn();
  }

  QString dataIniFileNmae() const
  {
      return "./g346_data.ini";
  }

  QString defaultSettingsFilename() const override
  {
      return dataIniFileNmae();
  }
  void saveSettings(const QString& iniFile=QString()) override
  {
    QString fname=iniFile.isEmpty() ? dataIniFileNmae() : iniFile;
    QSettings s(fname, QSettings::IniFormat);

    for(int i=0; myMsgList[i]; ++i)
    {
        ads_1553msg_t* m=myMsgList[i];
        if ((m->desc.tr==avb_rx) && (m->desc.sa!=0))
        {
            Ads1553MsgQ* msg=Ads1553Manager::instance().getMsgObj(m->desc.nickName);
            if (msg)
            {
                s.beginGroup(m->desc.nickName);
                for(int i=0; i<msg->wordCount(); ++i)
                {
                  s.setValue(QString("W%1").arg(i), (unsigned int)msg->data(i));
                }
                s.endGroup();
            }
        }
    }
    s.beginGroup("SAR");
    s.setValue("ifgain", *modeOperation->sar.if_gain);
    s.endGroup();
    s.beginGroup("RBM");
    s.setValue("ifgain", *modeOperation->rbm.if_gain);
    s.endGroup();

    s.beginGroup("Simulation");
    s.setValue("inuSmart", grifo_sim_enable.inu_smart);
    s.endGroup();

    s.beginGroup("Auto");
    s.setValue("linkSpoiCursor", grifo_sim_enable.link_spoi_to_cursor);
    s.endGroup();

#if 0
    Ads1553MsgQ* msg=Ads1553Manager::instance().getMsgObj("A1");
    if (msg)
    {
      s.beginGroup("A1");
      for(int i=0; i<msg->wordCount(); ++i)
      {
        s.setValue(QString("W%1").arg(i), (unsigned int)msg->data(i));
      }
      s.endGroup();
    }
#endif
  }
  void restoreSettings(const QString& iniFile=QString()) override
  {
    QString fname=iniFile.isEmpty() ? dataIniFileNmae() : iniFile;
    bool start_protection=iniFile.isNull();

    QSettings s(fname /*"./g346_data.ini"*/, QSettings::IniFormat);

    for(int i=0; myMsgList[i]; ++i)
    {
        ads_1553msg_t* m=myMsgList[i];
        if (m->desc.tr==avb_rx)
        {
            Ads1553MsgQ* msg=Ads1553Manager::instance().getMsgObj(m->desc.nickName);
            if (msg)
            {
                s.beginGroup(m->desc.nickName);
                for(int i=0; i<msg->wordCount(); ++i)
                {
                    msg->setData(i, s.value(QString("W%1").arg(i), 0).toUInt());
                }
                s.endGroup();
            }
        }
    }
    if (start_protection)
    {
        theMsg->A2B7.startProtection();
        theMsg->A1.startProtection();
    }

    s.beginGroup("SAR");
    int gain=s.value("ifgain").toInt();
    if (gain)
    {
        modeOperation->sar_if_gain=gain;
        *modeOperation->sar.if_gain=gain;
    }
    s.endGroup();
    s.beginGroup("RBM");
    gain=s.value("ifgain").toInt();
    if (gain)
    {
        modeOperation->default_if_gain=gain;
        *modeOperation->rbm.if_gain=gain;
    }
    s.endGroup();

    s.beginGroup("Simulation");
    grifo_sim_enable.inu_smart=s.value("inuSmart", 0).toInt();
    s.endGroup();

    s.beginGroup("Auto");
    grifo_sim_enable.link_spoi_to_cursor=s.value("linkSpoiCursor", 0).toBool();
    s.endGroup();

    this->snuForm.postInit();


#if 0
    Ads1553MsgQ* msg=Ads1553Manager::instance().getMsgObj("A1");
    if (msg)
    {
      s.beginGroup("A1");
      for(int i=0; i<msg->wordCount(); ++i)
      {
        msg->setData(i, s.value(QString("W%1").arg(i)).toUInt());
      }
      s.endGroup();
    }
#endif
  }
};

static ConcreteMcsG346* appInstance;

static int reset_antenna_slew;
static int reset_send_param;

static void fbegin_handler(IAvbDriver* const drv, unsigned int /*counter*/, avb_microseconds_t tt)
{
    static Ads1553MsgQ* msgTT=Ads1553Manager::instance().getMsgObj("RDRTT");

    //static int tt_out_trigger;
    //static int tt_out_reset_trigger;
    static unsigned int counter;

    if (!appInstance->snuForm.generateSyncTimetag())
      return;

    metricMeasure xx(G346Metric);

    if (!drv)
        return;
#if 1
    avb_microseconds_t tt_now=drv->getTimetag();
    unsigned int tt64=tt_now/64;
    uint16_t tt16=tt64;
    drv->writeSyncWord(0); //tt16);
    msgTT->setDataNoSignal(1, ++counter);
    msgTT->setDataNoSignal(0, tt16);
#endif

#if 0
    if (tt_out_reset_trigger)
    {
        ++counter;

        mG346Sync.stop();

        enableSkip(drv, true); //drv->enableSkipMessage(true);

        msgTT->setDataNoSignal(1, counter);
        tt_out_reset_trigger=0;
    }

    unsigned int stime=tt;
    unsigned short tt_low_16=(stime/64) & 0x0FFFF;
    unsigned int tt_low=tt_low_16;
    tt_low= tt_low & 0x0FFFF;

    unsigned int fix=70000/64;
    unsigned int tt_test=0x7A10U-(150000/64);
    if (tt_low<tt_test)
    {
      tt_out_trigger=1;
    }
    else
    {
        if (tt_out_trigger)
        {
          mG346Sync.start();

          tt_out_reset_trigger=1;
          tt_out_trigger=0;

          unsigned short tt_out=tt_low+fix;

#ifdef AVB_SKIP_BUG
          tt_out=0;
#endif
          drv->writeSyncWord(tt_out);
          enableSkip(drv, false); //drv->enableSkipMessage(false);
          //qWarning()<<"AVB SYNCH:"<<tt_out<<mRDRTT_ASYNCH.avbReserved_BcPos;
#ifdef AVB_SYNCH_USE_INSERT
          drv->insertMessage(&mRDRTT_ASYNCH);
          last_insert=mRDRTT_ASYNCH.avbReserved_BcPos;
#else
#endif

          msgTT->setDataNoSignal(0, tt_out);
          //msgA4->setDataNoSignal(1, counter);
        }
    }
#endif
    if (reset_antenna_slew>0)
    {
        --reset_antenna_slew;
        if (reset_antenna_slew<=0)
        {
            theMsg->a4a5.clear_antenna_slew();
        }
    }
    if (reset_send_param>0)
    {
        --reset_send_param;
        if (reset_send_param<=0)
        {
            theMsg->A1.sendRawParamater(-1, 0);
        }

    }
}

McsG346ApplicationQ::McsG346ApplicationQ()
{
    if (appInstance)
    {
        connect(&appInstance->cmdDock, &GrifoCmdDock::elevationMinus, this, &McsG346ApplicationQ::elevationMinus);
        connect(&appInstance->cmdDock, &GrifoCmdDock::elevationPlus, this, &McsG346ApplicationQ::elevationPlus);
        connect(&appInstance->cmdDock, &GrifoCmdDock::elevationZero, this, &McsG346ApplicationQ::elevationZero);

        connect(&appInstance->cmdDock, &GrifoCmdDock::waveformCommand, this, &McsG346ApplicationQ::sendWaveformCommand);
    }
}

void McsG346ApplicationQ::tabChanged(int /*t*/)
{
  //if (appInstance->checkAutoselect.checkState()!=Qt::Unchecked)
  //  appInstance->checkAutoselect.setCheckState(Qt::PartiallyChecked);
}

void McsG346ApplicationQ::toolChanged(int /*t*/)
{
  //if (appInstance->checkAutoTool.checkState()!=Qt::Unchecked)
  //  appInstance->checkAutoTool.setCheckState(Qt::PartiallyChecked);
}

/*
void McsG346ApplicationQ::setTabByMode()
{
  setTabByMode(theMsg->A2B7.dMode.getValue());
}
*/
void McsG346ApplicationQ::setAutoPanels(QWidget *dataPanel, int dockPanel)
{
  //Qt::CheckState oldCheck=appInstance->cmd

  //if (oldCheck==Qt::Checked)
  if (appInstance->cmdDock.autoSelectPanel())
  {
    appInstance->pWb.getTabArea()->setCurrentWidget(dataPanel);
    appInstance->cmdDock.selectControlDock(dockPanel);
    //appInstance->cmdDock.
  }
}

void McsG346ApplicationQ::modeChange(int mode)
{
}

void McsG346ApplicationQ::elevationPlus()
{
    theMsg->a4a5.move_antenna_el(true, 1); //0.017453293);
    reset_antenna_slew=2;
}

void McsG346ApplicationQ::elevationMinus()
{
    theMsg->a4a5.move_antenna_el(true, -1); //-0.017453293);
    reset_antenna_slew=2;
}

void McsG346ApplicationQ::elevationZero()
{
    theMsg->a4a5.set_antenna_el(true, 0);
    reset_antenna_slew=2;
}

void McsG346ApplicationQ::sendRawParameter(int id, unsigned int value)
{
    theMsg->A1.sendRawParamater(id, value);
    reset_send_param=4;
}

void McsG346ApplicationQ::sendWaveformCommand(int value)
{
    sendRawParameter(21, value);
}

#include <QSettings>
#include <QMessageBox>

IAdsApplication* AdsCreateApplicationInstance(IAdsWorkBench& wb)
{
  if (appInstance)
  {
    qDebug()<<"WARNING: trying to create multiple applicaiton instance";
    return appInstance;
  }

  QSettings s("./grifo_rt.ini", QSettings::IniFormat);
  s.beginGroup("RDR");
  bool sim=s.value("simulation", false).toBool();
  unsigned int rdr_rt=s.value("rdr_rt", 20).toUInt();
  s.endGroup();

  s.beginGroup("INU");
  bool sim_inu=s.value("simulation", true).toBool();
  s.endGroup();

  if (rdr_rt>0 && rdr_rt<31)
  {
    rdr_term.adr=rdr_rt;
  }

  if (sim)
  {
    if (QMessageBox::question(0, "Grifo MCS", "Simulation Mode?")==QMessageBox::Ok)
    {
      rdr_term.mode=avb_term_simulated;
      inu_term.mode=avb_term_disabled; //avb_term_simulated;
    }
  }
  //if (sim_inu)
  //  inu_term.mode=avb_term_disabled;

  appInstance=new ConcreteMcsG346(wb);
  g346Q=new McsG346ApplicationQ;
  return appInstance;
}


static void tt_synch_routine(IAvbDriver* const drv, ads_1553msg_t* const msg, avb_microseconds_t tt)
{
    static unsigned int counter;
    static Ads1553MsgQ* msgTT=Ads1553Manager::instance().getMsgObj("RDRTT");

    avb_microseconds_t tt_now=drv->getTimetag();
    unsigned int tt64=tt_now/64;
    uint16_t tt16=tt64;
    drv->writeSyncWord(tt16); //tt16);
    msgTT->setDataNoSignal(1, ++counter);
    msgTT->setDataNoSignal(0, tt16);
}

static void tt_asynch_routine(Ads1553MsgQ* msg)
{
    static unsigned int counter;
    static Ads1553MsgQ* msgTT=Ads1553Manager::instance().getMsgObj("RDRTT");

    msgTT->setDataNoSignal(1, ++counter);
    msgTT->setDataNoSignal(0, counter);
}
