#ifndef TRXBOARD_H
#define TRXBOARD_H

#include <QtConcurrent/QtConcurrent>
#include <chrono>
#include <thread>
#include <QVector>
#include <QString>
#include <QByteArray>
#include <QTime>
#include <QDebug>

#include "register/clockDistributer/ClockDistributer.h"
#include "register/boardsCtrlMngt/BoardsCtrlMngt.h"
#include "register/fpgaProgram/FpgaProgram.h"
#include "register/builtInTest/BuiltInTest.h"
#include "register/beamFormer/BeamFormer.h"
#include "register/scenPlayer/ScenPlayer.h"
#include "register/bpiFlash/BpiFlash.h"
#include "register/emulator/Emulator.h"
#include "register/debug/Debug.h"
#include "register/misc/Misc.h"
#include "register/sram/Sram.h"
#include "register/dsp/Dsp.h"
#include "register/afe/Afe.h"

#include "model/hardware/device/SonoDevice.h"
#include "TrxBoardUtils/TrxBoardStructures.h"
#include "TrxBoardUtils/ScenParamsRanges.h"
#include "TrxBoardUtils/PreProcessorDef.h"
#include "TrxBoardUtils/TrxBoardEnums.h"

#include "model/scenarioGenerator/core/general/Calculation.h"
#include "model/hardware/service/HardwarePacketEngine.h"

#define  SLAVE_ELEMENT_SEGMENT 64U
#define  TOTAL_SCEN_LUT_SRAM 6U
#define  MOUNTED_SLAVE_FPGA 7U
#define  CLOCK_DIVISION 0x55

#define  AFE_CHANNEL_NUM_PER_SLAVE 64U
#define  LOGGER_SAMPLE_CNT 2048U
#define  BITE_INTERVAL 0x0

#define  EEPROM_CRC_BEGIN 0U
#define  EEPROM_CRC_NUMBER 19U
#define  EEPROM_ID_BEGIN 19U
#define  EEPROM_ID_NUMBER 2U
#define  EEPROM_INFO_BEGIN 30U
#define  EEPROM_INFO_NUMBER 100U
#define  EEPROM_IMPULSE_RESPONSE_BEGIN 428U
#define  EEPROM_IMPULSE_RESPONSE_NUMBER 1024U

#define  EEPROM_NO_ERROR 0x0
#define  EEPROM_CRC_ERROR 0x1

class TrxBoard : public QObject
{
	Q_OBJECT

private:
    QVector<quint8> _swapVec;
    QVector<quint32> _unsignedQntzrVec;
    QList<quint32> _unsignedQntzrList;
	QList<quint32> _afeModuleOffset;
	QList<quint32> _fpgaOffset;
    QByteArray _eepromCrc;
	const quint32 _offsetSlave0;
	const quint32 _offsetSlave1;
	const quint32 _offsetSlave2;

	bool _allow;
	bool _run;
    qint32 _swCounter;
    qint32 _hwCounter;

    SonoDevice _device;
	AdcVoltages* _adc;
	VoltagesPg* _pg;
    FanRpm* _tachoRpm;
    criticalComponentVoltages* _coreVolt;
    criticalComponentTemperature* _coreTemp;

	ClockDistributer* _clkDistributer;
	BeamFormer* _beamFormerSlave0;
	BeamFormer* _beamFormerSlave1;
	BeamFormer* _beamFormerSlave2;
    BoardsCtrlMngt* _bCtrlMngt;
    BuiltInTest* _builtInTest;
    FpgaProgram* _fpgaProgram;
    ScenPalyer* _scenPlayer;
    Debug* _debugSlave0;
    Debug* _debugSlave1;
    Debug* _debugSlave2;
	BpiFlash* _bpiFlash;
	Afe* _afeSlave0;
	Afe* _afeSlave1;
	Afe* _afeSlave2;
	Emulator* _emul;
	Misc* _misc;
	Sram* _sram;
	Dsp* _dsp;

