// HardwareIni.h: interface for the CHardwareIni class.
//
//////////////////////////////////////////////////////////////////////
#pragma once

#include <map>
#include <string>
#include <vector>

#include "gclib.h"
#include "gclibo.h"
// ETEL
#ifdef WITH_ETEL
#include "dsa30.h"
#endif

// Input Card
#define PCI_7433_ADLINK 0

// Input & Output Card
#define PCI_7296_ADLINK     1
#define PCI_9112_ADLINK     2
#define PCI_7851_ADLINK     3
#define PCI_7432_ADLINK     4 // 32 in, 32 out
#define PCI_9222_ADLINK     5 // AO, AI, Encoder, DI, DO card
#define PCI_7856_HSL_ADLINK 6
// advantech
#define PCI_1203_ETHERCAT_IO_ADVANTECH 7
#define MAX_INPUT_CARD_TYPE            8

// 7856 Port Definition
#define PCI_7856_HSL_PORT       0
#define PCI_7856_MOTIONNET_PORT 1

// Advantech EtherCAT Ring Definition
#define PCI_1203_MOTION_RING 0
#define PCI_1203_IO_RING     1

// Output Card
#define PCI_7434_ADLINK      0
#define MAX_OUTPUT_CARD_TYPE MAX_INPUT_CARD_TYPE

// note that the output array size is set based on 6*16*144 = 13824 output pts total
// 1 card type can have max 16*144=2304 output pts
#define MAX_CARD_TYPE            MAX_OUTPUT_CARD_TYPE
#define MAX_CARD_FOR_EACH_TYPE   16
#define MAX_POINTS_FOR_EACH_CARD 144

// for remote IO 7851, max IO 63*32=2016. This value must be smaller than 2304 (as above).
// for remote IO 7856 (HSL), max IO 63*32=2016. This value must be smaller than 2304 (as above).
#define MAX_SLAVE_ID                 63
#define MAX_POINTS_FOR_EACH_SLAVE_ID 32

// ETEL
#define MAX_ETEL_AXIS 32

enum CARD_TYPE
{
    INPUT_CARD,
    OUTPUT_CARD,
    MOTION_CARD,
    ENCODER_CARD
};

enum INPUT_STATE
{
    INPUT_UNKNOWN,
    INPUT_ON,
    INPUT_OFF,
};

enum INPUT_CARD_INIT_RESULT
{
    INPUT_CARD_INIT_FAIL,
    INPUT_CARD_INIT_PASS,
};

enum INPUT_CARD_CLOSE_RESULT
{
    INPUT_CARD_CLOSE_FAIL,
    INPUT_CARD_CLOSE_PASS,
};

enum OUTPUT_CARD_INIT_RESULT
{
    OUTPUT_CARD_INIT_FAIL,
    OUTPUT_CARD_INIT_PASS,
};

enum OUTPUT_CARD_CLOSE_RESULT
{
    OUTPUT_CARD_CLOSE_FAIL,
    OUTPUT_CARD_CLOSE_PASS,
};

// class CIniFile;
#include "Utility.h"

#ifdef BUILD_IODLL
#define IODLLCLASS __declspec(dllexport)
#else
#define IODLLCLASS __declspec(dllimport)
#endif

class CMtrProfile;

class IODLLCLASS CHardwareIni : public CIniFile
{
public:
    CHardwareIni();
    virtual ~CHardwareIni();

    BOOL        GetChannelConfig(int nCardType, int nCardNo, int nNoOfChannel, int* npChannelArray, int nWhatCard);
    int         GetSharing(int nCardType, int nCardNo, int nWhatCard);
    int         GetNoOfDifferentCardType(int nWhatCard);
    std::string GetCardName(int nCardTypeNo, int nWhatCard);

    // read from hardware ini file for any hardware cards info used on the machine

    // get the no of card of different card category
    int GetNoOfCard(int nCardTypeNo, int nWhatCard);

    // get the no of encoder card type, eg 1
    int GetEncoderCardTypeNo(int nCardTypeNo);

    // get the name of the encoder card type, eg 8133
    std::string GetEncoderCardType(int nCardTypeNo);

