#ifndef COSY_Dkc
#define COSY_Dkc

#ifndef COSY_NodeDrv
#include "nodedrv.h"
#endif

#ifndef MARS_MTime
#include "MTime.h"
#endif

class TGLabel;

class Dkc : public NodeDrv
{
private:
    BYTE_t   fMacId;

    LWORD_t  fSoftVersion;

    LWORD_t  fPosRes;
    LWORD_t  fVelMax;
    LWORD_t  fVelRes;
    LWORDS_t fVel;

    LWORDS_t fPdoPos1;
    LWORDS_t fPdoPos2;
    MTime    fPdoTime1;
    MTime    fPdoTime2;

    BYTE_t   fPosActive;
    BYTE_t   fRpmActive;
    BYTE_t   fStatus;
    LWORD_t  fStatusDKC;
    BYTE_t   fStatusPdo3;

    bool fHasChangedPos1;  //!
    bool fHasChangedPos2;  //!

    bool fArmed;

    MLog *fReport;

    TGLabel  *fLabel;     //
    LWORDS_t  fUpdPos;    // ticks

    void Init();
    void StopDevice();

    TString EvalStatusDKC(UInt_t stat) const;
    Bool_t  PrintStatus(LWORD_t val) const;
    Bool_t  EvalStatus(UInt_t errnum, UInt_t errinf) const
    {
        return PrintStatus(errnum|(errinf<<16));
    }
    TString GetStatus(LWORD_t val) const;
    void CheckErrorDKC(LWORD_t val);
    void CheckErrorDKC(UInt_t errnum, UInt_t errinf)
    {
        CheckErrorDKC(errnum|(errinf<<16));
    }


    void HandleSDO(WORD_t idx, BYTE_t subidx, LWORD_t val, const timeval_t &tv);
    void HandleSDOOK(WORD_t idx, BYTE_t subidx, LWORD_t data, const timeval_t &tv);

    void HandlePDO1(const BYTE_t *data, const timeval_t &tv);
    void HandlePDO2(const BYTE_t *data, const timeval_t &tv);
    void HandlePDO3(const BYTE_t *data, const timeval_t &tv);

    void CheckConnection();

public:
    Dkc(const BYTE_t nodeid, const char *name=NULL);
    virtual ~Dkc();

    static LWORD_t string(BYTE_t b0=0, BYTE_t b1=0, BYTE_t b2=0, BYTE_t b3=0)
    {
        return (LWORD_t)(b0<<24 | b1<<16 | b2<<8 | b3);
    }

    void SendMsg(BYTE_t data[6]);
    void SendMsg(BYTE_t d0=0, BYTE_t d1=0, BYTE_t d2=0,
                 BYTE_t d3=0, BYTE_t d4=0, BYTE_t d5=0);

    void ReqPos1();
    void ReqPos2();
    void ReqVel();
    void ReqVelRes();
    void ReqPosRes();
    void ReqVelMax();
    void SetAcceleration(LWORD_t acc);
    void SetDeceleration(LWORD_t dec);
    void SetVelocity(LWORD_t vel);
    void SetVelocityRel(Double_t vel);
    void SetRpmMode(BYTE_t mode=TRUE);
    void SetRpmVelocity(LWORDS_t cvel);
    void SetPDO1On(BYTE_t flag=TRUE);

    void StartVelSync();
    void StartPosSync();

    void StartRelPos(LWORDS_t pos);
    void StartAbsPos(LWORDS_t pos);
    void StartAbsPosRev(Double_t pos);

    void StartNode();

    bool IsArmed() const { return fArmed; }
    void Arm();
    void Disarm();

    int IsPositioning() const { return fPosActive; }
    BYTE_t GetStatus() const { return fStatus; }
    BYTE_t GetStatusPdo3() const { return fStatusPdo3; }

    LWORDS_t GetPdoPos1() const { return fPdoPos1; }
    LWORDS_t GetPdoPos2() const { return fPdoPos2; }

    LWORDS_t GetVel()    const { return fVel; }
    LWORD_t  GetVelMax() const { return fVelMax; } // Velocity units (would be 100 for %)
    Double_t GetVelMaxRev() const { return (Double_t)fVelMax/fVelRes; } // Velocity units (would be 100 for %)
    LWORD_t  GetVelRes() const { return fVelRes; } // Velocity units (would be 100 for %)
    LWORD_t  GetPosRes() const { return fPosRes; } // Velocity units (would be 100 for %)

    bool IsOperative() const { return fStatusPdo3==0xef; }

    void HandleError();

    Double_t GetMjdPos1() const { return fPdoTime1.GetMjd(); }
    Double_t GetMjdPos2() const { return fPdoTime2.GetMjd(); }

    bool HasChangedPos1() const { return fHasChangedPos1; }
    bool HasChangedPos2() const { return fHasChangedPos2; }

    void ResetHasChangedPos1() { fHasChangedPos1 = false; }
    void ResetHasChangedPos2() { fHasChangedPos2 = false; }

    TString GetStatusDKC() const { return GetStatus(fStatusDKC); }

    void SetReport(MLog *log) { fReport = log; }
    void SetDisplay(TGLabel *label) { fLabel = label; }

    void DisplayVal();

    ClassDef(Dkc, 0)
};

#endif