	enum eScenParams : quint8
	{
		clear,
		set
	};

    enum eActiveElements : quint8
    {
        slave0Elements,
        slave1Elements,
        slave2Elements
    };

    struct ScenHwRegister
	{
		///////////// BeamFormer /////////////
        QList<ApoParams> apodizationParams;
        ProbeElementPosition* elementPosition;
		RxBeamformerProperties* rxBeamformer;
		PulseProperties* pulse;
		quint8 pulseTypeNumber;
		quint8 rxBeamFormerTypeNumber;

		//////////////// DSP ////////////////
        QVector<float> freqStepLut;
        QVector<float> lpfWeightStepLut;
        QVector<float> startLpfWeightLut;
        QVector<float> freqLut;
		QVector<float> dtgcLut;
		ReceiverConfiguration* configLut;
        FreqPoint* freqPoint;
        QVector<QVector<float> > blendWeight;
        quint8 receiverConfigTypeNumber;
        QList<quint32> mlaOffsetAddr;
        QList<quint32> startFreqLut;
        QList<quint32> endFreqLut;
        quint32 noiseReject;
        quint32 frameLoggerControl;
        QList<quint8> lpfScaleCoeff;
        QList<Lpf> lpfLut;
        ScenHwRegister();
        ~ScenHwRegister();
	};

    struct ScenGenHardwareParam {
		quint32 focusTypeNumber;
		quint32 totalTxShotNumber;
        QVector<quint8> rxBeamFormerNumber;
		quint32 scenarioStartIndex;
		quint32 scenarioEndIndex;

        ScenHwRegister* hwRegister;
		SramIndex* indexParams;
		SramRx* rxParams;
		SramTx* txParams;
        ScenGenHardwareParam();
        ~ScenGenHardwareParam();
	}

    * _scenParams;

    void sendPacket(void);

    void delay(quint16 ms) const;
    void fpgaProgram(const QString path, const quint8& slaveMounted) const;
    void mcsRead(const QString path) const;
    void setScenario(ScenGenHardwareParam* _scenParams);

    void sramClear(eSramClear clearMode);
	void setSwapVector(void);
    void setRomCrc(void);
	void setFpgaOffset(void);
	void setAfeModuleOffset(void);
	void scenParamsFilling(eScenParams cmd);
    //QList<quint32> signedVector2unsignedList(QVector<qint32>& sgnVec);

#ifndef DEVELOP_UI
    void afeAdcsSync(const quint8& slaveMounted);
    void gtReadReset(void);
#endif
    void waitForCaptureDone(Debug* _dbg);
    void adcCaptureStop(Debug* _dbg) const;
    void adcCaptureStart(Debug* _dbg) const;
    void adcLogTransferRoutine(Debug* _dbg, quint8 chNumPerFpga);
    void debuggerMode(Debug* _dbg, DebugMode& debug, DebugMode& debugRb, QString slaveN) const;

    template<class T>
    QByteArray uintLittleEndian2ByteArray(T& data) const;

    template<class T>
    T byteArray2UintLittleEndian(QByteArray& byte) const;

signals:
    void sendFramePacket(QByteArray newPacket);

    void sramBinaryCreateFlag(void);
    void registerCsvCompareFlag(void);
    void sramVerifyMessage(QString message);

public:
#ifndef DEVELOP_UI
    HardwarePacketEngine packetEngine;
#else
    void afeAdcsSync(const quint8& slaveMounted);
    void gtReadReset(void);
#endif

	TrxBoard();
	~TrxBoard();

	///////////////////////////////// Initialize API //////////////////////////////
	void init(void);

    ////////////////////////////////// Scenario API ///////////////////////////////
    void setProbeDependParams(ScenPrbDepHardwareParam& prbDepParams);
    void setScenario(ScenHardware& scenGenHw);