    // get the different no of encoder card used in the machine
    int GetNoOfEncoderCardType(void);
private:
    BOOL SetIniFile(int nWhatCard);
};

using stCard = struct _stCard
{
    std::string strCardType; // standardise to std for portability
    BOOL        Initialised;
    // ctor
    _stCard(const std::string& _strCardType = "NoCard", BOOL _Initialised = FALSE)
    {
        strCardType = _strCardType;
        Initialised = _Initialised;
    }
};
//
using union_uint = union _union_uint
{
    unsigned int uintValue;
    struct
    {
        unsigned short lo;
        unsigned short hi;
    } s;
    unsigned char byte[4];

    // ctor
    _union_uint()
    {
        uintValue = 0;
    }
};

// Advantech EtherCAT
// Bit Definition
// 0 RDY-- RDY pin input
// 1 ALM -- Alarm signal input
// 2 LMT+-- Limit switch+
// 3 LMT-- Limit switch-
// 4 ORG-- Original switch
// 5 DIR -- DIR output
// 6 EMG -- Emergency signal input
// 7 PCS -- PCS signal input
// 8 ERC -- Output offset counter clear signal to servo motor drvier
// 9 EZ -- Encoder Z signal
// 10 CLR -- External output toward clear position counter
// 11 LTC -- Latch signal input
// 12 SD -- Deceleration signal input
// 13 INP -- In-position signal input
// 14 14: SVON -- Servo On (OUT6)
// 15 ALRM -- Alarm reset output status
// 16 SLMT+ -- Softwarte limit+
// 17 SLMT-- Softwarte limit -
// 18 CMP--Compare signal
enum ACM_AX_MIO
{
    MIO_RDY = 0x00000001, // AX_MOTION_IO_RDY
    MIO_ALM = 0x00000002, // AX_MOTION_IO_ALM
    MIO_PEL = 0x00000004, // AX_MOTION_IO_LMTP
    MIO_MEL = 0x00000008,

    MIO_ORG = 0x00000010,
    MIO_DIR = 0x00000020,
    MIO_EMG = 0x00000040,
    MIO_PCS = 0x00000080,

    MIO_ERC = 0x00000100,
    MIO_EZ  = 0x00000200,
    MIO_CLR = 0x00000400,
    MIO_LTC = 0x00000800,

    MIO_SD      = 0x00001000,
    MIO_INP     = 0x00002000,
    MIO_SVON    = 0x00004000,
    MIO_ALM_RST = 0x00008000,

    MIO_SPLIM = 0x00010000,
    MIO_SNLIM = 0x00020000,
    MIO_CMP   = 0x00040000,
};

// Bit Definition
// 0 Stop. Stop
// 1 Res1. Reserved
// 2 WaitERC. Wait ERC finished
// 3 Res2. Reserved
// 4 CorrectBksh. Correcting Backlash;
// 5 Res3. Reserved
// 6 InFA. Feeding in return velocity= FA
// 7 InFL. Feeding in StrVel speed=FL;
// 8 InACC. Accelerating
// 9 WaitINP. Wait in position.
enum ACM_AX_MST
{
    MST_STOP     = 0x1,
    MST_RES1     = 0x2, // Reserved
    MST_WAIT_ERC = 0x4,
    MST_RES2     = 0x8, // Reserved

    MST_BACKLASH_CORRECTION = 0x10, // Correcting Backlash;
    MST_RES3                = 0x20, // Reserved
    MST_FEEDING_FA          = 0x40, // Feeding in return velocity= FA
    MST_FEADING_FL          = 0x80, // Feeding in StrVel speed=FL;

    MST_ACCEL    = 0x100, // 8 InACC. Accelerating
    MST_WAIT_INP = 0x200, // Wait in position.

};

// Galil
enum Galil_Axis
{
    AXIS_X,
    AXIS_Y,
    AXIS_Z,
    AXIS_W,
    AXIS_E,
    AXIS_F,
    AXIS_G,
    AXIS_H,
    MAX_GALIL_AXIS
};

const char GalilAxis[MAX_GALIL_AXIS] = {
    'X', 'Y', 'Z', 'W', 'E', 'F', 'G', 'H'
};