	void setLineFilterCoefficient(QVector<float>& lineFilterLut);
	void setStbCoefficient(QVector<quint32>& stbLut);
	void setDtgcLut(QVector<float>& dtgcLut);

    void scenPlayerStart(bool afeHvPwrOn = false);
    void scenPlayerStop(bool afeHvPwrOff = false);
	//void scenPlayerPause (bool pause) const;

    void setFramesMetaData(const QByteArray& metaData) const;

    /////////////////////////////// Built-in Test API /////////////////////////////
    void setBiteDacData(const QByteArray& iData, const QByteArray& qData) const;
    void biteScenPlayerStart(void);
    void biteScenPlayerStop(void);

    ////////////////////////////////// UI Test API ////////////////////////////////
    void setScenarioCompare(const QString scenPath);
    void setAtgcMode(eAtgcMode mode, quint16 value) const;
    QList<quint32> getAfeReg(eSlaveSelect sel, quint32 afeRegAddr);
    void setAdgCfg(eBiteDacOutput adg) const;
    void setTxDacEnable(quint8 biteInterval, bool cmd) const;

    void powerAo(bool flag);

    ////////////////////////////// Slave Programming API //////////////////////////
    void slaveFpgaProgram(const QString path);

    /////////////////////////////// BeamFormer Mode API ///////////////////////////
	void setBeamFormerMode(eClkMode mode) const;

    ///////////////////////////////// Emulator API ////////////////////////////////
	void emulatorInit(EmulatorProperties* config) const;
    void fillRam(QString path);
    void emulatorStart(void);
	void emulatorStop(void);

    ////////////////////////////// BoardCtrlMngt API //////////////////////////////
	quint32 deviceId(void) const;
	quint32 vendorId(void) const;

    void trxState(EepromStatus& romStatus) const;
    void mpsState(EepromStatus& romStatus) const;
    void prbCtrlState(EepromStatus& romStatus) const;
    void selectedPrbState(EepromStatus& romStatus, eSelectProbe prbSel) const;
    void prbState(PrbCase* prb) const;

    QString trxInfo(void) const;
    QString mpsInfo(void) const;
    QString prbCtrlInfo(void) const;
    QByteArray selectedPrbImpulseResponse(quint8 prbSel) const;
    void prbImpulseResponse(ConnectedPrbInfo* prbInfo) const;

	void supervisorRbValue(SupervisorRbValue* sValue) const;
	void mpsFaultStatus(MpsFaultStatus* faultStatus) const;
    void mpsPwrOn() const;
    void mpsPwrOff() const;
	void mpsReset(void) const;
	void mpsSetAo(float voltA, float voltB) const;

    void selectProbe(eSelectProbe prbSel);
	void getHealthStatus(HealthStatus* healStat) const;

    //////////////////////////////// BPI Flash API ////////////////////////////////
	void mcsProgram(QString path);
	void mcsVerify(QString path) const;

    //////////////////////////////// Miscellaneous API ////////////////////////////
	void getTrxStatus(StatusVec* status) const;
	void getFpgasCodeVersion(FpgaCodeVersion* version) const;
    void sramParityClear();
    quint32 getFrameLostCounter(void) const;
    void elementActiveEnable(eActiveElements &slaveElements, quint64 &elements) const;

    ////////////////////////////////// Logger API /////////////////////////////////
    void adcCaptureConfig(captureConfig& capCfg) const;
    void adcCaptureStart(void) const;
    void adcCaptureDone(void);
    void setCaptureManualSync(void) const;
    void adcLoggerStart(const QString path, const QString fileName);
    void setDebuggerMode(eDebugMode bfMode, bool enable);
    void setAfeConfig(AfeConfig& afeCfg) const;
    void setAfePwr(eAfePwrdnMode pwrMode) const;

    /////////////////////////////// DMA Data Packet ///////////////////////////////
	void readData();
};

#endif //TRXBOARD_H