class CCard
{
public:
    CCard();
    virtual ~CCard();

    int  GetOutputCardInitIndex(int nCardType, int nCardNo);
    int  GetInputCardInitIndex(int nCardType, int nCardNo);
    void SetOutputCardInitIndex(int nCardType, int nCardNo, int nIndexNo);
    void SetInputCardInitIndex(int nCardType, int nCardNo, int nIndexNo);
    long GetOutputStatusSize() const;
    BOOL GetOutputStatus(int nCardType, int nCardNo, int nPoint);
    void SetOutputStatusSize(long lSize);
    // Update the Output Status for read back
    void SetOutputStatus(int nCardType, int nCardNo, int nPoint, BOOL bLogic);

    // set / get Advantech Device Number
    UINT_PTR GetAcmDeviceHandle(int nCardNo);
    void     SetAcmDeviceHandle(int nCardNo, UINT_PTR hDevHandle);
    //
    GCon              GetGalilCardHandle(int nCardType, int nCardNo);
    void              SetGalilCardHandle(int nCardType, int nCardNo, GCon hDMC);
    int               Get7296PortNo(int nPoint);
    BOOL              GetOutputStatus(int nIndex) const;
    std::vector<BOOL> GetOutputStatus();

    // Advantech : to get device number which is need to open the device handle
    ULONG GetAcmDeviceNum(ULONG DevType, ULONG BoardID, ULONG MasterRingNo, ULONG SlaveBoardID);
    //
    void     RegisterAxisHandle(const CMtrProfile& mtrProfile, UINT_PTR hAxis);
    UINT_PTR GetAxisHandle(const CMtrProfile& mtrProfile);

    bool m_bTraceData{ false };

    bool m_bBenchDebug{ false };

protected:
    // for 8134
    static HANDLE m_hMotionIntArr[32];    // each axis has 1 int event
                                            // for 8164
    static HANDLE m_h8164MotionIntArr[32];  // each axis has 1 int event
                                            // for Galil Optima series
    static HANDLE m_hGalilMotionIntArr[32]; // each axis has 1 int event

    // 7856 MotionNet - cater up to 64 axis
    static HANDLE m_h7856MotionIntArr[64]; // each axis has 1 int event

    // Advantech EtherCAT - cater up to 64 axis / card   max 16 card
    static HANDLE m_hAdvantechMotionIntArr[16][64]; // each axis has 1 int event

    // Advantech Card Handle - cater 16 card
    static UINT_PTR m_hAcmDeviceHandle[16]; // each card has 1 handle

#ifdef WITH_ETEL
    // ETEL - per axis handle
    static DSA_DRIVE* m_ETEL_DSA_DRIVE[MAX_ETEL_AXIS]; // cater up to 32 ETEL Axis
#endif

private:
    // cater tracking for upto 16 brands
    static int m_nCardsPerBrand[MAX_CARD_FOR_EACH_TYPE];

    // track the input cards initialised Index
    // currently this is used for AdLink PCI IO Cards
    // for up to 6 different type of cards with 16 cards in each type per system
    static int m_nInputCardIndex[MAX_CARD_TYPE][MAX_CARD_FOR_EACH_TYPE];

    // track the output cards initialised Index
    // currently this is used for AdLink PCI IO Cards
    // for up to 6 different type of cards with 16 cards in each type per system
    static int m_nOutputCardIndex[MAX_CARD_TYPE][MAX_CARD_FOR_EACH_TYPE];

    // tracking of output point status for read back purpose
    // cater for 6 different output cards type
    // 16 cards per type
    // 144 points per card
    //    static bool m_nOutputStatus[MAX_CARD_TYPE][MAX_CARD_FOR_EACH_TYPE][MAX_POINTS_FOR_EACH_CARD];
    // for output tracking
    static std::vector<BOOL> m_bOutputArray;
    //
    // track the Galil cards initialised handle
    // currently this is used for Galil Cards only
    // for up to 5 different type of cards with 5 cards in each type per system
    static GCon m_hdmcGalil[5][5];

    static std::map<unsigned int, UINT_PTR> m_mapAxisHandle;
};
