#include "cmallsystem.h"
#include "logic.h"
#include "cmakepath.h"
#include <QApplication>
#include "vsmt_load.h"
#include "vsmt_unload.h"
#include "ccam_basler.h"
#include "ccamdriver_basler.h"
#include "def_logic.h"
#include "cdistancemeterdriver_hl.h"
#include "ceventrecord.h"
#include "cdebug_logger.h"
#include "clog_impl.h"
//CMAllsystem m_gSystem;
inline bool IsRunAtLaptop()
{
    static bool bAtLaptop = false;
    static bool bfirst = true;
    if (bfirst) {
        bfirst = false;
        SYSTEM_POWER_STATUS a;
        GetSystemPowerStatus(&a);
        bAtLaptop = (a.BatteryFlag != 128 && a.BatteryFlag != 255);
    }
    return bAtLaptop;
}

//CMAllsystem& GetInstance()
//{
//    return CMAllsystem::GetInstance();
//}

CMAllsystem::CMAllsystem()
    : CSystemExternal()
{
    m_iCellSize = 8;
    m_bNeedFreshUI = false;
    m_iCurChID = 0;

    m_bCamMove = false;
    m_bEnableCycle = false;
    m_bOnlyLeveling = false;
    m_bOnlyLocation = false;
    m_bOnlyASide = false;
    m_bOnlyBSide = false;
    m_bPausedAfterLocation = false;
    m_bPausedAfterLeveling = false;
    m_bDisableCutlineLaser = false;
    m_bDisableHairlineOffsetAutoCompensation = true;
    m_iMatchType = M_MATCHNCC;
    m_bScanTwoSensor = false;
    m_bSimulatorLeveling = false;
    m_bSimulatorLocation = false;

    m_iCurChID = CAM2X;
    m_iCurSideID = -1;
    m_iCurProcessID = -1;
    m_iCurLine = -1;
    m_iCurLayer = -1;

    m_pMWCamLight2X = 0;
    m_pMWCamLight6X = 0;
#ifdef __USE_THIRD_CAMERA__
    m_pMWCamLight4X = 0;
#endif

    m_bMoveInitPos = true;
    m_LaserGateDelay = 3.68;
    m_LaserGateDelayEnd = 4.12;

    m_bEnbaleLaserOpen = true;
    m_iAsideStart = -1;
    m_iAsideEnd = -1;
    m_iBsideStart = -1;
    m_iBsideEnd = -1;
    m_strserialID = "LS1530G";

    m_iCoatPreSpayWaitTimeMs = 3000;
    m_bStopAfterFinish = false;
#ifdef __SIMULATOR__
    m_iTotalCuttedWafer = 2;
#else
    m_iTotalCuttedWafer = 0;
#endif
    m_totalWorkHour = 0;
    m_fullAutoTime.ClearTime();
    m_fullAutoTime.StopTime();
    m_lineTime.ClearTime();
    m_totalCleanTime.StopTime();
    m_cellTime.ClearTime();
    m_totalCleanTime.StopTime();
    m_totalCoatTime.ClearTime();
    m_totalCoatTime.StopTime();
    m_totalCleanTime.StopTime();
    m_totalCleanTime.ClearTime();
    m_totalCleanTime.StopTime();
    m_bAllSMStoped = true;
    m_bIsSimulator = IsRunAtLaptop();
    SetLotId("NotSet");

    auto s_logger = std::make_shared<lp::FileLogger>();
    lp::ILogFactory::GetInstance().RegisterLogInstance(s_logger, lp::ELogType::kError);

    auto s_debugLogger = std::make_shared<lp::CDebugLogger>();
    lp::ILogFactory::GetInstance().RegisterLogInstance(s_debugLogger, lp::ELogType::kDebug);
}

CMAllsystem::~CMAllsystem()
{

}


void CMAllsystem::initNameList()
{
    m_mapNameList[CAM2X] = QObject::trUtf8("CAM2X");
    m_mapNameList[CAM6X] = QObject::trUtf8("CAM6X");
    m_mapNameList[CAM_DRIVER] = QObject::trUtf8("CAM_DRIVER");

    m_mapNameList[LIGHT_DIRECT2X] = QObject::trUtf8("DIRECT2X");
    m_mapNameList[LIGHT_SIDE2X] = QObject::trUtf8("SIDE2X");
    m_mapNameList[LIGHT_DIRECT6X] = QObject::trUtf8("DIRECT6X");
    m_mapNameList[LIGHT_SIDE6X] = QObject::trUtf8("SIDE6X");
    m_mapNameList[LIGHT_DRIVER_DIRECT] = QObject::trUtf8("DRIVER");

    m_mapNameList[MOTORX] = QObject::trUtf8("X_WT");
    m_mapNameList[MOTORY] = QObject::trUtf8("Y_WT");
    m_mapNameList[MOTORZ] = QObject::trUtf8("Z_WT");
    m_mapNameList[MOTORW] = QObject::trUtf8("W_WT");

    m_mapNameList[MOTORG1_PCHANGE] = QObject::trUtf8("G1_PG");
    m_mapNameList[MOTORG2_POWER] = QObject::trUtf8("G2_PW");
    m_mapNameList[MOTORG3_WIDEINDEX] = QObject::trUtf8("G3_WI");
    m_mapNameList[MOTORG4_WIDE5050] = QObject::trUtf8("G4_W50");
    m_mapNameList[MOTORG5_NARROWINDEX] = QObject::trUtf8("G5_NI");
    m_mapNameList[MOTORG6_NARROW5050] = QObject::trUtf8("G6_N50");
    m_mapNameList[MOTORG7_MASK] = QObject::trUtf8("G7_MK");

    m_mapNameList[MOTORA_CLAW] = QObject::trUtf8("A_CW");
    m_mapNameList[MOTORB1_LOCK] = QObject::trUtf8("B1_LK");
    m_mapNameList[MOTORB2_RAIL] = QObject::trUtf8("B2_LK");
    m_mapNameList[MOTORC_CASS] = QObject::trUtf8("C_CS");
    m_mapNameList[MOTORD_TRANS] = QObject::trUtf8("D_TR");

    m_mapNameList[MOTORE_COAT_SPINDLE] = QObject::trUtf8("E_SPN");
    m_mapNameList[MOTORE1_COAT_CLEAN_ARM] = QObject::trUtf8("E1_CLM");
    m_mapNameList[MOTORE2_COAT_COAT_ARM] = QObject::trUtf8("E2_COM");
    m_mapNameList[MOTORE3_COAT_BUMP] = QObject::trUtf8("E3_BP");
    m_mapNameList[MOTORE4_COAT_CURTAIN] = QObject::trUtf8("E4_CR");

    m_mapNameList[MOTORF_CLEAN_SPINDLE] = QObject::trUtf8("F_SPN");
    m_mapNameList[MOTORF1_CLEAN_ARM] = QObject::trUtf8("F1_CLM");
    m_mapNameList[MOTORF4_CLEAN_CURTAIN] = QObject::trUtf8("F2_CR");

    m_mapNameList[IO_INPUT] = QObject::trUtf8("IO_INPUT");
    m_mapNameList[IO_OUTPUT] = QObject::trUtf8("IO_OUTPUT");
    m_mapNameList[IO_INPUT_ANALOG] = QObject::trUtf8("IO_INPUT_ANALOG");
    m_mapNameList[IO_OUTPUT_ANALOG] = QObject::trUtf8("IO_OUTPUT_ANALOG");

    m_mapNameList[MOTOR_DRIVER] = QObject::trUtf8("MOTOR_DRIVER");

    m_mapNameList[LASER] = QObject::trUtf8("LASER");
    m_mapNameList[LASER_DRIVER] = QObject::trUtf8("LASER_DRIVER");

    m_mapNameList[POWERMETERHEAD] = QObject::trUtf8("POWERMETER");
    m_mapNameList[POWERMETERHEAD_REALTIME] = QObject::trUtf8("POWERMETER_RT");
    m_mapNameList[POWERMETERDRIVER] = QObject::trUtf8("POWERMETERDRIVER");

    m_mapNameList[BARCODE] = QObject::trUtf8("BARCODE");
    m_mapNameList[BARCODE_DRIVER] = QObject::trUtf8("BARCODE_DRIVER");

    //m_mapNameList[LASERPATH_D_NARROW] = QObject::trUtf8("D_NARROW");
    //m_mapNameList[LASERPATH_D_WIDE] = QObject::trUtf8("D_WIDE");
    m_mapNameList[LASERPATH_D_NARROW] = "D_NARROW";
    m_mapNameList[LASERPATH_D_WIDE] = "D_WIDE";
    m_mapNameList[LASERPATH_DRIVER] = QObject::trUtf8("LASERPATH_DRIVER");

    m_mapNameList[M_WORKER] = QObject::trUtf8("M_WORKER");
    m_mapNameList[M_WORKERDRIVER] = QObject::trUtf8("M_WORKERDRIVER");

    m_mapNameList[GEM_CLIENT] = QObject::trUtf8("GEM_CLIENT");
    m_mapNameList[GEM_DRIVER] = QObject::trUtf8("GEM_DRIVER");

    m_mapNameList[M_BLOB] = QObject::trUtf8("M_BLOB");
    m_mapNameList[M_FINDCIRCE] = QObject::trUtf8("M_FINDCIRCE");
    m_mapNameList[M_FINDEAGE] = QObject::trUtf8("M_FINDEAGE");
    m_mapNameList[M_FINDLINEEAGE] = QObject::trUtf8("M_FINDLINEEAGE");
    m_mapNameList[M_FINDARCEAGE] = QObject::trUtf8("M_FINDARCEAGE");
    m_mapNameList[M_MATCHGRAY] = QObject::trUtf8("M_MATCHGRAY");
    m_mapNameList[M_MATCHNCC] = QObject::trUtf8("M_MATCHNCC");
    m_mapNameList[M_MATCHSHAPE] = QObject::trUtf8("M_MATCHSHAPE");
    m_mapNameList[M_FINDLINE] = QObject::trUtf8("M_FINDLINE");
    m_mapNameList[M_KERFCHECK] = QObject::trUtf8("M_KERFCHECK");

    m_mapNameList[WORKTABLE] = QObject::trUtf8("WORKTABLE");
    m_mapNameList[WORKTABLE_DRIVER] = QObject::trUtf8("WORKTABLE_DRIVER");

    m_mapNameList[PRODUCT] = QObject::trUtf8("PRODUCT");
    m_mapNameList[PRODUCT_DRIVER] = QObject::trUtf8("PRODUCT_DRIVER");

    m_mapNameList[WTOFFSET] = QObject::trUtf8("WTOFFSET");
    m_mapNameList[WTOFFSET_DRIVER] = QObject::trUtf8("WTOFFSET_DRIVER");

    m_mapNameList[SIDE_A] = QObject::trUtf8("SIDE_A");
    m_mapNameList[SIDE_B] = QObject::trUtf8("SIDE_B");
    m_mapNameList[SIDE_C] = QObject::trUtf8("SIDE_C");
    m_mapNameList[SIDE_D] = QObject::trUtf8("SIDE_D");
    m_mapNameList[SIDE_DRIVER] = QObject::trUtf8("SIDE_DRIVER");

    m_mapNameList[CASSETTE] = QObject::trUtf8("CASSETTE");
    m_mapNameList[CASSETTE_DRIVER] = QObject::trUtf8("CASSETTE_DRIVER");

    m_mapNameList[PROCESS_COAT] = QObject::trUtf8("PROCESS_COAT");
    m_mapNameList[PROCESS_CLEAN] = QObject::trUtf8("PROCESS_CLEAN");

    m_mapNameList[PROCESS_LOCATE] = QObject::trUtf8("PROCESS_LOCATE");
    m_mapNameList[PROCESS_LEVELING] = QObject::trUtf8("PROCESS_LEVELING");
    m_mapNameList[PROCESS_CUT] = QObject::trUtf8("PROCESS_CUT");
    m_mapNameList[PROCESS_KERFCHECK] = QObject::trUtf8("PROCESS_KERFCHECK");

    m_mapNameList[PROCESS_POWERCALI_D_WIDE] = QObject::trUtf8("PROCESS_POWERCALI_D_WIDE");
    m_mapNameList[PROCESS_POWERCALI_D_NARROW] = QObject::trUtf8("PROCESS_POWERCALI_D_NARROW");
    m_mapNameList[PROCESS_LASERFOUCSCALI_D_WIDE] = QObject::trUtf8("PROCESS_LASERFOUCSCALI_D_WIDE");
    m_mapNameList[PROCESS_LASERFOUCSCALI_D_NARROW] = QObject::trUtf8("PROCESS_LASERFOUCSCALI_D_NARROW");

    m_mapNameList[PROCESS_SCAN] = QObject::trUtf8("PROCESS_SCAN");
    m_mapNameList[PROCESS_TRANS] = QObject::trUtf8("PROCESS_TRANS");

    m_mapNameList[SM_MAIN] = QObject::trUtf8("SM_MAIN");
    m_mapNameList[SM_TRANS] = QObject::trUtf8("SM_TRANS");
    m_mapNameList[SM_COAT] = QObject::trUtf8("SM_COAT");
    m_mapNameList[SM_CLEAN] = QObject::trUtf8("SM_CLEAN");
    m_mapNameList[SM_IO] = QObject::trUtf8("SM_IO");
    m_mapNameList[SM_CAMGRAB2X] = QObject::trUtf8("SM_CAMGRAB2X");
    m_mapNameList[SM_CAMGRAB6X] = QObject::trUtf8("SM_CAMGRAB6X");
    m_mapNameList[SM_GEM] = QObject::trUtf8("SM_GEM");
#ifdef __OLD_DEFINE_ID__
    m_mapNameList[LIGHT_DIRECT4X] = QObject::trUtf8("LIGHT_DIRECT4X");
    m_mapNameList[LIGHT_SIDE4X] = QObject::trUtf8("LIGHT_SIDE4X");
#endif // __OLD_DEFINE_ID__
    m_mapNameList[LIGHT_DRIVER_SIDE] = QObject::trUtf8("LIGHT_DRIVER_SIDE");
    m_mapNameList[CAMKerf] = QObject::trUtf8("CAM4X");
    m_mapNameList[SM_CAMGRAB4X] = QObject::trUtf8("SM_CAMGRAB4X");
    m_mapNameList[MOTORF2_CLEAN_ARM2] = QObject::trUtf8("MOTORF3_CLEAN_ARM2");
    m_mapNameList[MOTORH1_UPDOWN] = QObject::trUtf8("MOTORH1_UPDOWN");
    m_mapNameList[MOTORH2_TRANS] = QObject::trUtf8("MOTORH2_TRANS");
    m_mapNameList[MOTORJ1_UPDOWN] = QObject::trUtf8("MOTORJ1_UPDOWN");
    m_mapNameList[MOTORJ2_TRANS] = QObject::trUtf8("MOTORJ2_TRANS");
    m_mapNameList[MOTOR_SHUTTER] = QObject::trUtf8("MOTOR_SHUTTER");
    m_mapNameList[M_CALIBRATION_NCC] = QObject::trUtf8("NCC_Calibration");
    m_mapNameList[COATVOLUME_SENSOR] = QObject::trUtf8("CoatVolumeSensor");
    m_mapNameList[PROCESS_HALFKERF] = QObject::trUtf8("HalfCutKerf");
    m_mapNameList[PROCESS_LASERKERF] = QObject::trUtf8("LaserKerf");
    m_mapNameList[M_KERF_LASER] = QObject::trUtf8("LaserKerf");
    m_mapNameList[M_KERF_HALFCUT] = QObject::trUtf8("HalfCutKerf");
    m_mapNameList[GEM_DRIVER_JNG] = QObject::trUtf8("SM_GEM");
    m_mapNameList[WTOFFSET_LASER] = QObject::trUtf8("WTOFFSETLASER");
    m_mapNameList[HGRIPPER_DRIVER] = QObject::trUtf8("HGRIPPERDRIVER");
    m_mapNameList[SM_WTUnload] = QObject::trUtf8("Unload");
    m_mapNameList[SM_WTLoad] = QObject::trUtf8("Load");
    m_mapNameList[SM_Schedular] = QObject::trUtf8("Schedular");

    m_mapNameList[DistanceSensor_Driver] = QObject::trUtf8("DistanceSensorDriver");
    m_mapNameList[DistanceSensor] = QObject::trUtf8("DistanceSensor");

    m_mapNameList[LASERPATH_S_NARROW] = QObject::trUtf8("S_NARROW");
    m_mapNameList[PROCESS_POWERCALI_S_NARROW] = QObject::trUtf8("POWERCALI_S_NARROW");
    m_mapNameList[PROCESS_LASERFOUCSCALI_S_NARROW] = QObject::trUtf8("FOCUS_S_NARROW");
    m_mapNameList[PROCESS_UTILS] = QObject::trUtf8("PROCESS_UTILS");

    //线光斑支持
    m_mapNameList[LASERPATH_L_NARROW] = QObject::trUtf8("L_NARROW");
    m_mapNameList[PROCESS_POWERCALI_L_NARROW] = QObject::trUtf8("POWERCALI_L_NARROW");
    m_mapNameList[PROCESS_LASERFOUCSCALI_L_NARROW] = QObject::trUtf8("FOCUS_L_NARROW");

    //JIG支持
    m_mapNameList[JigDriver] = QObject::trUtf8("JigDriver");
    m_mapNameList[PROCESS_LASERKERF_D_WIDE] = QObject::trUtf8("PROCESS_LASERKERF_DWIDE");
}

int32_t CMAllsystem::createSystem()
{

    int iLanguageType = read_language_config();
    if (1 == iLanguageType)
    {
        m_appTranslater.load(CMakePath::make_bin_path("../theme/project_en"));
    }
    else
    {
        m_appTranslater.load(CMakePath::make_bin_path("../theme/project_cn"));
    }

    qApp->installTranslator(&m_appTranslater);

    //TODO:读取Config中的多语言的配置
    CAllsystem::createSystem();
    m_Variants.add_Variant(Var_AllSystem_Vacumm_TimeLimit_ID,
                           QObject::trUtf8("Vacumm_TimeLimit"), int(2000), false,
                           Variant::TOXML, QStringList() << "0" << "100000", QObject::tr("ms"));

    m_Variants.add_Variant(Var_AllSystem_Vacumm_BreakTimeLimit_ID,
                           QObject::trUtf8("Vacumm_BreakTimeLimit"), int(2000), false,
                           Variant::TOXML, QStringList() << "0" << "100000", QObject::tr("ms"));

    m_Variants.add_Variant(Var_AllSystem_CellExistCheckTime_ID,
                           QObject::trUtf8("CellExistCheckTime"), int(12000), false,
                           Variant::TOXML, QStringList() << "0" << "100000", QObject::tr("ms"));

    m_Variants.add_Variant(Var_AllSystem_CurChID_ID,
                           QObject::trUtf8("CurChID"), int(CAM2X), false,
                           Variant::TOXML);
    m_Variants.add_Variant(Var_AllSystem_CellSize_ID,
                           QObject::trUtf8("CellSize"), int(150), false,
                           Variant::TOXML, QStringList() << "0" << "300", QObject::tr("inch"));
    m_Variants.add_Variant(Var_AllSystem_LaserState_ID,
                           QObject::trUtf8("LaserState"), uint(0), false,
                           Variant::TOXML,
                           QStringList() << QObject::tr("Simulate")
                           << QObject::tr("PI") <<
                           QObject::tr("JDSU"));

    m_Variants.add_Variant(Var_AllSystem_LightState_ID,
                           QObject::trUtf8("LightState"), uint(3), false,
                           Variant::TOXML, QStringList()
                           << QObject::tr("Simulate")
                           << QObject::tr("PDCM")
                           << QObject::tr("OPT")
                           << QObject::tr("WL"));


    m_Variants.add_Variant(Var_AllSystem_SafeDoorConfig_ID,
                           QObject::trUtf8("SafeDoorConfig"), uint(0), false,
                           Variant::TOXML, QStringList()
                           << QObject::tr("NotUse") <<
                           QObject::tr("LeftDoor") <<
                           QObject::tr("RightDoor") <<
                           QObject::tr("AllDoor"));
    m_Variants.add_Variant(Var_AllSystem_FullScreen_ID,
                           QObject::trUtf8("FullScreen"), uint(1), false,
                           Variant::TOXML, QStringList()
                           << QObject::tr("FullScreen") <<
                           QObject::tr("ShowMaxium") <<
                           QObject::tr("ShowNormal"));

    m_Variants.add_Variant(Var_AllSystem_EnableSoftKeyboard_ID,
                           QObject::trUtf8("EnableSoftKeyboard"), bool(false), false,
                           Variant::TOXML);

    m_Variants.add_Variant(Var_AllSystem_StyleSheet_Type_ID,
                           QObject::trUtf8("StyleSheet_Type"), uint(0), false,
                           Variant::TOXML, QStringList()
                           << QObject::tr("StyleSheet_Light") <<
                           QObject::tr("StyleSheet_Dark"));

    m_Variants.add_Variant(Var_AllSystem_Language_Type_ID,
                           QObject::trUtf8("Language"), uint(0), false,
                           Variant::TOXML, QStringList()
                           << QObject::tr("Chinese") <<
                           QObject::tr("English"));

    m_Variants.add_Variant(Var_MaxCycle_Count,
                           QObject::trUtf8("MaxCycleCount"), int(0), false,
                           Variant::TOXML, QStringList() << "0" << "600");

    m_Variants.add_Variant(Var_Enable_FixLaserPathAngle,
                           QObject::trUtf8("FixLaserPathAngle"), true, false,
                           Variant::TOXML, QStringList());


    m_Variants.add_Variant(Var_XY_AngleOffset,
                           QObject::trUtf8("XYAngleOffset"), double(90), false,
                           Variant::TOXML, QStringList());

    /*m_Variants.add_Variant(Var_Enable_JigCheck,
                           QObject::trUtf8("Var_Enable_JigCheck"), true, false,
                           Variant::TOXML, QStringList()); */

    //write_config(true);
    read_config(false);

    initNameList();

    int32_t istate = m_Variants.get_VData(Var_ALLSystem_State_ID)->toUInt();
    createWorker(istate);
    createCam(istate);
    createCassette(istate);
    createLaser(istate);
    createLaserPath(istate);
    createLight(istate);
    createMotor(istate);
    createProduct(istate);
    createWorktable(istate);
    createPowerMeter(istate);
    createSide(istate);
    createStatemachine(istate);
    createOffset(istate);

    createBarcode(istate);
    createCoatVolumeSensor(istate);
    createMeasureDistance(istate);

    createGEM(istate);
    createHgripper(istate);
    //write_config(true);
    read_config(true);

    static CEventRecord gs_EventRecord;
    IEventHelper::GetInstance().SetEventInstance(&gs_EventRecord);
#if 0
    QString path = CMakePath::make_data_path("Demo.lpf");
    QFile file(path);
    if (!file.open(QIODevice::ReadWrite)) {
        return false;
    }
    try {
        QDataStream stream(&file);
        this->Serialize(stream, false);
    } catch (...) {
    }
    file.close();
#endif

    CProcess_Clean* pClean = GET_PROCESS(PROCESS_CLEAN, SM_CLEAN, CProcess_Clean);
    pClean->ReadWriteCleanTable(false);

    CProcess_Coat* pCoat = GET_PROCESS(PROCESS_COAT, SM_COAT, CProcess_Coat);
    pCoat->ReadWriteCleanTable(false);
    pCoat->ReadWriteCleanCoatLiquid(false);

    //SetLotId("LotId");
    /*
    QFile fileRecipe(CMakePath::make_config_path("recipe.xml"));
    if (!fileRecipe.open(QIODevice::WriteOnly)) {
        return false;
    }
    ConfigStreamWriter streamWriter(&fileRecipe);
    WriteRecipe(streamWriter, 0);
    fileRecipe.close();
    

    QFile fileReader(CMakePath::make_config_path("recipe.xml"));
    if (!fileReader.open(QIODevice::ReadOnly)) {
        return false;
    }
    ConfigStreamReader streamReader(&fileReader);


    //while (!streamReader.atEnd()) {
    //    
    //    std::string name = streamReader.name().toString().toStdString();
    //    std:string info = streamReader.text().toString().toStdString();
    //}

    if (streamReader.hasError()) {
        int errCode = streamReader.error();
    }
    //streamReader.readNextStartElement();
    //streamReader.attributes().value("version");
    //while (streamReader.readNextStartElement()) {
    //    std::string info = streamReader.text().toString().toStdString();
    //    std::string name = streamReader.name().toString().toStdString();
    //    qDebug() << " result : "
    //        << name.c_str() << " id:" << streamReader.attributes().value("id");

    //    streamReader.skipCurrentElement();
    //}
    //ReadRecipe(streamReader, 0);

    fileReader.close();
    */
    LogInfo("Start System");
    /*AddProductInfo("Start Coating");*/

    return RTN_SUCCESS1;
}

void CMAllsystem::createWorker(int istate)
{
    UNUSED(istate);

    CDriverCard* pcard = 0;
    pcard = new CWorkerDriverUser(m_mapNameList[M_WORKERDRIVER], M_WORKERDRIVER);
    CWorker* pWorker = new CWorker(m_mapNameList[M_WORKER], M_WORKER);
    if(!IsSimulator()){
        pWorker->m_workName = "Not Login";
        pWorker->m_workLevel = LEVEL_OPERATOR;
    }
    pcard->mchannels[M_WORKER] = pWorker;
    
    mcards[M_WORKERDRIVER] = pcard;

    pcard->init_driver();

}

void CMAllsystem::createCam(int istate)
{
    if (IsSimulator()) {
        istate = SIMULATE;
    }

    CCam* pCam2X = 0;
    CCam* pCam6X = 0;
    CCam* pCam4X = 0;
    CDriverCard* pcard = 0;
    switch (istate) {
    case SIMULATE:
    {
        pcard = new CMCamDriver(m_mapNameList[CAM_DRIVER], CAM_DRIVER);
        pCam2X = new CMCam(m_mapNameList[CAM2X], CAM2X);
        pcard->mchannels[CAM2X] = pCam2X;
        pCam6X = new CMCam(m_mapNameList[CAM6X], CAM6X);
        //pCam6X->m_imageContainer.m_imarktype = CImageContainer::MARK_LINE_H;
        pcard->mchannels[CAM6X] = pCam6X;
#ifdef __USE_THIRD_CAMERA__
        pCam4X = new CMCam(m_mapNameList[CAMKerf], CAMKerf);
        pcard->mchannels[CAMKerf] = pCam4X;
#endif
        mcards[CAM_DRIVER] = pcard;
        break;
    }

    case OFF_LINE:
    case ON_LINE:
    {
        CDriverCard* pcard = 0;
        pcard = new CCamDriver_Basler(m_mapNameList[CAM_DRIVER], CAM_DRIVER);
        pCam2X = new CCam_Basler(m_mapNameList[CAM2X], CAM2X);
        pcard->mchannels[CAM2X] = pCam2X;
        pCam6X = new CCam_Basler(m_mapNameList[CAM6X], CAM6X);
        //pCam6X->m_imageContainer.m_imarktype = CImageContainer::MARK_LINE_H;
        pcard->mchannels[CAM6X] = pCam6X;
#ifdef __USE_THIRD_CAMERA__
        pCam4X = new CMCam(m_mapNameList[CAMKerf], CAMKerf);
        pcard->mchannels[CAMKerf] = pCam4X;
#endif
        /*       CDriverCard* pcard = 0;
               pcard = new CCamDriver_IMG(_strCompName[CAM_DRIVER], CAM_DRIVER);
               pCam2X = new CCam_IMG(_strCompName[CAM2X], CAM2X);
               pcard->mchannels[CAM2X] = pCam2X;
               pCam6X = new CCam_IMG(_strCompName[CAM6X], CAM6X);
               pCam6X->m_imageContainer.m_imarktype = CImageContainer::MARK_LINE_H;
               pcard->mchannels[CAM6X] = pCam6X;
   #ifdef __USE_THIRD_CAMERA__
               pCam4X = new CCam_IMG(_strCompName[CAMKerf], CAMKerf);
               pcard->mchannels[CAMKerf] = pCam4X;
   #endif*/
        mcards[CAM_DRIVER] = pcard;
        break;
    }
    default:
        Q_ASSERT(0);
        break;
    }
    pCam2X->malgorithms[M_FINDEAGE] =
        new CAFindEageExternal(m_mapNameList[M_FINDEAGE], M_FINDEAGE);

    CAlgorithm* pAlgorithm = pCam2X->malgorithms[M_MATCHSHAPE] =
        new CAMatchShape_H(m_mapNameList[M_MATCHSHAPE], M_MATCHSHAPE);

    //   pAlgorithm->m_iSerialStyle=Variant::TOWRITEONLY;
#ifdef __SIMULATOR__
    pCam2X->malgorithms[M_MATCHNCC] =
        new CAMatchNCC_External(m_mapNameList[M_MATCHNCC], M_MATCHNCC);
#else
    pCam2X->malgorithms[M_MATCHNCC] =
        new CAMatchNCC_H(m_mapNameList[M_MATCHNCC], M_MATCHNCC);
#endif // __SIMULATOR__



    pAlgorithm = pCam6X->malgorithms[M_MATCHSHAPE] =
        new CAMatchShape_H(m_mapNameList[M_MATCHSHAPE], M_MATCHSHAPE);

    //   pAlgorithm->m_iSerialStyle=Variant::TOWRITEONLY;
#ifdef __SIMULATOR__
    pCam6X->malgorithms[M_MATCHNCC] =
        new CAMatchNCC_External(m_mapNameList[M_MATCHNCC], M_MATCHNCC);
#else
    pCam6X->malgorithms[M_MATCHNCC] =
        new CAMatchNCC_H(m_mapNameList[M_MATCHNCC], M_MATCHNCC);
#endif // __SIMULATOR__


    pCam6X->malgorithms[M_KERFCHECK] =
        new CAKerfCheck_H(m_mapNameList[M_KERFCHECK], M_KERFCHECK);

    pCam6X->malgorithms[M_CALIBRATION_NCC] =
        new CAMatchNCC_H(m_mapNameList[M_CALIBRATION_NCC], M_CALIBRATION_NCC);

    pCam6X->malgorithms[M_KERF_LASER] =
        new CAKerfCheck_H(m_mapNameList[M_KERF_LASER], M_KERF_LASER);

    CAKerfCheck_H* pKerf = new CAKerfCheck_H(m_mapNameList[M_KERF_HALFCUT], M_KERF_HALFCUT);
    pCam6X->malgorithms[M_KERF_HALFCUT] = pKerf;

#ifdef __USE_THIRD_CAMERA__
    //相机4
    pCam4X->malgorithms[M_MATCHNCC] =
        new CAMatchNCC_H(m_mapNameList[M_MATCHNCC], M_MATCHNCC);

    pCam4X->malgorithms[M_KERFCHECK] =
        new CAKerfCheck_H(m_mapNameList[M_KERFCHECK], M_KERFCHECK);
#endif

    m_RecipeCards[CAM_DRIVER] = pcard;
}

void CMAllsystem::createCassette(int istate)
{
    UNUSED(istate);

    CDriverCard* pcard = 0;
    pcard = new CCassetteDriver(m_mapNameList[CASSETTE_DRIVER],
                                CASSETTE_DRIVER);
    pcard->mchannels[CASSETTE] =
        new CCassette(m_mapNameList[CASSETTE], CASSETTE);
    mcards[CASSETTE_DRIVER] = pcard;

}


void CMAllsystem::createLaser(int istate)
{
    uint iLaserState = m_Variants.get_VData(Var_AllSystem_LaserState_ID)
        ->toUInt();
    //iLaserState = 4;

    if (IsSimulator()) {
        istate = SIMULATE;
    }

    CLaserDriver* pcard = 0;
    switch (istate) {
    case SIMULATE:
    {
        pcard = new CLaserDriver_Base(m_mapNameList[LASER_DRIVER], LASER_DRIVER);
        break;
    }
    case OFF_LINE:
    case ON_LINE:
    {
      
        switch (iLaserState) {
        case 0:pcard = new CLaserDriver_Base(m_mapNameList[LASER_DRIVER], LASER_DRIVER); break;
            /*case 2:pcard = new CLaserDriver_JDSU(m_mapNameList[LASER_DRIVER], LASER_DRIVER); break;
            case 3:pcard = new CLaserDriver_IGPS(m_mapNameList[LASER_DRIVER], LASER_DRIVER); break;*/
        case 1:pcard = new CLaserDriver_SP(m_mapNameList[LASER_DRIVER], LASER_DRIVER); break;
        case 2:pcard = new CLaserDriver_PI(m_mapNameList[LASER_DRIVER], LASER_DRIVER); break;
        default:Q_ASSERT(0); break;
        }
        break;
    }
    default:
        Q_ASSERT(0);
        break;
    }
    pcard->mchannels[LASER] = new CLaserBase(m_mapNameList[LASER], LASER);
    mcards[LASER_DRIVER] = pcard;

    pcard->m_pfnFireOn = std::function<void(int32_t, bool)>(std::bind(&CMAllsystem::OnFireOn, this, std::placeholders::_1, std::placeholders::_2));

    CDriverCard* card = new CJigDriver(m_mapNameList[JigDriver], JigDriver);
    mcards[JigDriver] = card;
}

void CMAllsystem::createLaserPath(int istate)
{
    UNUSED(istate);

    CDriverCard* pcard = 0;
    pcard = new CLaserPathDriver(m_mapNameList[LASERPATH_DRIVER],
                                 LASERPATH_DRIVER);

    pcard->mchannels[LASERPATH_D_NARROW] =
        new CLaserPath(m_mapNameList[LASERPATH_D_NARROW], LASERPATH_D_NARROW);

    pcard->mchannels[LASERPATH_D_WIDE] =
        new CLaserPath(m_mapNameList[LASERPATH_D_WIDE], LASERPATH_D_WIDE);

    pcard->mchannels[LASERPATH_S_NARROW] =
        new CLaserPath(m_mapNameList[LASERPATH_S_NARROW], LASERPATH_S_NARROW);

    pcard->mchannels[LASERPATH_L_NARROW] =
        new CLaserPath(m_mapNameList[LASERPATH_L_NARROW], LASERPATH_L_NARROW);
    mcards[LASERPATH_DRIVER] = pcard;
}

void CMAllsystem::createLight(int istate)
{
    if (IsSimulator()) {
        istate = SIMULATE;
    }
    CDriverCard* pcard = 0;
    switch (istate) {
    case SIMULATE:
    {
        pcard = new CLightDriverSocket(m_mapNameList[LIGHT_DRIVER_DIRECT], LIGHT_DRIVER_DIRECT);
        break;
    }
    case ON_LINE:
    case OFF_LINE:
    {
        uint iLightState = m_Variants.get_VData(Var_AllSystem_LightState_ID)
            ->toUInt();
        switch (iLightState) {
        case 0:
            pcard = new CLightDriverSocket(m_mapNameList[LIGHT_DRIVER_DIRECT], LIGHT_DRIVER_DIRECT); break;
            //case 1:pcard = new CLightDriver_KM(m_mapNameList[LIGHT_DRIVER_DIRECT], LIGHT_DRIVER_DIRECT); break;
            /*case 2:pcard = new CLightDriver_OPT(m_mapNameList[LIGHT_DRIVER_DIRECT], LIGHT_DRIVER_DIRECT); break;*/
        case 3:pcard = new CLightDriver_WL_Socket(m_mapNameList[LIGHT_DRIVER_DIRECT], LIGHT_DRIVER_DIRECT); break;
        }
        break;
    }
    default:
        Q_ASSERT(0);
        break;
    }
    pcard->mchannels[LIGHT_DIRECT2X] =
        new CLight(m_mapNameList[LIGHT_DIRECT2X], LIGHT_DIRECT2X);
    pcard->mchannels[LIGHT_DIRECT6X] =
        new CLight(m_mapNameList[LIGHT_DIRECT6X], LIGHT_DIRECT6X);
#ifdef __USE_THIRD_CAMERA__
    pcard->mchannels[LIGHT_DIRECT4X] =
        new CLight(m_mapNameList[LIGHT_DIRECT4X], LIGHT_DIRECT4X);
#endif
    mcards[LIGHT_DRIVER_DIRECT] = pcard;

    if (IsSimulator()) {
        pcard = new CLightDriverSocket(m_mapNameList[LIGHT_DRIVER_SIDE], LIGHT_DRIVER_SIDE);
    } else {
        pcard = new CLightDriver_WL_Socket(m_mapNameList[LIGHT_DRIVER_SIDE], LIGHT_DRIVER_SIDE);
    }
    pcard->mchannels[LIGHT_SIDE2X] =
        new CLight(m_mapNameList[LIGHT_SIDE2X], LIGHT_SIDE2X);
    pcard->mchannels[LIGHT_SIDE6X] =
        new CLight(m_mapNameList[LIGHT_SIDE6X], LIGHT_SIDE6X);
#ifdef __USE_THIRD_CAMERA__
    pcard->mchannels[LIGHT_SIDE4X] =
        new CLight(m_mapNameList[LIGHT_SIDE4X], LIGHT_SIDE4X);
#endif
    mcards[LIGHT_DRIVER_SIDE] = pcard;
}

void CMAllsystem::createMotor(int istate)
{
    if (IsSimulator()) {
        istate = SIMULATE;
    }
    CDriverCard* pcard = 0;

    switch (istate) {
    case SIMULATE:
    {
        pcard = new CMotorDriver_Base(m_mapNameList[MOTOR_DRIVER], MOTOR_DRIVER);
        //static_cast<CMotorDriver_Base*>(pcard)->SetSimulator(IsSimulator());
        pcard->SetSimulator(IsSimulator());
        break;
    }
    case ON_LINE:
    case OFF_LINE:
    {
        pcard = new CMotorDriver_ACS(m_mapNameList[MOTOR_DRIVER], MOTOR_DRIVER);
        break;
    }
    default:
        Q_ASSERT(0);
        break;
    }
    pcard->mchannels[MOTORX] = new CMotor(m_mapNameList[MOTORX], MOTORX);
    pcard->mchannels[MOTORY] = new CMotor(m_mapNameList[MOTORY], MOTORY);
    pcard->mchannels[MOTORZ] = new CMotor(m_mapNameList[MOTORZ], MOTORZ);
    pcard->mchannels[MOTORW] = new CMotor(m_mapNameList[MOTORW], MOTORW);


    //pcard->mchannels[MOTORG1_PCHANGE] = new CMotor(m_mapNameList[MOTORG1_PCHANGE], MOTORG1_PCHANGE);
    pcard->mchannels[MOTORG2_POWER] = new CMotor(m_mapNameList[MOTORG2_POWER], MOTORG2_POWER);
    pcard->mchannels[MOTORG3_WIDEINDEX] = new CMotor(m_mapNameList[MOTORG3_WIDEINDEX], MOTORG3_WIDEINDEX);
    pcard->mchannels[MOTORG4_WIDE5050] = new CMotor(m_mapNameList[MOTORG4_WIDE5050], MOTORG4_WIDE5050);
    pcard->mchannels[MOTORG5_NARROWINDEX] = new CMotor(m_mapNameList[MOTORG5_NARROWINDEX], MOTORG5_NARROWINDEX);
    pcard->mchannels[MOTORG6_NARROW5050]=new CMotor(m_mapNameList[MOTORG6_NARROW5050],MOTORG6_NARROW5050);
    /*pcard->mchannels[MOTORG7_MASK]=new CMotor(_strCompName[MOTORG7_MASK],MOTORG7_MASK);
    */

    pcard->mchannels[MOTORA_CLAW] = new CMotor(m_mapNameList[MOTORA_CLAW], MOTORA_CLAW);
    pcard->mchannels[MOTORB1_LOCK] = new CMotor(m_mapNameList[MOTORB1_LOCK], MOTORB1_LOCK);
    pcard->mchannels[MOTORB2_RAIL] = new CMotor(m_mapNameList[MOTORB2_RAIL], MOTORB2_RAIL);
    pcard->mchannels[MOTORC_CASS] = new CMotor(m_mapNameList[MOTORC_CASS], MOTORC_CASS);
    pcard->mchannels[MOTORD_TRANS] = new CMotor(m_mapNameList[MOTORD_TRANS], MOTORD_TRANS);


    pcard->mchannels[MOTORE_COAT_SPINDLE] = new CMotor(m_mapNameList[MOTORE_COAT_SPINDLE], MOTORE_COAT_SPINDLE);
    pcard->mchannels[MOTORE1_COAT_CLEAN_ARM] = new CMotor(m_mapNameList[MOTORE1_COAT_CLEAN_ARM], MOTORE1_COAT_CLEAN_ARM);
    pcard->mchannels[MOTORE2_COAT_COAT_ARM] = new CMotor(m_mapNameList[MOTORE2_COAT_COAT_ARM], MOTORE2_COAT_COAT_ARM);
    pcard->mchannels[MOTORE3_COAT_BUMP] = new CMotor(m_mapNameList[MOTORE3_COAT_BUMP], MOTORE3_COAT_BUMP);
    //pcard->mchannels[MOTORE4_COAT_CURTAIN] = new CMotor(m_mapNameList[MOTORE4_COAT_CURTAIN], MOTORE4_COAT_CURTAIN);

    pcard->mchannels[MOTORF_CLEAN_SPINDLE] = new CMotor(m_mapNameList[MOTORF_CLEAN_SPINDLE], MOTORF_CLEAN_SPINDLE);
    pcard->mchannels[MOTORF1_CLEAN_ARM] = new CMotor(m_mapNameList[MOTORF1_CLEAN_ARM], MOTORF1_CLEAN_ARM);
    //pcard->mchannels[MOTORF2_CLEAN_CURTAIN] = new CMotor(m_mapNameList[MOTORF2_CLEAN_CURTAIN], MOTORF2_CLEAN_CURTAIN);
    //pcard->mchannels[MOTORF2_CLEAN_ARM2] = new CMotor(m_mapNameList[MOTORF2_CLEAN_ARM2], MOTORF2_CLEAN_ARM2);

    pcard->mchannels[MOTORH1_UPDOWN] = new CMotor(m_mapNameList[MOTORH1_UPDOWN], MOTORH1_UPDOWN);
    pcard->mchannels[MOTORH2_TRANS] = new CMotor(m_mapNameList[MOTORH2_TRANS], MOTORH2_TRANS);

    pcard->mchannels[MOTORJ1_UPDOWN] = new CMotor(m_mapNameList[MOTORJ1_UPDOWN], MOTORJ1_UPDOWN);
    pcard->mchannels[MOTORJ2_TRANS] = new CMotor(m_mapNameList[MOTORJ2_TRANS], MOTORJ2_TRANS);

    //pcard->mchannels[MOTOR_SHUTTER] = new CMotor(m_mapNameList[MOTOR_SHUTTER], MOTOR_SHUTTER);

    pcard->mchannels[IO_INPUT] = new CIO(m_mapNameList[IO_INPUT], IO_INPUT, 64, CMotorDriver::MODULE_IO_IN);
    pcard->mchannels[IO_OUTPUT] = new CIO(m_mapNameList[IO_OUTPUT], IO_OUTPUT, 64, CMotorDriver::MODULE_IO_OUT);
    pcard->mchannels[IO_INPUT_ANALOG] = new CIO(m_mapNameList[IO_INPUT_ANALOG], IO_INPUT_ANALOG, 4, CMotorDriver::MODULE_IO_INANALOG);
    mcards[MOTOR_DRIVER] = pcard;

    //注册外部检查函数
    CMotorDriver_Base* pMotorDriver = dynamic_cast<CMotorDriver_Base*>(pcard);
    pMotorDriver->m_pfnIOAvaliable = std::function<void(int, int)>(std::bind(&CMAllsystem::OnIsIOSetAvailable, this, std::placeholders::_1, std::placeholders::_2));
    pMotorDriver->m_pfnMoveAvaliable = std::function<void(int, bool, int, double, bool)>(std::bind(&CMAllsystem::OnIsMotorMoveAvailable, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
    pMotorDriver->m_pfnPrepareHome = std::function<void(int)>(std::bind(&CMAllsystem::OnPrepareHome, this, std::placeholders::_1));
    pMotorDriver->m_pfnAfterHome = std::function<void(int)>(std::bind(&CMAllsystem::OnAfterHome, this, std::placeholders::_1));
    pMotorDriver->m_pfnLimitCheck = std::function<void(int32_t, double)>(std::bind(&CMAllsystem::OnLimitCheck, this, std::placeholders::_1, std::placeholders::_2));

    //主气压检测
    pMotorDriver->m_pfnMainPresureDetected = std::function<void(void)>(std::bind(&CMAllsystem::MainPressCheck, this));

    //防撞检测
    pMotorDriver->m_pfnMovingDetected = [](int motorId, std::string& sException) {
        if (motorId == MOTORA_CLAW) {
            CMotorDriver_Base* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver_Base);
            int clawCheck = pMotorDriver->get_iodata(IO_INPUT, IN_CLAW_Collision_Detection_Push, true);
            if (clawCheck == IO_TRIGGER_OFF) {
                //检查防撞传感器没信号了，说明撞到了
                sException = QObject::trUtf8("Glaw strike sensor triggerd").toStdString();
                return true;
            } else {
                return false;
            }
        }
		else if (motorId == MOTORC_CASS)
		{
			CMotorDriver_Base* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver_Base);
			bool bCheck = pMotorDriver->get_iodata(IO_INPUT, IN_CHECKBOX_DOOR_OPENED, true);
			if (bCheck == IO_TRIGGER_ON)
			{
				//检查CHECKBOX传感器有信号了，说明异常操作
				sException = QObject::trUtf8("checkbox door opened").toStdString();
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
        
    };

    //当前激光是否是激光关闭状态
    pMotorDriver->m_pfnSetLaserOff = [&](int32_t ioid, int32_t idata) {
        if (ioid == OUT_LASERGATE && idata == LASER_OFF) {
            return true;
        } else {
            return false;
        }

    };

}

void CMAllsystem::createProduct(int istate)
{
    UNUSED(istate);
    CDriverCard* pcard = 0;
    pcard = new CMProductDriver(m_mapNameList[PRODUCT_DRIVER],
                                PRODUCT_DRIVER);
    pcard->mchannels[PRODUCT] =
        new CMProduct(m_mapNameList[PRODUCT], PRODUCT);
    mcards[PRODUCT_DRIVER] = pcard;

    m_RecipeCards[PRODUCT_DRIVER] = pcard;
}

void CMAllsystem::createStatemachine(int istate)
{
    UNUSED(istate);
    msms[SM_IO] = new VSMT_IO(SM_IO, m_mapNameList[SM_IO]);
    msms[SM_CAMGRAB2X] = new VSMT_IO(SM_CAMGRAB2X, m_mapNameList[SM_CAMGRAB2X]);
    msms[SM_CAMGRAB6X] = new VSMT_IO(SM_CAMGRAB6X, m_mapNameList[SM_CAMGRAB6X]);
#ifdef __USE_THIRD_CAMERA__
    msms[SM_CAMGRAB4X] = new VSMT_IO(SM_CAMGRAB4X, m_mapNameList[SM_CAMGRAB4X]);
#endif
    msms[SM_MAIN] = new VSMT_Main(SM_MAIN, m_mapNameList[SM_MAIN]);
    msms[SM_TRANS] = new VSMT_Transfer(SM_TRANS, m_mapNameList[SM_TRANS]);
    msms[SM_COAT] = new VSMT_Coat(SM_COAT, m_mapNameList[SM_COAT]);
    msms[SM_CLEAN] = new VSMT_Clean(SM_CLEAN, m_mapNameList[SM_CLEAN]);

    msms[SM_GEM] = new VSMT_GEM(SM_GEM, m_mapNameList[SM_GEM]);

    msms[SM_WTUnload] = new VSMT_Unload(SM_WTUnload, m_mapNameList[SM_WTUnload]);
    msms[SM_WTLoad] = new VSMT_Load(SM_WTLoad, m_mapNameList[SM_WTLoad]);
    msms[SM_Schedular] = new VSMT_Schedular(SM_Schedular, m_mapNameList[SM_Schedular]);

    msms[SM_WTUnload]->AddProcess(PROCESS_TRANS, msms[SM_TRANS]->FindProcess(PROCESS_TRANS));
    msms[SM_WTLoad]->AddProcess(PROCESS_TRANS, msms[SM_TRANS]->FindProcess(PROCESS_TRANS));

    m_RecipeSMS[SM_MAIN] = msms[SM_MAIN];
    m_RecipeSMS[SM_COAT] = msms[SM_COAT];
    m_RecipeSMS[SM_CLEAN] = msms[SM_CLEAN];
}

void CMAllsystem::createWorktable(int istate)
{

    UNUSED(istate);
    CDriverCard* pcard = 0;
    pcard = new CMWorkTableDriver(m_mapNameList[WORKTABLE_DRIVER],
                                  WORKTABLE_DRIVER);
    pcard->mchannels[WORKTABLE] =
        new CMWorkTable(m_mapNameList[WORKTABLE], WORKTABLE);
    mcards[WORKTABLE_DRIVER] = pcard;
}

void CMAllsystem::createPowerMeter(int istate)
{
    UNUSED(istate);
    CDriverCard* pcard = 0;
    pcard = new CPowerMeterDriver_lp(m_mapNameList[POWERMETERDRIVER],
                                     POWERMETERDRIVER);
    pcard->mchannels[POWERMETERHEAD] =
        new CPowerMeter(m_mapNameList[POWERMETERHEAD], POWERMETERHEAD);

    mcards[POWERMETERDRIVER] = pcard;
}

void CMAllsystem::createSide(int istate)
{
    UNUSED(istate);
    CDriverCard* pcard = 0;
    pcard = new CProductSideDriver(m_mapNameList[SIDE_DRIVER],
                                   SIDE_DRIVER);
    pcard->mchannels[SIDE_A] =
        new CProductSide(m_mapNameList[SIDE_A], SIDE_A);
    pcard->mchannels[SIDE_B] =
        new CProductSide(m_mapNameList[SIDE_B], SIDE_B);
    mcards[SIDE_DRIVER] = pcard;
    m_RecipeCards[SIDE_DRIVER] = pcard;
}

void CMAllsystem::createOffset(int istate)
{
    UNUSED(istate);
    CDriverCard* pcard = 0;
    pcard = new CWorktableOffsetDriver(m_mapNameList[WTOFFSET_DRIVER],
                                       WTOFFSET_DRIVER);
    pcard->mchannels[WTOFFSET] =
        new CWorktableOffset(m_mapNameList[WTOFFSET], WTOFFSET);
    pcard->mchannels[WTOFFSET_LASER] =
        new CWorktableLaserOffset(m_mapNameList[WTOFFSET_LASER], WTOFFSET_LASER);

    mcards[WTOFFSET_DRIVER] = pcard;
}

void CMAllsystem::createBarcode(int istate)
{
    UNUSED(istate);
    CDriverCard* pcard = 0;
    pcard = new CBarcodeDriverInfoScan(m_mapNameList[BARCODE_DRIVER],
                                       BARCODE_DRIVER);

    pcard->SetSimulator(m_gSystem.IsSimulator());
    pcard->mchannels[BARCODE] =
        new CBarCode(m_mapNameList[BARCODE], BARCODE);

    mcards[BARCODE_DRIVER] = pcard;
}



void CMAllsystem::createCoatVolumeSensor(int istate)
{
    CDriverCard* pCoatVolumeSensor = new CCoatVolumeSensor(m_mapNameList[COATVOLUME_SENSOR],
                                                           COATVOLUME_SENSOR);

    mcards[COATVOLUME_SENSOR] = pCoatVolumeSensor;
}

void CMAllsystem::createGEM(int istate)
{
    UNUSED(istate);
    CDriverCard* pcard = 0;
    pcard = new CHSMSDriver(m_mapNameList[GEM_DRIVER],
                            GEM_DRIVER);
    pcard->mchannels[GEM_CLIENT] =
        new CHSMS(m_mapNameList[GEM_CLIENT], GEM_CLIENT);
    mcards[GEM_DRIVER] = pcard;

    CDriverCard* pGemCard = new CGEMDriver(m_mapNameList[GEM_DRIVER_JNG], GEM_DRIVER_JNG);
    mcards[GEM_DRIVER_JNG] = pGemCard;
}

void CMAllsystem::createMeasureDistance(int istate)
{
    CDriverCard* pcard = 0;
    pcard = new CDistanceMeterDriver_HL(m_mapNameList[DistanceSensor_Driver],
                                        DistanceSensor_Driver);

    pcard->mchannels[DistanceSensor] = new CMeasHead(m_mapNameList[DistanceSensor], DistanceSensor);

    mcards[DistanceSensor_Driver] = pcard;
}

void CMAllsystem::createHgripper(int istate)
{
    //istate = SIMULATE;

    UNUSED(istate);
    CDriverCard* pcard = 0;
    switch (istate) {
    case SIMULATE:
        pcard = new CDriverCard(m_mapNameList[HGRIPPER_DRIVER],
                                HGRIPPER_DRIVER);
        break;
    default:
        pcard = new CDHGripperRS485(m_mapNameList[HGRIPPER_DRIVER],
                                    HGRIPPER_DRIVER);
        break;
    }

    mcards[HGRIPPER_DRIVER] = pcard;
}

void CMAllsystem::EMO()
{
    CAllsystem::EMO();
    try {
        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
        pMotorDriver->emg_on(true);
        CProcess_Coat* pCoat = GET_PROCESS(PROCESS_COAT, SM_COAT, CProcess_Coat);
        Q_ASSERT(pCoat);
        pCoat->nozzeloperator_coat(INIT_COAT);

        CProcess_Clean* pClean = GET_PROCESS(PROCESS_CLEAN, SM_CLEAN, CProcess_Clean);
        Q_ASSERT(pClean);
        pClean->nozzeloperator_clean(INIT_CLEAN);
        SetIndicatorLight(Qt::red, true);
        SetIndicatorLight(Qt::green, true);
        SetIndicatorLight(Qt::yellow, true);

        //TODO:急停时关闭激光
        //CLaserDriver_SP* pLaserDriver = GET_CARD(LASER_DRIVER, CLaserDriver_SP);
        //pLaserDriver->SetInnerGate(LASER, false);
        //LOG_ERR("EMO shut down laser");
        //m_gSystem.LogError("EMO shut down laser");

    } catch (QString& s) {
        MqDebug() << s;
    }
}

void CMAllsystem::LEAVE_EMO()
{
    CAllsystem::LEAVE_EMO();
    CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    pMotorDriver->emg_on(false);
    try {
        SetIndicatorLight(Qt::red, false);
        SetIndicatorLight(Qt::green, false);
        SetIndicatorLight(Qt::yellow, true);
    } catch (QString& s) {
        MqDebug() << s;
    }
}

void CMAllsystem::prepareSystem()
{
    V_State* m_pState = m_gSystem.FindSM(SM_IO)->GetIdleState();

    bool bLeft = false;
    bool bRight = false;
    GetSaveDoorCtrl(bLeft, bRight);
    if (bLeft) {
        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("De active IO %1").arg(OUT_LEFTDOOR_UNLOCK),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_LEFTDOOR_UNLOCK << false, 0);
    } else {
        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("Active IO %1").arg(OUT_LEFTDOOR_UNLOCK),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_LEFTDOOR_UNLOCK << true, 0);
    }

    if (bRight) {
        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("De active IO %1").arg(OUT_RIGHTDOOR_UNLOCK),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_RIGHTDOOR_UNLOCK << false, 0);
    } else {
        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("Active IO %1").arg(OUT_RIGHTDOOR_UNLOCK),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_RIGHTDOOR_UNLOCK << true, 0);
    }

    m_pState->pushback_Msg(VarMsg_Driver_ID,
                           QObject::trUtf8("Active IO %1").arg(OUT_WT_BASE_VACUUM),
                           QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                           << IO_OUTPUT << OUT_WT_BASE_VACUUM << true, 0);
    m_pState->pushback_Msg(VarMsg_Driver_ID,
                           QObject::trUtf8("Active IO %1").arg(OUT_Shutter_All_Open),
                           QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                           << IO_OUTPUT << OUT_Shutter_All_Open << false, 0);

        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("Active IO %1").arg(OUT_CCD_AIR),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_CCD_AIR << true, 0);

        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("Active IO %1").arg(OUT_CCD_AIR_6X),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_CCD_AIR_6X << true, 0);

        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("Active IO %1").arg(OUT_WT_KERF_VACCUM),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_WT_KERF_VACCUM << true, 0);

        //关掉静电消除器
        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("Active IO %1").arg(OUT_ELECT_Entry),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_ELECT_Entry << false, 0);

        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("Active IO %1").arg(OUT_ELECT_Transfer),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_ELECT_Transfer << false, 0);

        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("Active IO %1").arg(OUT_ELECT_Wt),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_ELECT_Wt << false, 0);

        m_pState->pushback_Msg(VarMsg_Driver_ID,
                               QObject::trUtf8("Active IO %1").arg(OUT_POWER_ELECT_ENTRY),
                               QVariantList() << MOTOR_DRIVER << CMotorDriver::SETIO
                               << IO_OUTPUT << OUT_POWER_ELECT_ENTRY << true, 0);

#ifdef __SIMULATOR__
    CLaserDriver_Base* laserDirver = GET_CARD(LASER_DRIVER, CLaserDriver_Base);
    laserDirver->OpenLaserGate(LASER, false);
#endif // __SIMULATOR__

}

void CMAllsystem::exitSystem()
{
    try {
        LogInfo("Exit system\n");
        CAllsystem::exitSystem();
        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
        pMotorDriver->emg_on(true);

        m_recordLog.Exit();

        //HACK:这里使用了Transfer的流程,所以先清空所有流程
        msms[SM_WTUnload]->mprocesss.clear();
        msms[SM_WTLoad]->mprocesss.clear();
    } catch (QString& s) {
        LOG_ERR(s.toLocal8Bit().data());
        MqDebug() << s;
    }

}

bool CMAllsystem::IsDebug()
{
    return true;
}

bool CMAllsystem::IsSimulator()
{
    return m_bIsSimulator;
}

void CMAllsystem::AssertCheckWtVaccum()
{
    if (!m_gSystem.IsSimulator()) {
        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
        Q_ASSERT(pMotorDriver);
        if (!pMotorDriver->get_iodata(IO_INPUT, IN_WT_WAFER_VACUUM, true)) {
            MQT_THROW_CODESTR(ALARM_MAIN_SAFE_PROTECT, QObject::trUtf8("WP Vaccum Off"));
        }

		if (!pMotorDriver->get_iodata(IO_INPUT, IN_WT_RING_VACUUM, true)) {
			MQT_THROW_CODESTR(ALARM_MAIN_SAFE_PROTECT, QObject::trUtf8("WP Ring Vaccum Off"));
		}

        if (!pMotorDriver->get_iodata(IO_INPUT, IN_WT_Worktable_Install_Check, true)) {
            MQT_THROW_CODESTR(ALARM_MAIN_SAFE_PROTECT, QObject::trUtf8("WP Base Vaccum Off"));
        }
    }
}

bool CMAllsystem::start_manual(int iSMID, const V_MsgQueue& msgqueue, bool bReport)
{
    //TODO:如果正在上料或正在下料时，不能处理
    VSMT_Base* pSM = (VSMT_Base*)FindSM(iSMID);
    if (pSM->IsCanDoManual()) {
        pSM->appandMsgqueue_toIdle(msgqueue);
        return true;
    } else {
        if (bReport) {
            if (!pSM->IsIdle() || pSM->IsSemiPaused() || pSM->IsAutoPasued()) {
                m_gSystem.m_SysMsg.SetMsg
                (QObject::trUtf8("Pause action before operator"));
            } else {
                m_gSystem.m_SysMsg.SetMsg
                (QObject::trUtf8("The current status does not support this operation"));
            }
        }
        return false;
    }
}

bool CMAllsystem::start_semi(int iSMID, const V_MsgQueue& msgqueue, bool bReport /*= true*/)
{
    //执行半自动操作
    //自动不能处于工作状态
    VSMT_Base* pSM = (VSMT_Base*)FindSM(iSMID);
    VSMT_Base* pSMTrans = (VSMT_Base*)FindSM(SM_TRANS);
    if (pSMTrans->IsCanDoManual() && pSMTrans->IsCanDoSemi()) {
        pSM->GetIdleState()->appandMsgqueue(msgqueue);
        return true;
    } else {
        if (bReport) {
            m_gSystem.m_SysMsg.SetMsg
            (QObject::trUtf8("Pause action before test move"));
        }
        return false;
    }
}

//执行手动操作
void CMAllsystem::start_test(int iSMID, const V_MsgQueue& msgqueue,
                             bool bReport/*=true*/)
{
    //HACK:如果Transfer不在Wait状态也认为是空闲
    VSMT_Base* pSM = (VSMT_Base*)FindSM(iSMID);
    VSMT_Base* pSMTrans = (VSMT_Base*)FindSM(SM_TRANS);
    VSMT_Base* pSMLoad = (VSMT_Base*)FindSM(SM_WTLoad);
    VSMT_Base* pSMUnload = (VSMT_Base*)FindSM(SM_WTUnload);
    VSMT_Base* pSMSchedular = (VSMT_Base*)FindSM(SM_Schedular);
    if (pSMTrans->IsCanDoManual() 
        && pSMLoad->IsCanDoManual()
        && pSMUnload->IsCanDoManual()
        && pSMSchedular->IsCanDoManual()
        && pSM->IsCanDoManual()) 
    {
        pSM->GetIdleState()->appandMsgqueue(msgqueue);
    } else {
        if (bReport) {
            m_gSystem.m_SysMsg.SetMsg
            (QObject::trUtf8("Pause action before test move"));
        }
    }
}

void CMAllsystem::start_reset(int iSMID, const V_MsgQueue& msgqueue, bool bReport/*=true*/)
{
    VSMT_Base* pSM = (VSMT_Base*)FindSM(iSMID);
    bool bTransIdle = m_gSystem.FindSM(SM_TRANS)->IsIdle();
    if (bTransIdle
        && pSM->IsIdle()) {
        m_gSystem.FindSM(SM_TRANS)->GetIdleState()->appandMsgqueue(msgqueue);
    } else {
        if (bReport) {
            if (iSMID == SM_COAT && bTransIdle) {
                m_gSystem.m_SysMsg.SetMsg
                (QObject::trUtf8("stop coating before reset"));
            } else if (iSMID == SM_CLEAN && bTransIdle) {
                m_gSystem.m_SysMsg.SetMsg
                (QObject::trUtf8("stop cleaning before reset"));
            } else if (iSMID == SM_MAIN && bTransIdle) {
                m_gSystem.m_SysMsg.SetMsg
                (QObject::trUtf8("stop cutting before reset"));
            } else {
                m_gSystem.m_SysMsg.SetMsg
                (QObject::trUtf8("Pause transfer before reset"));
            }
        }
    }
}

void CMAllsystem::abort_state(int iSMID, int iStateID, QVariantList& extraData, bool bOnnlyCurMachine/*=false*/)
{
    VSMT_Base* pSM = (VSMT_Base*)FindSM(iSMID);
    if (
        (false == bOnnlyCurMachine && IsAllSMIdle())
        || (true == bOnnlyCurMachine && m_gSystem.FindSM(iSMID)->IsIdle())
        ) {
        pSM->AbortState(iStateID, extraData);
        /*if (pSM->m_pHistoryState_Auto) {
            pSM->m_pHistoryState_Auto->pushfront_Msg(VarMsg_StateExit_ID,
                                                     QObject::trUtf8("Abort Auto State Manually"),
                                                     QVariantList() << iStateID << extraData);
        }
        if (pSM->m_pHistoryState_Semi) {
            pSM->m_pHistoryState_Semi->pushfront_Msg(VarMsg_StateExit_ID,
                                                     QObject::trUtf8("Abort Semi State Manually"),
                                                     QVariantList() << iStateID << extraData);
        }*/
    }

}

void CMAllsystem::absmove_xy(double dx, double dy)
{
    CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    int32_t pmotorids[2] = { 0 };
    float64_t pfposs[2] = { 0 };
    pmotorids[0] = MOTORX;
    pmotorids[1] = MOTORY;
    pfposs[0] = dx;
    pfposs[1] = dy;
    pMotorDriver->absmove_multi(pmotorids, pfposs, 2);
}

void CMAllsystem::absmove_xy_msg(double dx, double dy, V_MsgQueue& msgqueue)
{

    msgqueue.pushback_Msg(VarMsg_Driver_ID, QObject::trUtf8("XY Abs Move Sig"),
                          QVariantList()
                          << MOTOR_DRIVER << CMotorDriver::ABSMOVE_MULTI
                          << MOTORX << dx << MOTORY << dy, 0);

}

void CMAllsystem::relmove_xy_msg(double dx, double dy, V_MsgQueue& msgqueue)
{

    msgqueue.pushback_Msg(VarMsg_Driver_ID, QObject::trUtf8("XY Rel Move Sig"),
                          QVariantList()
                          << MOTOR_DRIVER << CMotorDriver::RELMOVE_MULTI
                          << MOTORX << dx << MOTORY << dy, 0);
}

void CMAllsystem::absmove_msg(double dpos, int ichID, V_MsgQueue& msgqueue)
{
    msgqueue.pushback_Msg(VarMsg_Driver_ID, QObject::trUtf8("Abs Move Sig"),
                          QVariantList()
                          << MOTOR_DRIVER << CMotorDriver::ABSMOVE
                          << ichID << dpos, 0);

}

void CMAllsystem::relmove_msg(double ddis, int ichID, V_MsgQueue& msgqueue)
{
    msgqueue.pushback_Msg(VarMsg_Driver_ID, QObject::trUtf8("Relative Move Sig"),
                          QVariantList()
                          << MOTOR_DRIVER << CMotorDriver::RELMOVE
                          << ichID << ddis, 0);

}

void CMAllsystem::jogmove_msg(double dSpd, int ichID, V_MsgQueue& msgqueue)
{
    msgqueue.pushback_Msg(VarMsg_Driver_ID, QObject::trUtf8("Jog Move Sig"),
                          QVariantList()
                          << MOTOR_DRIVER << CMotorDriver::STARTMOVE
                          << ichID << dSpd, 0);
}

void CMAllsystem::stopmove_msg(int ichID, V_MsgQueue& msgqueue)
{
    msgqueue.pushback_Msg(VarMsg_Driver_ID, QObject::trUtf8("Jog Move Sig"),
                          QVariantList()
                          << MOTOR_DRIVER << CMotorDriver::STOPMOVE
                          << ichID, 0);
}

void CMAllsystem::changeChannel_msg(int32_t idestCh, bool bxymove, V_MsgQueue& msgqueue)
{
    msgqueue.pushback_Msg(VarMsg_System_ChangeCh,
                          QObject::trUtf8("Change Channel Sig"),
                          QVariantList()
                          << idestCh << bxymove, 0);
}

void CMAllsystem::changeChannel(int32_t idestCh, bool bxymove)
{
    CMWorkTableDriver* pWorkTableDriver = GET_CARD(WORKTABLE_DRIVER, CMWorkTableDriver);
    Q_ASSERT(pWorkTableDriver);

    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    Q_ASSERT(pDriver);
    if (LASER_ON == pDriver->get_iodata(IO_OUTPUT, OUT_LASERGATE, true)) {
        QString chName = QObject::tr("CAM4X");
        if (idestCh == CAM2X)chName = QObject::tr("CAM2X");
        if (idestCh == CAM6X)chName = QObject::tr("CAM6X");
        if (idestCh == LASERPATH_D_NARROW) chName = QObject::tr("D_NARROW");
        if(idestCh == LASERPATH_D_WIDE) chName = QObject::tr("D_NARROW");
        if(idestCh == LASERPATH_S_NARROW) chName = QObject::tr("S_NARROW");
        MQT_THROW_CODESTR(ALARM_CHANGE_COMP_FAIELD_LASERON, QObject::tr("Can't change component %1 to cur pos,because Laser On").arg(chName));
    }

    //先移动到焦距
    pWorkTableDriver->MoveToCutDepthPos(idestCh, 0);
    CMPointd axis2, wpdp;
    pWorkTableDriver->CurAxisToWt(m_gSystem.m_iCurChID, wpdp, true);
    if (m_gSystem.m_iCurChID == CAM2X || m_gSystem.m_iCurChID == CAM6X || m_gSystem.m_iCurChID == CAMKerf) {
        CCam* pCam = GET_CHDIRECT(m_gSystem.m_iCurChID, CCam);
        pCam->m_imageContainer.clearString(-1);
    }
    m_gSystem.m_iCurChID = idestCh;
    if (bxymove) {
        int iPosState = CheckWtPos(wpdp);
        if (iPosState == 1) {
            MQT_THROW_CODESTR(ALARM_MAIN_SAFE_PROTECT, QObject::trUtf8("Target X location out of work table,"
                                                                       "Only change channel do not move"));
        } else if (iPosState == 2) {
            MQT_THROW_CODESTR(ALARM_MAIN_SAFE_PROTECT, QObject::trUtf8("Target Y location out of work table,"
                                                                       "Only change channel do not move"));
        }
        //移动坐标
        pWorkTableDriver->WtToAxis(idestCh, wpdp, axis2);
        absmove_xy(axis2.tX, axis2.tY);
    }
}

void CMAllsystem::changeSide_msg(int32_t iside, bool bxymove, V_MsgQueue& msgqueue)
{
    msgqueue.pushback_Msg(VarMsg_System_ChangeSide,
                          QObject::trUtf8("Change Side Sig"),
                          QVariantList()
                          << iside << bxymove, 0);
}

//检查工作台位置
int CMAllsystem::CheckWtPos(const CMPointd& pt)
{
    //TODO:添加JIG支持
    //CJigDriver* pJigDriver = GET_CARD(JigDriver, CJigDriver);

    CWorkTable* pWorkTable = GET_CHDIRECT(WORKTABLE, CWorkTable);
    double dWidth = pWorkTable->m_Variants.get_VData(Var_WorkTable_Width_ID)->toDouble();
    double dHeight = pWorkTable->m_Variants.get_VData(Var_WorkTable_Height_ID)->toDouble();

    if (fabs(pt.tX) > dWidth / 2) {
        return 1;
    }
    if (fabs(pt.tY) > dHeight / 2) {
        return 2;
    }
    return 0;
}

void CMAllsystem::WriteRecipe(ConfigStreamWriter& streamWriter, int iVersion)
{
    CAllsystem::WriteRecipe(streamWriter, iVersion);

    /*
    QString path = CMakePath::make_data_path("test.lpf");
    QFile file(path);
    if (!file.open(QIODevice::WriteOnly)) {
        MQT_THROW_STR(QObject::trUtf8("Can not open file."
                                      "file path:%1").arg(path));
    }
    ConfigStreamWriter stream(&file);
    stream.setAutoFormatting(true);
    stream.writeStartDocument();
    stream.writeStartElement("recipe");
    stream.writeAttribute("version", "1");

    for (auto iter = m_RecipeCards.begin(); iter != m_RecipeCards.end(); ++iter) {
        (*iter)->WriteRecipe(stream, iVersion);
    }

    for (auto iter = m_RecipeSMS.begin(); iter != m_RecipeSMS.end(); ++iter) {
        (*iter)->WriteRecipe(stream, iVersion);
    }
    streamWriter.writeEndElement();

    streamWriter.writeEndDocument();
    */
}

void CMAllsystem::SetCamLight(int32_t iCamID, int32_t light, bool bdirect,
                              bool bsetDefault)
{
    CLightDriver* pLightDriver = GET_CARD(LIGHT_DRIVER_DIRECT, CLightDriver);
    if (!bdirect) {
        pLightDriver = GET_CARD(LIGHT_DRIVER_SIDE, CLightDriver);
    }
    Q_ASSERT(pLightDriver);

    switch (iCamID) {
    case CAM2X:
        if (bdirect) { pLightDriver->setlight(LIGHT_DIRECT2X, light); } else { pLightDriver->setlight(LIGHT_SIDE2X, light); }
        break;
#ifdef __USE_THIRD_CAMERA__
    case CAMKerf:
        if (bdirect) { pLightDriver->setlight(LIGHT_DIRECT4X, light); } else { pLightDriver->setlight(LIGHT_SIDE4X, light); }
        break;
#endif
    case CAM6X:
        if (bdirect) { pLightDriver->setlight(LIGHT_DIRECT6X, light); } else { pLightDriver->setlight(LIGHT_SIDE6X, light); }
        break;
    default:
        return;
        Q_ASSERT(0);
        break;
    }
    if (bsetDefault) {
        CCamDriver* pCamDriver = GET_CARD(CAM_DRIVER, CCamDriver);
        Q_ASSERT(pCamDriver);
        pCamDriver->set_default_cam_property(iCamID, Var_Cam_Exposure_ID);
        pCamDriver->set_default_cam_property(iCamID, Var_Cam_Gain_ID);
        pCamDriver->set_default_cam_property(iCamID, Var_Cam_Contrast_ID);
        pCamDriver->set_default_cam_property(iCamID, Var_Cam_Brightness_ID);
    }
}

void CMAllsystem::SetCamParam(int iCamID, int exposureUs, int gain)
{
    CCamDriver* pCamDriver = GET_CARD(CAM_DRIVER, CCamDriver);
    Q_ASSERT(pCamDriver);
    pCamDriver->set_cam_property(iCamID, Var_Cam_Exposure_ID, exposureUs, false);
    pCamDriver->set_cam_property(iCamID, Var_Cam_Gain_ID, gain, false);
}

void CMAllsystem::SetCamParam_sig(int iCamID, int exposureUs, int gain, V_MsgQueue& msgqueue)
{
    msgqueue.pushback_Msg(VarMsg_Driver_ID,
                          QObject::trUtf8("Set cam property Exposure Sig"),
                          QVariantList()
                          << CAM_DRIVER << CCamDriver::SET_CAM_PROPERTY
                          << iCamID << Var_Cam_Exposure_ID
                          << exposureUs << false, 0);

    msgqueue.pushback_Msg(VarMsg_Driver_ID,
                          QObject::trUtf8("Set cam property Gain Sig"),
                          QVariantList()
                          << CAM_DRIVER << CCamDriver::SET_CAM_PROPERTY
                          << iCamID << Var_Cam_Gain_ID
                          << gain << false, 0);
}

void CMAllsystem::SetCamLight_sig(int32_t iCamID, int32_t light,
                                  bool bdirect, bool bsetDefault, V_MsgQueue& msgqueue)
{
    int32_t iligthID = 0;
    int driverId = LIGHT_DRIVER_DIRECT;
    if (!bdirect)
        driverId = LIGHT_DRIVER_SIDE;
    switch (iCamID) {
    case CAM2X:
        if (bdirect) { iligthID = LIGHT_DIRECT2X; } else { iligthID = LIGHT_SIDE2X; }
        break;
    case CAM6X:
        if (bdirect) { iligthID = LIGHT_DIRECT6X; } else { iligthID = LIGHT_SIDE6X; }
        break;
#ifdef __USE_THIRD_CAMERA__
    case CAMKerf:
        if (bdirect) { iligthID = LIGHT_DIRECT4X; } else { iligthID = LIGHT_SIDE4X; }
        break;
#endif
    default:
        return;
        Q_ASSERT(0);
        break;
    }

    msgqueue.pushback_Msg(VarMsg_Driver_ID,
                          QObject::trUtf8("Set Light Sig"),
                          QVariantList()
                          << driverId << CLightDriver::SETLIGHT
                          << iligthID << light, 0);

    if (bsetDefault) {
        msgqueue.pushback_Msg(VarMsg_Driver_ID,
                              QObject::trUtf8("Set default cam property Exposure Sig"),
                              QVariantList()
                              << CAM_DRIVER << CCamDriver::SET_DEFAULT_CAM_PROPERTY
                              << iCamID << Var_Cam_Exposure_ID, 0);
        msgqueue.pushback_Msg(VarMsg_Driver_ID,
                              QObject::trUtf8("Set default cam property Gain Sig"),
                              QVariantList()
                              << CAM_DRIVER << CCamDriver::SET_DEFAULT_CAM_PROPERTY
                              << iCamID << Var_Cam_Gain_ID, 0);
        msgqueue.pushback_Msg(VarMsg_Driver_ID,
                              QObject::trUtf8("Set default cam property Contrast Sig"),
                              QVariantList()
                              << CAM_DRIVER << CCamDriver::SET_DEFAULT_CAM_PROPERTY
                              << iCamID << Var_Cam_Contrast_ID, 0);
        msgqueue.pushback_Msg(VarMsg_Driver_ID,
                              QObject::trUtf8("Set default cam property Brightness Sig"),
                              QVariantList()
                              << CAM_DRIVER << CCamDriver::SET_DEFAULT_CAM_PROPERTY
                              << iCamID << Var_Cam_Brightness_ID, 0);
    }

}

void CMAllsystem::SetDefaultLight(int32_t iCamID)
{
    CCam* pCam = GET_CHDIRECT(iCamID, CCam);
    Q_ASSERT(pCam);
    int iLightDirect = pCam->m_Variants.get_VData(Var_Cam_LightDirect_default_ID)
        ->toInt();
    int iLightSide = pCam->m_Variants.get_VData(Var_Cam_LightSide_default_ID)
        ->toInt();
    SetCamLight(iCamID, iLightDirect, true, false);
    SetCamLight(iCamID, iLightSide, false, false);
}

void CMAllsystem::SetDefaultLight_Sig(int32_t iCamID, V_MsgQueue& msgqueue)
{
    CCam* pCam = GET_CHDIRECT(iCamID, CCam);
    Q_ASSERT(pCam);
    int iLightDirect = pCam->m_Variants.get_VData(Var_Cam_LightDirect_default_ID)
        ->toInt();
    int iLightSide = pCam->m_Variants.get_VData(Var_Cam_LightSide_default_ID)
        ->toInt();
    SetCamLight_sig(iCamID, iLightDirect, true, false, msgqueue);
    SetCamLight_sig(iCamID, iLightSide, false, true, msgqueue);
}

int32_t CMAllsystem::get_lightdata(int32_t iCamID, bool bdirect)
{
    int32_t iligthID = 0;
    switch (iCamID) {
    case CAM2X:
        if (bdirect) { iligthID = LIGHT_DIRECT2X; } else { iligthID = LIGHT_SIDE2X; }
        break;
    case CAM6X:
        if (bdirect) { iligthID = LIGHT_DIRECT6X; } else { iligthID = LIGHT_SIDE6X; }
        break;
#ifdef __USE_THIRD_CAMERA__
    case CAMKerf:
        if (bdirect) { iligthID = LIGHT_DIRECT4X; } else { iligthID = LIGHT_SIDE4X; }
        break;
#endif
    default:
        return 0;
        Q_ASSERT(0);
        break;
    }
    CLight* pLight = GET_CHDIRECT(iligthID, CLight);
    Q_ASSERT(pLight);
    return pLight->m_Variants.get_VData(Var_Light_Bright_ID)->toInt();
}

void CMAllsystem::write_config(bool bAll)
{
    m_Variants.get_VData(Var_AllSystem_CurChID_ID)->setValue((int)m_iCurChID);
    m_Variants.get_VData(Var_AllSystem_CellSize_ID)->setValue((int)m_iCellSize);

    CAllsystem::write_config(bAll);

}

void CMAllsystem::read_config(bool bAll)
{
    CAllsystem::read_config(bAll);
    m_iCurChID = m_Variants.get_VData(Var_AllSystem_CurChID_ID)->toInt();
    m_iCellSize = m_Variants.get_VData(Var_AllSystem_CellSize_ID)->toInt();

}

void CMAllsystem::write_wafersize_config()
{
    CMProduct* pProduct = GET_CHDIRECT(PRODUCT, CMProduct);
    QString strPath;
    uint isizetype = pProduct->m_Variants.get_VData(Var_MProduct_SizeType_ID)
        ->toUInt();
    if (isizetype == 0) {
        strPath = CMakePath::make_config_path("12Inch.xml");
    } else if (isizetype == 1) {
        strPath = CMakePath::make_config_path("8Inch.xml");
    } else {
        strPath = CMakePath::make_config_path("6Inch.xml");
    }
    QFile file(strPath);
    bool isOk = file.open(QIODevice::WriteOnly);
    if (true == isOk) {
        QDomDocument doc;
        //创建xml头部格式 <?xml version="1.0" encoding="UTF-8"?>
        QDomProcessingInstruction ins;
        ins = doc.createProcessingInstruction("xml", "version=\'1.0\' encoding=\'UTF-8\'");
        //追加元素
        doc.appendChild(ins);
        //根节点元素
        QDomElement root = doc.createElement(m_sName);
        root.setAttribute("ID", m_iID);
        doc.appendChild(root);
        for (CARDSMAP::iterator ii = mcards.begin(); ii != mcards.end(); ii++) {
            if ((*ii)->m_iSerialStyle & TOREADONLY) continue;
            if ((*ii)->m_iID != CASSETTE_DRIVER) { continue; }
            (*ii)->WriteConfig(doc, root);
        }

        for (SMMAP::iterator iii = msms.begin(); iii != msms.end(); iii++) {
            if ((*iii)->m_iSerialStyle & TOREADONLY) continue;
            if ((*iii)->m_iID != SM_COAT && (*iii)->m_iID != SM_CLEAN
                && (*iii)->m_iID != SM_TRANS) {
                continue;
            }
            (*iii)->WriteConfig(doc, root);
        }
        //保存
        QTextStream stream(&file);  //文本流关联文件
        doc.save(stream, 4); //4 缩进字符

        file.close();  //关闭文件
    }
}

void CMAllsystem::read_wafersize_config()
{
    return;
    CMProduct* pProduct = GET_CHDIRECT(PRODUCT, CMProduct);
    QString strPath;
    uint isizetype = pProduct->m_Variants.get_VData(Var_MProduct_SizeType_ID)
        ->toUInt();
    if (isizetype == 0) {
        strPath = CMakePath::make_config_path("12Inch.xml");
    } else if (isizetype == 1) {
        strPath = CMakePath::make_config_path("8Inch.xml");
    } else {
        strPath = CMakePath::make_config_path("6Inch.xml");
    }
    QFile file(strPath);
    bool isOk = file.open(QIODevice::ReadOnly);
    if (true == isOk) {
        //file和文档对象关联
        QDomDocument doc;
        QString errorMsg; int errorLine; int errorColumn;
        isOk = doc.setContent(&file, &errorMsg, &errorLine, &errorColumn);
        if (isOk) //如果关联成功
        {
            //获取根节点
            QDomElement root = doc.documentElement();
            file.close();
            QDomNodeList List = root.childNodes();
            int iSizeList = List.size();
            int iIndex = 0;
            for (CARDSMAP::iterator ii = mcards.begin(); ii != mcards.end(); ii++) {
                if ((*ii)->m_iSerialStyle & TOWRITEONLY) continue;
                if ((*ii)->m_iID != CASSETTE_DRIVER) { continue; }
                Q_ASSERT(iIndex < iSizeList); UNUSED(iSizeList);
                (*ii)->ReadConfig(List.at(iIndex).toElement());
                iIndex++;
            }

            for (SMMAP::iterator iii = msms.begin(); iii != msms.end(); iii++) {
                if ((*iii)->m_iSerialStyle & TOWRITEONLY) continue;
                if ((*iii)->m_iID != SM_COAT && (*iii)->m_iID != SM_CLEAN
                    && (*iii)->m_iID != SM_TRANS) {
                    continue;
                }
                Q_ASSERT(iIndex < iSizeList); UNUSED(iSizeList);
                (*iii)->ReadConfig(List.at(iIndex).toElement());
                iIndex++;
            }
        } else {
            MqDebug() << "read config err." << "Error Message:" << errorMsg;
            MqDebug() << "Error Line:" << errorLine;
            MqDebug() << "Error Column:" << errorColumn;
        }
        file.close();
    }
}

int CMAllsystem::read_language_config()
{
    QString configPath = CMakePath::make_config_path("config.xml");
    QFile file(configPath);
    if (!file.open(QIODevice::ReadOnly))
    {
        return 0;
    }

    QDomDocument doc; QString errorMsg;  int errorLine; int errorColumn;
    if (false == doc.setContent(&file, &errorMsg, &errorLine, &errorColumn))
    {
        return 0;
    }
    file.close();

    QDomElement root = doc.documentElement();

    QDomNodeList List = root.childNodes();
    int iSizeList = List.size();
    for (int i = 0; i < iSizeList; i++)
    {
        QDomElement item = List.at(i).toElement();
        
        if (item.attribute("ID").toInt() == Var_AllSystem_Language_Type_ID)
        {
            return item.childNodes().at(0).toElement().text().toInt();
        }
    }

    return 0;
}
void CMAllsystem::Serialize(QDataStream& stream, bool bwrite)
{
    try {
        static int versionId = 1;
        if (bwrite) {
            stream << versionId;
        } else {
            stream >> versionId;
        }
        //    if(!bwrite) return;
        CAllsystem::Serialize(stream, bwrite, versionId);
        if (bwrite) {
            write_wafersize_config();
        } else {
            read_wafersize_config();
        }
        if (!bwrite) {
            SetCutStreet(0, m_iCurSideID, CAM2X, true);
            SetCutStreet(0, m_iCurSideID, CAM6X, true);
#ifdef __USE_THIRD_CAMERA__
            SetCutStreet(0, m_iCurSideID, CAMKerf, true);
#endif
        }
    } catch (QString& s) {
        m_SysMsg.SetMsg(s);
    }
}

void CMAllsystem::ReadRecipe(ConfigStreamReader& streamReader, int iVersion)
{
    CAllsystem::ReadRecipe(streamReader, iVersion);
    SetCutStreet(0, m_iCurSideID, CAM2X, true);
    SetCutStreet(0, m_iCurSideID, CAM6X, true);
}

void CMAllsystem::EvtLog(QString& evt, QString& data)
{
    CWorkerDriver* pDriver = GET_CARD(M_WORKERDRIVER, CWorkerDriver);
    Q_ASSERT(pDriver);
    //LOG(INFO) << INFO_TITTLE() <<evt.toStdString()<<  "(" <<data.toStdString()<<")";
    m_gSystem.LogInfo(evt + "(" + data + ")");
    pDriver->LogWrite(evt, data);
}

//X方向切割，自动开激光
int CMAllsystem::CutPosX(double dStartPosX, double dEndPosX, double dPosY,
                         double dPosZ, int iDelayTime,
                         int iLaserPathID, double dOffsetY,
                         double dspd, int iside, int iSubIndex, bool bEnableLaser, double dAccSpeed/*=0*/,
                         bool bSetIOStatus/*=true*/, bool bSetCutSpeed/*=true*/, bool bCloseLaserIO/*=true*/)
{
    bEnableLaser = m_bEnbaleLaserOpen;
    CutPos(dStartPosX, dEndPosX, dPosY, dPosZ, dOffsetY, 0, iLaserPathID, true, dspd, dAccSpeed, bEnableLaser);
    return RTN_SUCCESS1;
#if 0
    if (bEnableLaser) {
        CLaserDriver_SP* pLaserDriver = GET_CARD(LASER_DRIVER, CLaserDriver_SP);
        if (!pLaserDriver->m_bInternalGate) {
            MQT_THROW_CODESTR(ALARM_MAIN_LOGIC_PARAM, QObject::trUtf8("Laser Inner Gate not opened"));
        }
    }
    //TODO:处理划线异常时，直接软件关掉激光器
    bool bRecordCutTime = true;
    CPreciseTime timeElpase;
    timeElpase.StartTime();
    CPreciseTime timeElpaseAll;
    timeElpaseAll.StartTime();
    CMPointd calcStart, calcEnd, calcGateStart, calcGateEnd;
    CalcPos(dStartPosX, dEndPosX, dPosY, dPosZ, dOffsetY, dspd, iLaserPathID,
            calcStart, calcEnd, calcGateStart, calcGateEnd);
    //MqDebug()<<"dStartPosX Time:"<<m_gSystem.m_lineTime.GetTime()<<"S";
    //LOG_IF(INFO, bRecordCutTime) << "Start Cut Pos X" << " Actual Line Width:" << fabs(dStartPosX - dEndPosX);
    //MqDebug() << "CutPosX X1:" << dStartPosX << "X2" << dEndPosX <<  "Y:" << dPosY << "Z:" << dPosZ << "Length:" << dStartPosX-dEndPosX;
    UNUSED(iDelayTime);
    //平台定位误差在生成切割道的时候进行补偿
    //CWorktableOffset* pOffset=GET_CHDIRECT(WTOFFSET,CWorktableOffset);
    //int iEnable=pOffset->m_Variants.get_VData(Var_WorkTable_Offset_EnableOffset)
    //        ->toBool();
    //if(iEnable)
    //{
    //    //偏移Y方向，平台位置补偿,默认禁用
    //    CWorktableOffsetDriver* pOffsetDriver=GET_CARD(WTOFFSET_DRIVER,CWorktableOffsetDriver);
    //    double dWorktableOffsetY=pOffsetDriver->GetOffset(WTOFFSET,dPosY);
    //    dOffsetY+=dWorktableOffsetY;
    //}

    //启用激光Y向位置补偿
    CLaserPath* pLaserPath = GET_CHDIRECT(iLaserPathID, CLaserPath);
    Q_ASSERT(pLaserPath);
    double dLaserOffsetY = 0;
    pLaserPath->GetOffset(dLaserOffsetY);
    dOffsetY += dLaserOffsetY;

    dPosY += dOffsetY;
    CMWorkTableDriver* pWorktableDriver =
        GET_CARD(WORKTABLE_DRIVER, CMWorkTableDriver);
    Q_ASSERT(pWorktableDriver);
    CMotorDriver_ACS* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver_ACS);
    Q_ASSERT(pMotorDriver);
    CMotor* pMotorX = GET_CHDIRECT(MOTORX, CMotor);
    CLaserDriver* pLaserDriver = GET_CARD(LASER_DRIVER, CLaserDriver);
    float curZos = pMotorDriver->get_posdata(MOTORZ, true);
    if (!INRANGE(dPosZ, curZos - 0.001, curZos + 0.001))
        pMotorDriver->absmove(MOTORZ, dPosZ);

    //MqDebug()<<"MOVEZ Time:"<<m_gSystem.m_lineTime.GetTime()<<"S";
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X Z Arriavel " << timeElpase.GetTime() << "S" << " Target:" << dPosZ << " CurPos:" << dPosZ;
    timeElpase.ClearTime();
    timeElpase.StartTime();
    if (DEQUAL0(dspd)) {
        MQT_THROW_CODESTR(ALARM_MAIN_LOGIC_PARAM, QObject::trUtf8("X Direct cut Err.Cut Speed equal 0."));
    }
    if (DEQUAL0(dAccSpeed)) {
        dAccSpeed = pMotorX->m_Variants.get_VData(Var_Motor_Default_accspd_ID)
            ->toDouble();
    }

    //iDelayTime = 338;3.38ms
    double dGateDelayDisStart = dspd * m_LaserGateDelay / 1000;
    double dGateDelayDisEnd = dspd * m_LaserGateDelayEnd / 1000;

    //加速距离
    double dSpdRate = dAccSpeed / dspd;
    double dExpandlength = dspd / dSpdRate + dGateDelayDisStart;
    //double dExpandlength = dspd*dspd*0.6/dAccSpeed;

    CMPointd AxisStart, AxisEnd, WPDPStart, WPDPEnd, AxisOCStart, AxisOCEnd;

    WPDPStart = CMPointd(dStartPosX, dPosY);
    WPDPEnd = CMPointd(dEndPosX, dPosY);


    double dDelayDis = 0;
    CMPointd CURWPDP;
    pWorktableDriver->CurAxisToWt(iLaserPathID, CURWPDP, true);

    //到起点距离到终点远，则交换起点位置
    if (fabs(CURWPDP.tX - WPDPStart.tX) > fabs(CURWPDP.tX - WPDPEnd.tX)) {
        CMPointd WPDPTemp = WPDPStart; WPDPStart = WPDPEnd; WPDPEnd = WPDPTemp;
    }
    //开关光偏移，实际划线坐标
    //起点为靠近激光头方向的点
    if (WPDPStart.tX > WPDPEnd.tX) {
        //从右往左划线
        WPDPStart.tX -= dDelayDis;
        WPDPEnd.tX -= dDelayDis;
    } else {
        //起点靠近原点,从左往右划线
        WPDPStart.tX += dDelayDis;
        WPDPEnd.tX += dDelayDis;
    }

    double pegpos[2] = { 0 };
    int state[2] = { 0 };

    int isize = 0;
    double dDotLineStep = 0;
    double dSolidLine = 0;
    double dSolidBase = 0;
    CProductSide* pProductSide = GET_CHDIRECT(iside, CProductSide);
    if (pProductSide) {
        int iSubSize = pProductSide->m_vSubIndex.size();
        dDotLineStep = pProductSide->m_Variants.get_VData(Var_ProductSide_StepDotLine)
            ->toDouble();
        dSolidLine = pProductSide->m_Variants.get_VData(Var_ProductSide_SolidDotLine)
            ->toDouble();
        dSolidBase = pProductSide->m_dSolidBasePosX;
        if (iSubIndex >= 0 && iSubIndex < iSubSize) {
            SUBINDEX& subIndex = pProductSide->m_vSubIndex[iSubIndex];
            dDotLineStep = subIndex.dSubIndexX;
            dSolidLine = subIndex.dSolidLine;
            dSolidBase += subIndex.dSolidOffset;
        }

    }

    pWorktableDriver->WtToAxis(iLaserPathID, WPDPStart, AxisOCStart);
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPEnd, AxisOCEnd);

    //Gate延迟,起点在右边
    if (AxisOCStart.tX > AxisOCEnd.tX) {
        AxisOCStart.tX += dGateDelayDisStart;
        AxisOCEnd.tX += dGateDelayDisEnd;
    } else {
        AxisOCStart.tX -= dGateDelayDisStart;
        AxisOCEnd.tX -= dGateDelayDisEnd;// - dGateDelayDisStart - dGateDelayDisEnd;
    }

    state[0] = 1;
    state[1] = 0;
    isize = 2;
    pegpos[0] = AxisOCStart.tX;	//开光点
    pegpos[1] = AxisOCEnd.tX;		//关光点

    //MqDebug() << "Gate Start:" << AxisOCStart.tX << "Gate End:" << AxisOCEnd.tX << "Diff:" << AxisOCEnd.tX - AxisOCStart.tX <<endl;
    //MqDebug() << "Delay Start:" << dGateDelayDisStart << "Delay End:" << dGateDelayDisEnd << endl;

//运动到准备点,添加加速段的距离
    if (WPDPStart.tX > WPDPEnd.tX) {

        WPDPStart.tX += dExpandlength;
        WPDPEnd.tX -= dExpandlength;
    } else {
        WPDPStart.tX -= dExpandlength;
        WPDPEnd.tX += dExpandlength;
    }


    //计算坐标点
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPStart, AxisStart);
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPEnd, AxisEnd);
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X Ready Move To Start " << timeElpase.GetTime() << "S";
    timeElpase.ClearTime();
    timeElpase.StartTime();
    //移动到起始位置
    /*pMotorDriver->absmove(MOTORX,AxisStart.tX,FALSE);
    pMotorDriver->absmove(MOTORY,AxisStart.tY,FALSE);*/
    //HACK:直接移动，跳过安全性检查
    pMotorDriver->absmove_direct(MOTORX, AxisStart.tX, false);
    pMotorDriver->absmove_direct(MOTORY, AxisStart.tY, false);

    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X Move Start Finish " << timeElpase.GetTime() << "S";
    timeElpase.ClearTime();
    timeElpase.StartTime();

    //TODO:启动Gate开光buffer
    //设定加工速度
    if (bSetCutSpeed)
        pMotorDriver->setspeed(MOTORX, dspd, 0, 0, 0, 0);
    //MSleep(100);
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X setspeed finished " << timeElpase.GetTime() << "S";
    timeElpase.ClearTime();
    timeElpase.StartTime();

    //TODO:开始划线
    //MqDebug() << "关激光" <<endl;

    if (bSetIOStatus) {
        pLaserDriver->OpenLaserGate(LASER, FALSE);
        pMotorDriver->setio(IO_OUTPUT, OUT_BLUE, TRUE);
        pMotorDriver->setio(IO_OUTPUT, OUT_LENS_Blow_Inner, TRUE);
        pMotorDriver->setio(IO_OUTPUT, OUT_LENS_Blow_Outter, TRUE);
    }
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X OpenLaserGate finished " << timeElpase.GetTime() << "S";
    timeElpase.ClearTime();
    timeElpase.StartTime();

    //等待运动结束放后面，让其他IO先操作
    pMotorDriver->wait_move_finished_block(MOTORX, 30000);
    pMotorDriver->wait_move_finished_block(MOTORY, 30000);

    double dCurX = pMotorDriver->get_posdata(MOTORX, true);
    double dCurY = pMotorDriver->get_posdata(MOTORY, true);
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X Already move to start finished" << timeElpase.GetTime() << "S";
    //LOG_IF(INFO, bRecordCutTime) << "Target:X:" << AxisStart.tX << "Y:" << AxisStart.tY << " CurX:" << dCurX << " CurY:" << dCurY;
    timeElpase.ClearTime();
    timeElpase.StartTime();

    /*   pMotorDriver->PEGMove(MOTORX,AxisStart.tX,AxisEnd.tX,pegpos,state,isize);
       delete [] pegpos;
       delete [] state;
       pMotorDriver->stopmove(MOTORX);
       */

    QString err = "";
    int ret = RTN_SUCCESS1;
    try {
        //TODO:处理急停操作
        //按了急停后，这后续的操作需要处理
        //AxisStart 运动的起点
        //AxisEnd 运动的终点
        if (!IsSimulator()) {
            ret = pMotorDriver->PEGMove_BuffGate(MOTORX, OUT_LASERGATE, AxisStart.tX, AxisEnd.tX, pegpos, 2, bEnableLaser);
        } else {
            pMotorDriver->absmove(MOTORX, AxisEnd.tX, FALSE);
            pMotorDriver->wait_move_finished_block(MOTORX, 10000);
        }
    } catch (const QString& ex) {
        LOG_ERR(ex.toLocal8Bit().data());
        err = ex;

        //关闭激光器
        LOG_ERR("Error shut down laser");
        bool bClosed = false;
        try {
            pLaserDriver->OpenLaserGate(LASER, FALSE);
        } catch (const QString& ioEx) {
            LOG_ERR(fmt::format("OpenLaserGate FALSE failed {}", ioEx.toLocal8Bit().data()));
        }
        try {
            CLaserDriver_SP* pLaserDriver = GET_CARD(LASER_DRIVER, CLaserDriver_SP);
            pLaserDriver->SetInnerGate(LASER, false);
            bClosed = true;
        } catch (const QString& laserEx) {
            LOG_ERR(fmt::format("SetInnerGate failed", laserEx.toLocal8Bit().data()));
        }


        m_gSystem.LogError("Error shut down laser");
        m_gSystem.LogError(ex);

        if (false == bClosed) {
            err += "/nBut close Laser failed.Push down EMG immediately";
        }

        ret = RTN_FAILED1;
    }
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X PEG Finished " << timeElpase.GetTime() << "S";;
    timeElpase.ClearTime();
    timeElpase.StartTime();


    pMotorDriver->stopmove(MOTORX);

    //LOG_IF(INFO, bRecordCutTime) << "StopMove Time: " << timeElpase.GetTime() << "S";
    timeElpase.ClearTime();
    timeElpase.StartTime();

    //关光
    //MqDebug() << "再关一次激光" <<endl;
    if (bCloseLaserIO)
        pLaserDriver->OpenLaserGate(LASER, FALSE);

    if (bSetCutSpeed) {
        //恢复默认速度
        pMotorDriver->setdefaultspeed(MOTORX);
        //LOG_IF(INFO, bRecordCutTime) << "Reset default speed" << timeElpase.GetTime() << "S";
    }
    if (ret != RTN_SUCCESS1) {
        pLaserDriver->OpenLaserGate(LASER, FALSE);
        MQT_THROW_CODESTR(ALARM_FALTAL_LASER_CUTLINE, (QObject::trUtf8("Cut line failed.") + "\n" + err));
    }

    //LOG_IF(INFO, bRecordCutTime) << "Calc	:Start" << calcStart.tX << "," << calcStart.tY << "," << calcEnd.tX << "," << calcEnd.tY;
    //LOG_IF(INFO, bRecordCutTime) << "CutPosX:Start" << AxisStart.tX << "," << AxisStart.tY << "," << AxisEnd.tX << "," << AxisEnd.tY;

    //LOG_IF(INFO, bRecordCutTime) << "Calc	:GateEnd" << calcGateStart.tX << "," << calcGateStart.tY << "," << calcGateEnd.tX << "," << calcGateEnd.tY;
    //LOG_IF(INFO, bRecordCutTime) << "CutPosX:GateEnd" << AxisOCStart.tX << "," << AxisOCStart.tY << "," << AxisOCEnd.tX << "," << AxisOCEnd.tY;

    //LOG_IF(INFO, bRecordCutTime) << "Line Width:" << fabs(dStartPosX - dEndPosX)
    //    << " Move Width:" << fabs(AxisStart.tX - AxisEnd.tX)
    //    << " Gate Width:" << fabs(AxisOCEnd.tX - AxisOCStart.tX);


    ////LOG_IF(INFO, true) << "Start " << AxisStart.tX <<"," << AxisOCStart.tX <<"," << AxisOCEnd.tX <<"," << AxisEnd.tX<< " END";
    //LOG_IF(ERROR, !((AxisStart.tX < AxisOCStart.tX&&AxisOCEnd.tX < AxisEnd.tX)
    //                || (AxisStart.tX > AxisOCStart.tX&&AxisOCEnd.tX > AxisEnd.tX)))
    //    << "Start " << AxisStart.tX << "," << AxisOCStart.tX << "," << AxisOCEnd.tX << "," << AxisEnd.tX << " END";
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X All Finish: " << timeElpaseAll.GetTime() << "S" << " Move" << fabs(AxisStart.tX - AxisEnd.tX);
    return 0;
#endif
}

//没有使用Y轴切割
int CMAllsystem::CutPosY(double dStartPosY, double dEndPosY, double dPosX, double dPosZ,
                         int iLaserPathID, double dOffsetX, double dOverCut,
                         double dCutSpeed, double dAccSpeed)
{
    CMotor* pMotor = GET_CHDIRECT(MOTORY, CMotor);
    double dspdX = pMotor->m_Variants.get_VData(Var_Motor_Default_speed_ID)->toDouble();

    return CutPos(dStartPosY, dEndPosY, dPosX, dPosZ, 0, 0, iLaserPathID, false, dspdX, 0, true);

#if 0
    MqDebug() << "CutPosY:" << "YStart" << dStartPosY << "YEnd" << dEndPosY << "XPOS" << dPosX << "POSZ" << dPosZ << "dOffsetX" << dOffsetX;
    //UNUSED(iDelayTime);
    dPosX += dOffsetX;
    CMWorkTableDriver* pWorktableDriver =
        GET_CARD(WORKTABLE_DRIVER, CMWorkTableDriver);
    Q_ASSERT(pWorktableDriver);
    CMotorDriver_ACS* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver_ACS);
    Q_ASSERT(pMotorDriver);
    CLaserDriver* pLaserDriver = GET_CARD(LASER_DRIVER, CLaserDriver);
    Q_ASSERT(pLaserDriver);
    pMotorDriver->absmove(MOTORZ, dPosZ);

    CMPointd AxisStart, AxisEnd, WPDPStart, WPDPEnd, AxisOCStart, AxisOCEnd;

    WPDPStart = CMPointd(dPosX, dStartPosY);
    WPDPEnd = CMPointd(dPosX, dEndPosY);

    //	double dDelayDis=SpdY.dSpeed*iDelayTime/1000;
    double dDelayDis = 0;
    CMPointd CURWPDP;
    pWorktableDriver->CurAxisToWt(iLaserPathID, CURWPDP, true);
    if (fabs(CURWPDP.tY - WPDPStart.tY) > fabs(CURWPDP.tY - WPDPEnd.tY)) {
        CMPointd WPDPTemp = WPDPStart; WPDPStart = WPDPEnd; WPDPEnd = WPDPTemp;
    }

    if (WPDPStart.tY > WPDPEnd.tY) {
        WPDPStart.tY += dDelayDis;
        WPDPEnd.tY += dDelayDis;
    } else {
        WPDPStart.tY -= dDelayDis;
        WPDPEnd.tY -= dDelayDis;
    }

    pWorktableDriver->WtToAxis(iLaserPathID, WPDPStart, AxisOCStart);
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPEnd, AxisOCEnd);

    CMotor* pMotorY = GET_CHDIRECT(MOTORY, CMotor);
    double dspd = pMotor->m_Variants.get_VData(Var_Motor_Default_speed_ID)->toDouble();
    if (DEQUAL0(0)) {
        dAccSpeed = pMotor->m_Variants.get_VData(Var_Motor_Default_accspd_ID)->toDouble();;
    }

    //加速距离
    double dSpdRate = dAccSpeed / dspd;
    double dExpandlength = dspd / dSpdRate;//+dGateDelayDisStart;
    //double dExpandlength = dspd*dspd*0.6/dAccSpeed;
    if (WPDPStart.tY > WPDPEnd.tY) {

        WPDPStart.tY += dExpandlength;
        WPDPEnd.tY -= dExpandlength;
    } else {
        WPDPStart.tY -= dExpandlength;
        WPDPEnd.tY += dExpandlength;
    }
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPStart, AxisStart);
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPEnd, AxisEnd);

    pMotorDriver->absmove(MOTORX, AxisStart.tX, FALSE);
    pMotorDriver->absmove(MOTORY, AxisStart.tY, FALSE);

    pMotorDriver->wait_move_finished(MOTORX);
    pMotorDriver->wait_move_finished(MOTORY);

    //开光
    //pLaserDriver->SetGateSource(LASER,TRUE);
//    pLaserDriver->OpenLaserGate(iLaserPathID,TRUE);

//    pMotorDriver->absmove(MOTORY,AxisEnd.tY,FALSE);
//    pMotorDriver->wait_move_finished(MOTORY);

    double pegpos[2] = { 0 };
    pegpos[0] = AxisOCStart.tY;	//开光点
    pegpos[1] = AxisOCEnd.tY;		//关光点


    QString err = "";
    int ret = RTN_SUCCESS1;
    try {
        if (!IsSimulator())
        {
            ret = pMotorDriver->PEGMove_BuffGate(MOTORY, OUT_LASERGATE, AxisStart.tY, AxisEnd.tY, pegpos, 2, m_gSystem.m_bEnbaleLaserOpen);
        }
        else
        {
            pMotorDriver->absmove(MOTORY, AxisEnd.tY, FALSE);
            pMotorDriver->wait_move_finished_block(MOTORY, 30000);
        }
    } catch (const QString& ex) {
        UNUSED(ex)
            ret = RTN_FAILED1;
    }

    pMotorDriver->stopmove(MOTORY);

    //关光
    pLaserDriver->OpenLaserGate(LASER, FALSE);
    //pLaserDriver->SetGateSource(LASER,FALSE);
    pMotorDriver->setdefaultspeed(MOTORY);

    if (ret != RTN_SUCCESS1) {
        MQT_THROW_CODESTR(ALARM_MOTION_MOVE, QObject::trUtf8("PEG buffer gate operate failed."));
    }
    return 0;
#endif
}

int CMAllsystem::CutPos(double dStartPos, double dEndPos, double dLocationPos, double dPosZ,
                        double dOffsetY, double dOverCut,
                        int iLaserPathID, bool bXDirect, double dCutSpeed, double dAccSpeed, bool bEnableLaser)
{
    //是否启用激光，与全局配置相关联
    bEnableLaser &= m_bEnbaleLaserOpen;
    CMotorDriver_Base* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver_Base);
    //Q_ASSERT(pMotorDriver);
    CLaserDriver* pLaserDriver = GET_CARD(LASER_DRIVER, CLaserDriver);
    Q_ASSERT(pLaserDriver);
    CMWorkTableDriver* pWorktableDriver = GET_CARD(WORKTABLE_DRIVER, CMWorkTableDriver);
    Q_ASSERT(pWorktableDriver);
    bool bRecordCutTime = true;

    CMPointd axisStart, axisEnd;
    double dGateStart;
    double  dGateEnd;
    CalcPos(dStartPos, dEndPos, dLocationPos, dPosZ, dOffsetY, dOverCut,
            iLaserPathID, bXDirect, dCutSpeed, dAccSpeed,
            axisStart, axisEnd, dGateStart, dGateEnd);

    //TODO:处理点划线的情况
    //计算Z位置
    float curZos = pMotorDriver->get_posdata(MOTORZ, true);
    if (!INRANGE(dPosZ, curZos - 0.001, curZos + 0.001))
        pMotorDriver->absmove(MOTORZ, dPosZ);

    QTime timeElpase;
    double pegpos[2] = { 0 };
    int state[2] = { 0 };

    state[0] = 1;
    state[1] = 0;

    int isize = 2;
    pegpos[0] = dGateStart;	    //开光点
    pegpos[1] = dGateEnd;		//关光点

	if(bXDirect){
		if (axisStart.tX > axisEnd.tX) {
			axisEnd.tX -= 30;
		}
		else {
			axisEnd.tX += 30;
		}
	}

    //LOG_IF(INFO, true) << "Cut Pos X Ready Move To Start " << timeElpase.GetTime() << "S";
	double dPosCurY = pMotorDriver->get_posdata(MOTORY, true);
	double dPosCurX = pMotorDriver->get_posdata(MOTORX, true);
	double dOffsetTest = axisStart.tY - dPosCurY;
	double dOffsetTestX = pMotorDriver->get_posdata(MOTORX, true) - axisStart.tX;
	bool bNeedWait = fabs(dOffsetTest > 0.05) || fabs(dOffsetTestX) > 0.05;
	//bool bNeedWait = fabs(dOffsetTest > 0.05);
	//划线前准备
	if (true) {
		pLaserDriver->OpenLaserGate(LASER, FALSE);
		pMotorDriver->setio(IO_OUTPUT, OUT_BLUE, TRUE);
		//pMotorDriver->setio(IO_OUTPUT, OUT_LENS_Blow_Inner, TRUE);
		//pMotorDriver->setio(IO_OUTPUT, OUT_LENS_Blow_Outter, TRUE);
        CLaserPathDriver* pLaserPathDriver = GET_CARD(LASERPATH_DRIVER, CLaserPathDriver);
        pLaserPathDriver->OpenLensBlow(iLaserPathID, true);
	}

	CDHGripperRS485* pHgripDriver = GET_CARD(HGRIPPER_DRIVER, CDHGripperRS485);
	int iGripperValue = -1;
	pHgripDriver->GetPosValue(iGripperValue, true);
	/*if (iLaserPathID == LASERPATH_L_NARROW) {
		if (iGripperValue != 1000) {
			int state = pHgripDriver->GetPosState();
			m_gSystem.AddProductInfo(PROCESS_CUT, fmt::format("L_Narrow Gipper not equal iGripperValue : {} iState: {}", iGripperValue, state).c_str());
			MQT_THROW_CODESTR(ALARM_EAP_RESERVED, "L_Narrow Gipper not equal");
		}
	}
	else if (iLaserPathID == LASERPATH_D_WIDE) {
		if (iGripperValue != 58) {
			int state = pHgripDriver->GetPosState();
			m_gSystem.AddProductInfo(PROCESS_CUT, fmt::format("D_Wide Gipper not equal iGripperValue : {} iState: {}", iGripperValue, state).c_str());
			MQT_THROW_CODESTR(ALARM_EAP_RESERVED, "D_Wide Gipper not equal");
		}
	}*/

    if (!IsSimulator()) {
		if (bXDirect) {
			//移动到起始位置
			bool bNeedMoveX = true;
			if (axisStart.tX > axisEnd.tX) {
				if (dPosCurX > axisStart.tX) {
					bNeedMoveX = false;
				}
			}
			else {
				if (dPosCurX < axisStart.tX) {
					bNeedMoveX = false;
				}
			}
			if (bNeedMoveX) {
				static_cast<CMotorDriver_ACS*>(pMotorDriver)->absmove_direct(MOTORX, axisStart.tX, false);
			}

			static_cast<CMotorDriver_ACS*>(pMotorDriver)->absmove_direct(MOTORY, axisStart.tY, false);
		}
		else {
			static_cast<CMotorDriver_ACS*>(pMotorDriver)->absmove_direct(MOTORX, axisStart.tX, false);
			static_cast<CMotorDriver_ACS*>(pMotorDriver)->absmove_direct(MOTORY, axisStart.tY, false);
		}
    }

    //LOG_IF(INFO, true) << "Cut Pos X Move Start Finish " << timeElpase.GetTime() << "S";

    //MSleep(100);
    //LOG_IF(INFO, true) << "Cut Pos X setspeed finished " << timeElpase.GetTime() << "S";
    //LOG_IF(INFO, true) << "Cut Pos X OpenLaserGate finished " << timeElpase.GetTime() << "S";

    //等待运动结束放后面，让其他IO先操作
    pMotorDriver->wait_move_finished_block(MOTORX, 30000);
    pMotorDriver->wait_move_finished_block(MOTORY, 30000);

	pMotorDriver->wait_move_finished(MOTORX);
	if (bNeedWait) {
		//MSleep(1000);
	}

    double dCurX = pMotorDriver->get_posdata(MOTORX, true);
    double dCurY = pMotorDriver->get_posdata(MOTORY, true);
	//MqDebug() << ""
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X Already move to start finished" << timeElpase.GetTime() << "S";
	//MqDebug()  << "Target:X:" << axisStart.tX << "Y:" << axisStart.tY << " CurX:" << dCurX << " CurY:" << dCurY;
    std::ostringstream stream;
	stream << "Target:X_S:" << axisStart.tX << "X_E:" << axisEnd.tX << " CurX:" << dCurX << " CurY:" << dCurY << " GripperValue:"<< iGripperValue;
    m_gSystem.AddProductInfo(PROCESS_CUT, stream.str().c_str());
    //设定加工速度
   
    //加速度？？

    double dMovePosStart = axisStart.tX;
    double dMovePosEnd = axisEnd.tX;
    int iMotorId = MOTORX;
    if (!bXDirect) {
        dMovePosStart = axisStart.tY;
        dMovePosEnd = axisEnd.tY;
        iMotorId = MOTORY;
    }

    pMotorDriver->setspeed(iMotorId, dCutSpeed, 0, 0, 0, 0);
    QString err = "";
    int ret = RTN_SUCCESS1;
    try {
        //TODO:处理急停操作
        //按了急停后，这后续的操作需要处理
        if (!IsSimulator()) {
            //AxisStart 运动的起点
            //AxisEnd 运动的终点
            ret = static_cast<CMotorDriver_ACS*>(pMotorDriver)->PEGMove_BuffGate(iMotorId, OUT_LASERGATE, dMovePosStart, dMovePosEnd, pegpos, 2, bEnableLaser);
        } else {
            pMotorDriver->absmove(iMotorId, dMovePosEnd, FALSE);
            pMotorDriver->wait_move_finished_block(iMotorId, 10000);
        }
    } catch (const QString& ex) {
        LOG_ERR(ex.toLocal8Bit().data());
        err = ex;

        //关闭激光器
        LOG_ERR("Error shut down laser");
        bool bClosed = false;
        try {
            pLaserDriver->OpenLaserGate(LASER, FALSE);
        } catch (const QString& ioEx) {
            LOG_ERR(fmt::format("OpenLaserGate FALSE failed {}", ioEx.toLocal8Bit().data()));
        }
        try {
            CLaserDriver_SP* pLaserDriver = GET_CARD(LASER_DRIVER, CLaserDriver_SP);
            if (nullptr != pLaserDriver) {
                pLaserDriver->SetInnerGate(LASER, false);
            }
            bClosed = true;
        } catch (const QString& laserEx) {
            LOG_ERR(fmt::format("SetInnerGate failed {}", laserEx.toLocal8Bit().data()));
        }

        m_gSystem.LogError("Error shut down laser");
        m_gSystem.LogError(ex);

        if (false == bClosed) {
            err += "/nBut close Laser failed.Push down EMG immediately";
        }

        ret = RTN_FAILED1;
    }
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X PEG Finished " << timeElpase.GetTime() << "S";;

    pMotorDriver->stopmove(iMotorId);

    //LOG_IF(INFO, bRecordCutTime) << "StopMove Time: " << timeElpase.GetTime() << "S";

    //关光
    //MqDebug() << "再关一次激光" <<endl;
    if (true)
        pLaserDriver->OpenLaserGate(LASER, FALSE);

    if (true) {
        //恢复默认速度
        pMotorDriver->setdefaultspeed(MOTORX);
        //LOG_IF(INFO, bRecordCutTime) << "Reset default speed" << timeElpase.GetTime() << "S";
    }
    if (ret != RTN_SUCCESS1) {
        pLaserDriver->OpenLaserGate(iLaserPathID, FALSE);
        MQT_THROW_CODESTR(ALARM_FALTAL_LASER_CUTLINE, (QObject::trUtf8("Cut line failed.") + "\n" + err));
    }

    //LOG_IF(INFO, bRecordCutTime) << "Calc	:Start" << calcStart.tX << "," << calcStart.tY << "," << calcEnd.tX << "," << calcEnd.tY;
    //LOG_IF(INFO, bRecordCutTime) << "CutPosX:Start" << AxisStart.tX << "," << AxisStart.tY << "," << AxisEnd.tX << "," << AxisEnd.tY;

    //LOG_IF(INFO, bRecordCutTime) << "Calc	:GateEnd" << calcGateStart.tX << "," << calcGateStart.tY << "," << calcGateEnd.tX << "," << calcGateEnd.tY;
    //LOG_IF(INFO, bRecordCutTime) << "CutPosX:GateEnd" << AxisOCStart.tX << "," << AxisOCStart.tY << "," << AxisOCEnd.tX << "," << AxisOCEnd.tY;

    //LOG_IF(INFO, bRecordCutTime) << "Line Width:" << fabs(dStartPosX - dEndPosX)
    //    << " Move Width:" << fabs(AxisStart.tX - AxisEnd.tX)
    //    << " Gate Width:" << fabs(AxisOCEnd.tX - AxisOCStart.tX);


    ////LOG_IF(INFO, true) << "Start " << AxisStart.tX <<"," << AxisOCStart.tX <<"," << AxisOCEnd.tX <<"," << AxisEnd.tX<< " END";
    //LOG_IF(ERROR, !((AxisStart.tX < AxisOCStart.tX&&AxisOCEnd.tX < AxisEnd.tX)
    //                || (AxisStart.tX > AxisOCStart.tX&&AxisOCEnd.tX > AxisEnd.tX)))
    //    << "Start " << AxisStart.tX << "," << AxisOCStart.tX << "," << AxisOCEnd.tX << "," << AxisEnd.tX << " END";
    //LOG_IF(INFO, bRecordCutTime) << "Cut Pos X All Finish: " << timeElpaseAll.GetTime() << "S" << " Move" << fabs(AxisStart.tX - AxisEnd.tX);
    return 0;
}

/*
bool CMAllsystem::CalcPos(double dStartPosX, double dEndPosX, double dPosY, double dPosZ,
                          double dOffsetY, double dspd, int iLaserPathID,
                          CMPointd& AxisStart, CMPointd& AxisEnd, CMPointd& AxisGateStart, CMPointd& AxisGateEnd)
{
    dPosY += dOffsetY;

    //
    CMWorkTableDriver* pWorktableDriver = GET_CARD(WORKTABLE_DRIVER, CMWorkTableDriver);
    Q_ASSERT(pWorktableDriver);
    CMotorDriver_ACS* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver_ACS);
    Q_ASSERT(pMotorDriver);
    CMotor* pMotor = GET_CHDIRECT(MOTORX, CMotor);
    if (DEQUAL0(dspd)) {
        MQT_THROW_CODESTR(ALARM_CUT_PARAM, QObject::trUtf8("%1 Direct cut Err.Cut Speed equal 0.").arg(pMotor->m_sName));
    }

    double dAccSpeed = 0;
    if (DEQUAL0(dAccSpeed)) {
        dAccSpeed = pMotor->m_Variants.get_VData(Var_Motor_Default_accspd_ID)
            ->toDouble();
    }

    CMPointd WPDPStart, WPDPEnd;
    WPDPStart = CMPointd(dStartPosX, dPosY);
    WPDPEnd = CMPointd(dEndPosX, dPosY);

    //靠近激光头一端设定为起点
    CMPointd CURWPDP;
    pWorktableDriver->CurAxisToWt(iLaserPathID, CURWPDP, true);
    if (fabs(CURWPDP.tX - WPDPStart.tX) > fabs(CURWPDP.tX - WPDPEnd.tX)) {
        CMPointd WPDPTemp = WPDPStart; WPDPStart = WPDPEnd; WPDPEnd = WPDPTemp;
    }


    //计算Gate 开关光的点
    //iDelayTime = 338;3.38ms
    double dGateDelayDisStart = dspd * m_LaserGateDelay / 1000;
    double dGateDelayDisEnd = dspd * m_LaserGateDelayEnd / 1000;
    //CMPointd AxisGateStart,AxisGateEnd;
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPStart, AxisGateStart);
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPEnd, AxisGateEnd);
    if (AxisGateStart.tX > AxisGateEnd.tX) {
        AxisGateStart.tX += dGateDelayDisStart;
        AxisGateEnd.tX += dGateDelayDisEnd;
    } else {
        AxisGateStart.tX -= dGateDelayDisStart;
        AxisGateEnd.tX -= dGateDelayDisEnd;
    }

    //加减速距离
    //运动起点与结束点
    double dSpdRate = dAccSpeed / dspd;
    double dExpandlength = dspd / dSpdRate + dGateDelayDisStart;
    //double dExpandlength = dspd*dspd*0.6/dAccSpeed;
    //运动到准备点,添加加速段的距离
    if (WPDPStart.tX > WPDPEnd.tX) {
        WPDPStart.tX += dExpandlength;
        WPDPEnd.tX -= dExpandlength;
    } else {
        WPDPStart.tX -= dExpandlength;
        WPDPEnd.tX += dExpandlength;
    }

    //计算出起始运动点
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPStart, AxisStart);
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPEnd, AxisEnd);

    return true;
}
*/
bool CMAllsystem::CalcPos(double dStartPos, double dEndPos, double dLocationPos, double dPosZ,
                          double dOffsetPos, double dOverCut,
                          int iLaserPathID, bool bXDirect,
                          double dCutSpeed, double dAccSpeed,
                          CMPointd& axisStart, CMPointd& axisEnd, double& dGatePosStart, double& dGatePosEnd)
{
    int iWorkMotorId = bXDirect ? MOTORX : MOTORY;
    CMotor* pMotor = GET_CHDIRECT(iWorkMotorId, CMotor);
    if (DEQUAL0(dCutSpeed)) {
        MQT_THROW_CODESTR(ALARM_CUT_PARAM, QObject::trUtf8("%1 Direct cut Err.Cut Speed equal 0.").arg(pMotor->m_sName));
    }
    if (DEQUAL0(dAccSpeed)) {
        dAccSpeed = pMotor->m_Variants.get_VData(Var_Motor_Default_accspd_ID)->toDouble();
    }

    //刀痕偏移整体补偿
    CLaserPath* pLaserPath = GET_CHDIRECT(iLaserPathID, CLaserPath);
    Q_ASSERT(pLaserPath);
    double dLaserOffset = 0;
    //TODO:LowK时可能需要添加每个宽度下面的刀痕补偿数据
    pLaserPath->GetOffset(dLaserOffset);
    dOffsetPos += dLaserOffset;

    dLocationPos += dOffsetPos;

    CMWorkTableDriver* pWorktableDriver = GET_CARD(WORKTABLE_DRIVER, CMWorkTableDriver);
    Q_ASSERT(pWorktableDriver);
    //靠近激光头一端设定为起点
    CMPointd CurWaferDP;
    pWorktableDriver->CurAxisToWt(iLaserPathID, CurWaferDP, true);
    double dPosLocation = bXDirect ? CurWaferDP.tX : CurWaferDP.tY;

    //将起点设置为更靠近当前激光位置
    if (fabs(dPosLocation - dStartPos) > fabs(dPosLocation - dEndPos)) {
        /*double dTempPos = dStartPos;

        dStartPos = dEndPos;
        dEndPos = dTempPos;*/
        std::swap(dStartPos, dEndPos);
    }

    //开光提前一点开,关光晚一点关,所以开关光都是做加法
    CLaserPathDriver* pLaserDriver = GET_CARD(LASERPATH_DRIVER, CLaserPathDriver);
    double dTimeGateStartDelayMs =  pLaserDriver->m_Variants.get_VData(Var_GateStartDelay)->toDouble();
    double dTimeGateEndDelayMs = pLaserDriver->m_Variants.get_VData(Var_GateEndDelay)->toDouble();
    double dGateDelayDisStart = dCutSpeed * dTimeGateStartDelayMs / 1000;
    double dGateDelayDisEnd = dCutSpeed * dTimeGateEndDelayMs / 1000;
    if (dStartPos > dEndPos) {
        dStartPos += dGateDelayDisStart + dOverCut;
        dEndPos += dGateDelayDisEnd - dOverCut;
    } else {
        dStartPos -= dGateDelayDisStart+dOverCut;
        dEndPos -= dGateDelayDisEnd - dOverCut;
    }

    //加减速距离
    //运动起点与结束点
    //s=1/2*a*
    //TODO:需要跟踪计算一下加速的距离
    double dAccTime = dCutSpeed / dAccSpeed;
    double dExpandlength = dAccTime * dAccTime * dAccSpeed / 2 + 45; // v*v/(2a)
    //double dExpandlength = dspd*dspd*0.6/dAccSpeed;
    //运动到准备点,添加加速段的距离
    dGatePosStart = dStartPos;
    dGatePosEnd = dEndPos;
    if (dStartPos > dEndPos) {
        dStartPos += dExpandlength;
        dEndPos -= dExpandlength;
    } else {
        dStartPos -= dExpandlength;
        dEndPos += dExpandlength;
    }

    CMPointd WPDPStart, WPDPEnd, WPDPGateStart, WPDPGateEnd;
    if (bXDirect) {
        WPDPStart = CMPointd(dStartPos, dLocationPos);
        WPDPEnd = CMPointd(dEndPos, dLocationPos);
        WPDPGateStart = CMPointd(dGatePosStart, dLocationPos);
        WPDPGateEnd = CMPointd(dGatePosEnd, dLocationPos);
    } else {
        WPDPStart = CMPointd(dLocationPos, dStartPos);
        WPDPEnd = CMPointd(dLocationPos, dEndPos);
        WPDPGateStart = CMPointd(dLocationPos, dGatePosStart);
        WPDPGateEnd = CMPointd(dLocationPos, dGatePosEnd);
    }

    //计算出起始运动点
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPStart, axisStart);
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPEnd, axisEnd);

    CMPointd axisGateStart, axisGateEnd;
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPGateStart, axisGateStart);
    pWorktableDriver->WtToAxis(iLaserPathID, WPDPGateEnd, axisGateEnd);

    if (bXDirect) {
        dGatePosStart = axisGateStart.tX;
        dGatePosEnd = axisGateEnd.tX;
    } else {
        dGatePosStart = axisGateStart.tY;
        dGatePosEnd = axisGateEnd.tY;
    }

    return RTN_SUCCESS1;
}

/*!
 * \brief CMAllsystem::VacuumSet
 * 打开真空并检测输入
 * \param bOn
 * \param IOOutput
 * \param IOInput
 */
void CMAllsystem::VacuumSet(bool bOn, int IOOutput, int IOInput)
{
    if (!IsSimulator()) {
        MainPressCheck();
    }

    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    Q_ASSERT(pDriver);
    pDriver->setio(IO_OUTPUT, IOOutput, bOn);
    if (IOInput == -1 || !bOn) { return; }

    if (IsSimulator())return;

    BOOL bTimeOut = TRUE;
    CPreciseTime Time;
    Time.StartTime();
    DWORD dwTimeOut = m_Variants.get_VData(Var_AllSystem_Vacumm_TimeLimit_ID)->toInt();
    do {
        bool bOnCur = pDriver->get_iodata(IO_INPUT, IOInput, true) ? true : false;
        if (bOn == bOnCur) {
            bTimeOut = FALSE;
            break;
        }
    } while ((Time.GetTime() * 1000) < dwTimeOut);
    if (bTimeOut) {
        MQT_THROW_CODESTR(ALARM_VACCUM_TIMEOUT, QObject::trUtf8("Vacuum %1 Can not Open")
                          .arg(pDriver->getioname(IO_OUTPUT, IOOutput)));
    }
}
//破真空
void CMAllsystem::VaccumBreak(int IOOutput)
{
    MainPressCheck();
    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    Q_ASSERT(pDriver);
    pDriver->setio(IO_OUTPUT, IOOutput, true);
    int iWaitTime = m_Variants.
        get_VData(Var_AllSystem_Vacumm_BreakTimeLimit_ID)->toInt();
    MSleep(iWaitTime);
    pDriver->setio(IO_OUTPUT, IOOutput, false);
}


bool CMAllsystem::IsVaccumOn(int IOOutput, int IOInput)
{
    MainPressCheck();
    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    Q_ASSERT(pDriver);
    if (pDriver->get_iodata(IO_OUTPUT, IOOutput, true) ||
        pDriver->get_iodata(IO_INPUT, IOInput, true)) {
        return true;
    }
    return false;
}

//液体平台真空检查
void CMAllsystem::VacuumLeakCheck(int IOOutput, int IOInput)
{
    MainPressCheck();
    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    Q_ASSERT(pDriver);
    pDriver->freshio(IO_OUTPUT, IOOutput);
    if (pDriver->get_iodata(IO_OUTPUT, IOOutput, true) &&
        !pDriver->get_iodata(IO_INPUT, IOInput, true)) {
        if (IO_OUTPUT == OUT_CLEAN_VACUUM) {
            MQT_THROW_CODESTR(ALARM_CLEAN_CleanVaccumLeak, QObject::trUtf8("Vacuum %1 Is Leak")
                              .arg(pDriver->getioname(IO_OUTPUT, IOOutput)));
        } else {
            MQT_THROW_CODESTR(ALARM_COAT_CoatVaccumLeak, QObject::trUtf8("Vacuum %1 Is Leak")
                              .arg(pDriver->getioname(IO_OUTPUT, IOOutput)));
        }
    }
}

/*!
 * \brief CMAllsystem::CellExist
 * 检测是否存在晶圆 ，打开真空检查真空状态，检查完后关闭真空
 * \param IOOutput
 * \param IOInput
 * \return
 */
bool CMAllsystem::CellExist(int IOOutput, int IOInput)
{
    BOOL bExist = FALSE;
    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    Q_ASSERT(pDriver);
    MainPressCheck();
    pDriver->setio(IO_OUTPUT, IOOutput, true);
    double dTimeLimit = m_Variants.get_VData(Var_AllSystem_CellExistCheckTime_ID)->toInt();
    CPreciseTime time1;
    time1.StartTime();
    while (time1.GetTime() * 1000 < dTimeLimit) {
        if (pDriver->get_iodata(IO_INPUT, IOInput, true)) {
            bExist = TRUE;
            break;
        }
        MSleep(10);
    }
    if (!bExist) {
        pDriver->setio(IO_OUTPUT, IOOutput, false);
    }
    return bExist;
}

void CMAllsystem::MainPressCheck()
{
    if (IsSimulator())return;

    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    Q_ASSERT(pDriver);
    if (!pDriver->get_iodata(IO_INPUT, IN_MAIN_PRESSURE, true)) {
        MQT_THROW_CODESTR(ALARM_MAIN_PRESS_CHECK, QObject::trUtf8("Main press(%1) Off.")
                          .arg(IN_MAIN_PRESSURE));
    }
}

void CMAllsystem::SafeDoorCheck()
{
    bool bLeft = false;
    bool bRight = false;
    GetSaveDoorCtrl(bLeft, bRight);
    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    Q_ASSERT(pDriver);

    if (!pDriver->get_iodata(IO_INPUT, IN_SAFEDOOR_LEFT, true) && bLeft) {
        MQT_THROW_CODESTR(ALARM_DOOR_LEFT_CHECK, QObject::trUtf8("Left safe door open."));
    }

    if (!pDriver->get_iodata(IO_INPUT, IN_SAFEDOOR_RIGHT, true) && bRight) {
        MQT_THROW_CODESTR(ALARM_DOOR_RIGHT_CHECK, QObject::trUtf8("Right safe door open."));
    }
}

void CMAllsystem::CloseSafeDoor()
{
    try {
        bool bLeft = false;
        bool bRight = false;
        GetSaveDoorCtrl(bLeft, bRight);

        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
        if (bLeft) {
            pMotorDriver->setio(IO_OUTPUT, OUT_LEFTDOOR_UNLOCK, false);
        }
        if (bRight) {
            pMotorDriver->setio(IO_OUTPUT, OUT_RIGHTDOOR_UNLOCK, false);
        }
    } catch (const QString& ex) {
        LOG_ERR(ex.toLocal8Bit().data());
    }
}

void CMAllsystem::OpenSafeDoor()
{
    try {
        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
        pMotorDriver->setio(IO_OUTPUT, OUT_LEFTDOOR_UNLOCK, true);
        pMotorDriver->setio(IO_OUTPUT, OUT_RIGHTDOOR_UNLOCK, true);
    } catch (const QString& ex) {
        LOG_ERR(ex.toLocal8Bit().data());
    }
}

bool CMAllsystem::IsSafeDoorOpened()
{
    try {
        bool bLeft = false;
        bool bRight = false;
        GetSaveDoorCtrl(bLeft, bRight);

        bool bOpend = true;
        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
        if (bLeft) {
            int leftDoor = pMotorDriver->get_iodata(IO_OUTPUT, OUT_LEFTDOOR_UNLOCK, false);
            bOpend &= (bool)leftDoor;
        }
        if (bRight) {
            bOpend &= (bool)pMotorDriver->get_iodata(IO_OUTPUT, OUT_RIGHTDOOR_UNLOCK, false);
        }

        return bOpend;
    } catch (const QString& ex) {
        LOG_ERR(ex.toLocal8Bit().data());
        return true;
    }
}

void CMAllsystem::SetIndicatorLight(Qt::GlobalColor color,
                                    bool bon)
{
    try {
        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER,
                                              CMotorDriver);
        Q_ASSERT(pMotorDriver);
        if (!pMotorDriver->m_bInited) return;
        switch (color) {
        case Qt::red:
            pMotorDriver->setio(IO_OUTPUT, OUT_RED, bon);
            break;
        case Qt::yellow:
            pMotorDriver->setio(IO_OUTPUT, OUT_YELLOW, bon);
            break;
        case Qt::green:
            pMotorDriver->setio(IO_OUTPUT, OUT_GREEN, bon);
            break;
        case Qt::blue:
            pMotorDriver->setio(IO_OUTPUT, OUT_BLUE, bon);
            break;
        default:
            Q_ASSERT(0);
            break;
        }
    } catch (QString& s) {
        MqDebug() << s;
    }
}

//蜂鸣器
void CMAllsystem::SetIndicatorBuzz(bool bon)
{
    try {
        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER,
                                              CMotorDriver);
        Q_ASSERT(pMotorDriver);
        if (!pMotorDriver->m_bInited) return;
        pMotorDriver->setio(IO_OUTPUT, OUT_BUZZ, bon);
    } catch (QString& s) {
        MqDebug() << s;
    }
}

DWORD CMAllsystem::GetIndicatorLight()
{
    CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER,
                                          CMotorDriver);
    Q_ASSERT(pMotorDriver);
    if (!pMotorDriver->m_bInited) return 0;
    DWORD iLight = 0;
    iLight |= pMotorDriver->get_iodata(IO_OUTPUT, OUT_RED, false) << 2;
    iLight |= pMotorDriver->get_iodata(IO_OUTPUT, OUT_YELLOW, false) << 1;
    iLight |= pMotorDriver->get_iodata(IO_OUTPUT, OUT_GREEN, false) << 0;
    iLight |= pMotorDriver->get_iodata(IO_OUTPUT, OUT_BLUE, false) << 3;
    return iLight;
}

//重置所有面的状态
void CMAllsystem::Reset_All_Side(bool bRsetCutLine/*=true*/)
{
    CProductSideDriver* pSideDriver = GET_CARD(SIDE_DRIVER,
                                               CProductSideDriver);
    Q_ASSERT(pSideDriver);

    pSideDriver->ResetSide(SIDE_A, bRsetCutLine);
    pSideDriver->ResetSide(SIDE_B, bRsetCutLine);

    CProcess_Locate* pLocate = GET_PROCESS(
        PROCESS_LOCATE, SM_MAIN,
        CProcess_Locate);
    pLocate->CalcuLocateVector(); //计算定位的Vector

    if (true == bRsetCutLine) {
        CProcess_Level* pLevel = GET_PROCESS(PROCESS_LEVELING, SM_MAIN, CProcess_Level);
        pLevel->m_iCurLineId = -1;
    }
}

//iSideID -1 加载面
void CMAllsystem::ChangeSide(int iSideID)
{
    CProcess_Level* pLevel = GET_PROCESS(PROCESS_LEVELING,
                                         SM_MAIN,
                                         CProcess_Level);
    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    CMWorkTable* pWorkTable = GET_CHDIRECT(WORKTABLE, CMWorkTable);

    m_gSystem.m_iCurLayer = -1;
    m_gSystem.m_iCurLine = -1;
    //CLaserDriver* pLaserDriver=GET_CARD(LASER_DRIVER,CLaserDriver);
    //pLaserDriver->OpenLaserGate(LASERPATH_D_NARROW,false);
    Q_ASSERT(pDriver);
    if (LASER_ON == pDriver->get_iodata(IO_OUTPUT, OUT_LASERGATE, true)) {
        QString sideName = QObject::tr("Load SIDE");
        if (iSideID == SIDE_A)sideName = QObject::tr("SIDE_A");
        if (iSideID == SIDE_B)sideName = QObject::tr("SIDE_B");
        MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAIELD_LASERON, QObject::tr("Can't change channel to %1,because Laser On").arg(sideName));
    }

    if (iSideID == SIDE_A || iSideID == SIDE_B) {
        CProductSide* pSide = GET_CHDIRECT(iSideID, CProductSide);
        pLevel->CalcuPtByCell(iSideID);
        //如果先找了A面，再切换到B面时，如果B面没有找过，则可以将A面的角度偏差直接应用到B面，手动时B面找得更快
        /*if(iSideID == SIDE_B){
            int isize=pSide->m_CutLineVector.size();
            if(isize<=0){
                CProductSide* pSideA=GET_CHDIRECT(SIDE_A,CProductSide);
                CProductSide* pSideB=GET_CHDIRECT(SIDE_A,CProductSide);
                double sideAInitAngle = pSideA->m_Variants.get_VData(Var_ProductSide_InitAngle)->toDouble();
                double sideBInitAngle = pSideB->m_Variants.get_VData(Var_ProductSide_InitAngle)->toDouble();
                if(!INRANGE(pSideA->m_dLevelAngle, sideAInitAngle-0.1, sideAInitAngle+0.1)){
                    pSideB->m_dLevelAngle = sideBInitAngle + pSideA->m_dLevelAngle - sideAInitAngle;
                }
            }
        }*/
        pDriver->absmove(MOTORW, pSide->m_dLevelAngle - 0.01, TRUE);
        pDriver->absmove(MOTORW, pSide->m_dLevelAngle, TRUE);
        SetCutStreet(0, iSideID, CAM2X, false);
        SetCutStreet(0, iSideID, CAM6X, false);
    } else {
        double dLoadPosW = pWorkTable->m_Variants.get_VData(
            Var_MWorkTable_Load_W_ID)->toDouble();
        pDriver->absmove(MOTORW, dLoadPosW, TRUE);
    }

    if (iSideID == SIDE_A || iSideID == SIDE_B) {
        m_gSystem.m_iCurSideID = iSideID;
    } else {
        m_gSystem.m_iCurSideID = -1;
    }
}
QString CMAllsystem::makeModelPath(QString& fileName, int32_t iSideid, int32_t iCamid)
{
    Q_ASSERT(iCamid == CAM2X || iCamid == CAM6X);
    QString str = "A_";
    if (iSideid == SIDE_B) {
        str = "B_";
    }
    QString strCamName = "CAM6X";
    if (iCamid == CAM2X) {
        strCamName = "CAM2X";
    }
    QString s = fileName;

    if (m_iMatchType == M_MATCHNCC) {
        return CMakePath::make_pattern_path(s.left(s.length() - 4)) +
            "/" + str + strCamName + ".mnm";
    } else if (m_iMatchType == M_MATCHSHAPE) {
        return CMakePath::make_pattern_path(s.left(s.length() - 4)) +
            "/" + str + strCamName + ".msm";
    } else {
        Q_ASSERT(0);
    }
    return QString();
}

//设置切割道宽度参数
void CMAllsystem::SetCutStreet(CImageContainer* pContainer, int iSideID, int iCamID,
                               bool bSetBoth)
{
    if (iSideID != SIDE_A && iSideID != SIDE_B) {
        iSideID = SIDE_A;
    }
    int iOtherSideID = SIDE_A;
    if (iOtherSideID == iSideID) {
        iOtherSideID = SIDE_B;
    }

    CCam* pCam = GET_CHDIRECT(iCamID, CCam);
    CProductSide* pSide = GET_CHDIRECT(iSideID, CProductSide);
    Q_ASSERT(pSide);
    pCam->m_iHairLenH = pSide->m_Variants.
        get_VData(Var_ProductSide_CutStreet)->toInt();

    CProductSide* pOtherSide = GET_CHDIRECT(iOtherSideID, CProductSide);
    pCam->m_iHairLenV = pOtherSide->m_Variants.
        get_VData(Var_ProductSide_CutStreet)->toInt();

    pCam->SetHairLineToImageContainer(pContainer, true);
    if (bSetBoth) {
        int iSideOtherID = iSideID == SIDE_A ? SIDE_B : SIDE_A;
        CProductSide* pSideOther = GET_CHDIRECT(iSideOtherID, CProductSide);
        Q_ASSERT(pSideOther);
        pCam->m_iHairLenV = pSideOther->m_Variants.
            get_VData(Var_ProductSide_CutStreet)->toInt();
        pCam->SetHairLineToImageContainer(pContainer, false);
    }
}

bool CMAllsystem::IsAllSMStopped()
{
    bool bStoped = true;
    {

        bStoped &= IsSMStopped(SM_TRANS);
        if (false == bStoped)
            return bStoped;
    }

    {
        bStoped &= IsSMStopped(SM_MAIN);
        if (false == bStoped)
            return bStoped;
    }
    {
        bStoped &= IsSMStopped(SM_COAT);
        if (false == bStoped)
            return bStoped;
    }
    {
        bStoped &= IsSMStopped(SM_CLEAN);
        if (false == bStoped)
            return bStoped;
    }
    {
        bStoped &= IsSMStopped(SM_WTLoad);
        if (false == bStoped)
            return bStoped;
    }
    {
        bStoped &= IsSMStopped(SM_WTUnload);
        if (false == bStoped)
            return bStoped;
    }

    //bool b= m_gSystem.FindSM(SM_TRANS)->IsStop()&&
    //        m_gSystem.FindSM(SM_MAIN)->IsStop()&&
    //        m_gSystem.FindSM(SM_COAT)->IsStop()&&
    //        m_gSystem.FindSM(SM_CLEAN)->IsStop();

    m_bAllSMStoped = bStoped;
    return bStoped;
}

bool CMAllsystem::IsAllSMIdle()
{
    return m_gSystem.FindSM(SM_TRANS)->IsIdle() &&
        m_gSystem.FindSM(SM_MAIN)->IsIdle() &&
        m_gSystem.FindSM(SM_COAT)->IsIdle() &&
        m_gSystem.FindSM(SM_CLEAN)->IsIdle();

}

bool CMAllsystem::IsSMStopped(int smID)
{
    return m_gSystem.FindSM(smID)->IsStop();
    //QMutexLocker l(&m_gSystem.FindSM(smID)->m_SMMutex);
    /*return m_gSystem.FindSM(smID)->m_pCurState->m_iStateType == VS_Thread::State_Idle &&
        m_gSystem.FindSM(smID)->m_pHistoryState_Auto == 0 &&
        m_gSystem.FindSM(smID)->m_pHistoryState_Semi == 0;*/
}

bool CMAllsystem::IsSMIdle(int smID)
{
    return m_gSystem.FindSM(smID)->IsManual();
    //return m_gSystem.FindSM(smID)->m_pCurState->m_iStateType == VS_Thread::State_Idle;
}

bool CMAllsystem::IsSMAutoPaused(int smID)
{
    //自动暂停状态
    QMutexLocker lckTrans(&m_gSystem.FindSM(smID)->m_SMMutex);
    return m_gSystem.FindSM(smID)->m_pHistoryState_Auto
        && m_gSystem.FindSM(smID)->m_pCurState->m_iStateType != VS_Thread::State_Work_Auto;
}

bool CMAllsystem::IsSMAutoRun(int smID)
{
    return m_gSystem.FindSM(smID)->IsAutoRun();
    /*QMutexLocker lckTrans(&m_gSystem.FindSM(smID)->m_SMMutex);
    return m_gSystem.FindSM(smID)->m_pCurState->m_iStateType == VS_Thread::State_Work_Auto;*/
}

bool CMAllsystem::IsSMAutoMode(int smID)
{
    //TODO:

    /*QMutexLocker lckTrans(&m_gSystem.FindSM(smID)->m_SMMutex);
    VSMT_Base* pSM = (VSMT_Base*)FindSM(smID);
    if (pSM->m_pHistoryState_Auto
        || pSM->m_pCurState->m_iStateType == VS_Thread::State_Work_Auto
        || pSM->m_pCurState->m_iStateType == VS_Thread::State_Wait) {
        return true;
    }*/

    return false;
}

bool CMAllsystem::StopSemi(int iSMID)
{
    VSMT_Base* pSM = (VSMT_Base*)FindSM(iSMID);
    if (m_gSystem.FindSM(iSMID)->IsStop())
        return true;

    pSM->pushfront_Msg(VarMsg_StopSemi_ID,
                       QObject::trUtf8("Stop Semi Sig"));

    pSM->pushfront_Msg(VarMsg_Pause_ID, QObject::trUtf8("Pause Sig"));

    return true;
}

void CMAllsystem::LogInfo(const QString& msg, const char* pFile, int line)
{
    //m_recordLog.LogInfo(msg);

	__LOGINSTANCE__.Log(lp::kInfo, msg.toLocal8Bit().data(), pFile, line, "RecordLog");
}

void CMAllsystem::LogError(const QString& msg)
{
    m_recordLog.LogError(msg);
}

void CMAllsystem::AddProductInfo(const QString& waferId, const QString& info, bool toLog/*=true*/)
{
    m_productLog.AddLog(GetLotId(), waferId.toStdString(), info);
    if (toLog) {
        QString data = QString("Lot %1 Wafer:%2 %3").arg(GetLotId().c_str()).arg(waferId).arg(info);
        m_recordLog.ProductLog(data);
    }
}

void CMAllsystem::AddProductInfo(int processId, const QString& info, bool toLog/*=true*/)
{
    std::string waferId;
    switch (processId) {
    case PROCESS_TRANS:
        waferId = GetTransWaferId();
        break;
    case PROCESS_CUT:
    case PROCESS_LEVELING:
    case PROCESS_LOCATE:
        waferId = GetMainWaferId();
        break;
    case PROCESS_COAT:
        waferId = GetCoatWaferId();
        break;
    case PROCESS_CLEAN:
        waferId = GetCleanWaferId();
        break;
    default:
        waferId = GetMainWaferId();
        break;
    }

    AddProductInfo(waferId.c_str(), info, toLog);
}

void CMAllsystem::AddProductInfo(CASSSLOT* pSlot, const QString& info, bool toLog/*=true*/)
{
    if (pSlot == nullptr) {
        LOG_ERR(fmt::format("SLOT is nullptr {}", info.toLocal8Bit().data()));
        return;
    }

    AddProductInfo(pSlot->WaferID, info, toLog);
}

void CMAllsystem::OnPrepareHome(int iMotorID)
{

    CProcess_Trans* pTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS,
                                         CProcess_Trans);
    Q_ASSERT(pTrans);
    CProcess_Coat* pCoat = GET_PROCESS(PROCESS_COAT, SM_COAT,
                                       CProcess_Coat);
    Q_ASSERT(pCoat);
    CProcess_Clean* pClean = GET_PROCESS(PROCESS_CLEAN, SM_CLEAN,
                                         CProcess_Clean);

    //检查ACS初始化是否正常

    Q_ASSERT(pClean);

    if (!IsAcsInited()) {
        CMotor* pMotor = GET_CHDIRECT(iMotorID, CMotor);
        Q_ASSERT(pMotor);
        MQT_THROW_CODESTR(ALARM_ACS_INIT_ERROR, QObject::tr("Motor %1 can't init,because ACS not inited").arg(pMotor->m_sName));
    }

    //上下料回原完成后才能回原其他轴
    if (iMotorID == MOTORX || iMotorID == MOTORY || iMotorID == MOTORW
        || iMotorID == MOTORB1_LOCK || iMotorID == MOTORB2_RAIL
        || iMotorID == MOTORA_CLAW) {
        CMotor* pMotor = GET_CHDIRECT(iMotorID, CMotor);
        Q_ASSERT(pMotor);

        //检查轴有没有回原点
        CMotor* pMotorH1 = GET_CHDIRECT(MOTORH1_UPDOWN, CMotor);
        CMotor* pMotorH2 = GET_CHDIRECT(MOTORH2_TRANS, CMotor);
        CMotor* pMotorJ1 = GET_CHDIRECT(MOTORJ1_UPDOWN, CMotor);
        CMotor* pMotorJ2 = GET_CHDIRECT(MOTORJ2_TRANS, CMotor);

        //轴是否已经回原
        if (!pMotorH1->m_Variants.get_VData(Var_Motor_Hashome_ID)->toBool()) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAIELD_OTHER_AXIS_FIRST, QObject::tr("Motor %1 can't init,because motor %2 not inited").
                              arg(pMotor->m_sName).arg(pMotorH1->m_sName));
        }
        if (!pMotorH2->m_Variants.get_VData(Var_Motor_Hashome_ID)->toBool()) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAIELD_OTHER_AXIS_FIRST, QObject::tr("Motor %1 can't init,because motor %2 not inited").
                              arg(pMotor->m_sName).arg(pMotorH2->m_sName));
        }

        if (!pMotorJ1->m_Variants.get_VData(Var_Motor_Hashome_ID)->toBool()) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAIELD_OTHER_AXIS_FIRST, QObject::tr("Motor %1 can't init,because motor %2 not inited").
                              arg(pMotor->m_sName).arg(pMotorJ1->m_sName));
        }

        if (!pMotorJ2->m_Variants.get_VData(Var_Motor_Hashome_ID)->toBool()) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAIELD_OTHER_AXIS_FIRST, QObject::tr("Motor %1 can't init,because motor %2 not inited").
                              arg(pMotor->m_sName).arg(pMotorJ2->m_sName));
        }

        //是否在安全位置
        if (false == pTrans->IsMotorLoadVAtWait()) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAILED_OTHER_AXIS_NOTSAFE, QObject::tr("Motor %1 can't init,because motor %2 not in inited pos").
                              arg(pMotor->m_sName).arg(pMotorH1->m_sName));
        }

        if (false == pTrans->IsMotorLoadHAtWait()) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAILED_OTHER_AXIS_NOTSAFE, QObject::tr("Motor %1 can't init,because motor %2 not in inited pos").
                              arg(pMotor->m_sName).arg(pMotorH2->m_sName));
        }

        if (false == pTrans->IsMotorUnloadVAtWait()) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAILED_OTHER_AXIS_NOTSAFE, QObject::tr("Motor %1 can't init,because motor %2 not in inited pos").
                              arg(pMotor->m_sName).arg(pMotorJ1->m_sName));
        }

        if (false == pTrans->IsMotorUnloadHAtWait()) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAILED_OTHER_AXIS_NOTSAFE, QObject::tr("Motor %1 can't init,because motor %2 not in inited pos").
                              arg(pMotor->m_sName).arg(pMotorJ2->m_sName));
        }
        /*pTrans->MoveLoadInitPos();
        pTrans->MoveUnLoadInitPos();*/
    }

    if (iMotorID == MOTORA_CLAW) {
        CMotor* pMotor = GET_CHDIRECT(iMotorID, CMotor);
        Q_ASSERT(pMotor);
        CMotor* pMotorD = GET_CHDIRECT(MOTORD_TRANS, CMotor);
        if (!pMotorD->m_Variants.get_VData(Var_Motor_Hashome_ID)->toBool()) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAIELD_OTHER_AXIS_FIRST, QObject::tr("Motor %1 can't init,because motor %2 not inited").
                              arg(pMotor->m_sName).arg(pMotorD->m_sName));
        }

        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
        Q_ASSERT(pMotorDriver);
    }

    if (iMotorID == MOTORX || iMotorID == MOTORY
        || iMotorID == MOTORZ) {
        //这几个轴执行时检查激光器是否打开
        CLaserDriver* pLaserDriver = GET_CARD(LASER_DRIVER, CLaserDriver);
        CMotor* pMotor = GET_CHDIRECT(iMotorID, CMotor);
        Q_ASSERT(pMotor);

        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
        Q_ASSERT(pMotorDriver);
        if (LASER_ON == pMotorDriver->get_iodata(IO_OUTPUT, OUT_LASERGATE, true)) {
            MQT_THROW_CODESTR(ALARM_MOTION_INIT_FAIELD_LASERON, QObject::tr("Motor %1 can't init,because Laser On").arg(pMotor->m_sName));
        }
        //pLaserDriver->OpenLaserGate(0,false);
    }
    switch (iMotorID) {
    case MOTORX:
    case MOTORY:
    case MOTORW:
        CellExist(OUT_WT_WAFER_VACUUM, IN_WT_WAFER_VACUUM);
        break;
    case MOTORE_COAT_SPINDLE:
        CellExist(OUT_COAT_VACUUM, IN_COAT_VACUUM);
    case MOTORE1_COAT_CLEAN_ARM:
    case MOTORE2_COAT_COAT_ARM:
    case MOTORE3_COAT_BUMP:
    {
        switch (iMotorID) {
        case MOTORE2_COAT_COAT_ARM:
        case MOTORE3_COAT_BUMP:
            pCoat->CoatArmUp(true);
            if (MOTORE3_COAT_BUMP == iMotorID) {
                pCoat->MoveCoatWaitPos();
            }
            break;
        }
        break;
    }
    case MOTORF_CLEAN_SPINDLE:
        CellExist(OUT_CLEAN_VACUUM, IN_CLEAN_VACUUM);
    case MOTORF1_CLEAN_ARM:
        break;
    case MOTORB1_LOCK:
        pTrans->AssertRailNearHasWafer(false, QObject::tr("Prepare home"));
        break;
    case MOTORB2_RAIL:
        pTrans->AssertRailFarHasWafer(false, QObject::tr("Prepare home"));
        break;
    case MOTORA_CLAW:
    case MOTORC_CASS:
        break;
    case MOTORD_TRANS:
    {
        CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
        bool_t bCassFront = pMotorDriver->get_iodata(IO_INPUT, IN_WaferOutCass_Front_Cassete, true);
        CMotor* pMotor = GET_CHDIRECT(iMotorID, CMotor);
        if (bCassFront) {
            MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                              QObject::trUtf8("%1 can not initial because Claw near Casste")
                              .arg(pMotor->m_sName));
        }
        break;
    }
    }
}

void CMAllsystem::OnAfterHome(int iMotorID)
{
    //移动到回原初始位
    if (!m_bMoveInitPos) return;
    CProcess_Trans* pTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS,
                                         CProcess_Trans);
    pTrans;
    Q_ASSERT(pTrans);
    CProcess_Coat* pCoat = GET_PROCESS(PROCESS_COAT, SM_COAT,
                                       CProcess_Coat);
    Q_ASSERT(pCoat);
    CProcess_Clean* pClean = GET_PROCESS(PROCESS_CLEAN, SM_CLEAN,
                                         CProcess_Clean);
    Q_ASSERT(pClean);
    CProcess_Scan* pCass = GET_PROCESS(PROCESS_SCAN, SM_TRANS,
                                       CProcess_Scan);
    Q_ASSERT(pCass);

    switch (iMotorID) {
    case MOTORA_CLAW:
    {
        pTrans->MoveHGrabWait();
        break;
    }
    case MOTORC_CASS:
    {
        pCass->CassUp(CASSETTE);
        break;
    }

    case MOTORE_COAT_SPINDLE:
    {
        pCoat->MoveSpindleInitPos(false);
        //        pCoat->SpindleUp(true);
        break;
    }
    case MOTORE1_COAT_CLEAN_ARM:
    {
        pCoat->MoveCleanWaitPos();
        break;
    }
    case MOTORE2_COAT_COAT_ARM:
    {
        pCoat->CoatArmUp(true);
        pCoat->MoveCoatWaitPos();
        pCoat->CoatArmUp(false);
        break;
    }
    case MOTORE3_COAT_BUMP:
    {
        pCoat->CoatArmUp(true);
        pCoat->MoveCoatWaitPos();
        pCoat->CoatArmUp(false);
        break;
    }
    case MOTORF_CLEAN_SPINDLE:
    {
        pClean->MoveSpindleInitPos(false);
        //        pClean->SpindleUp(true);
        break;
    }
    case MOTORF1_CLEAN_ARM:
    {
        pClean->MoveCleanWaitPos();
        break;
    }
    case MOTORH2_TRANS:
    {
        pTrans->MoveHLoadWait(true);
        break;
    }
    case MOTORJ2_TRANS:
    {
        pTrans->MoveHUnloadWait();
        break;
    }
        
    }
}

void CMAllsystem::OnLimitCheck(int32_t motorId, double targetPos)
{
    //通过位置检查限位
}

//轴是否可运动控制
void CMAllsystem::OnIsMotorMoveAvailable(int motorid, bool checklimit/*=false*/, int idirect/*=1*/,
                                         double dTargetPos/*=0*/, bool bIsHoming/*=false*/)
{
    if (IsSimulator())return;

    CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    try {
        //检查限位信号和回原状态
        CheckLimitAndHoming(motorid, checklimit, idirect, bIsHoming);
        QString sMotorName = m_mapNameList[motorid];
#pragma region 夹抓
        if (motorid == MOTORA_CLAW) {
            //夹抓移动前保证上下料在安全位置
            //根据目标位置控制
            CMotorDriver::MotorDestArea eAreaCur = pMotorDriver->get_motor_cur_area_type(motorid);
            CMotorDriver::MotorDestArea eAreaTarget = pMotorDriver->get_motor_area_type(motorid, dTargetPos);
            bool bCheckLoad = false;
            bool bCheckUnload = false;
            //如果目标在同一个区域，或从安全区域前往目标区域，则只需要检查一个区域，
            //否则需要检查上料下料两个区域
            if (eAreaCur == CMotorDriver::CENTER_AREA || eAreaCur == eAreaTarget) {
                if (eAreaTarget == CMotorDriver::PAS_AREA) {
                    bCheckLoad = true;
                }
                if (eAreaTarget == CMotorDriver::NAG_AREA) {
                    bCheckUnload = true;
                }
            } else if (eAreaTarget == CMotorDriver::CENTER_AREA) {
                //允许前往安全区域
                if (eAreaCur == CMotorDriver::PAS_AREA) {
                    bCheckLoad = true;
                }
                if (eAreaCur == CMotorDriver::NAG_AREA) {
                    bCheckUnload = true;
                }
            } else {
                bCheckLoad = true;
                bCheckUnload = true;
            }

            if (bCheckLoad) {
                CMotorDriver::MotorDestArea eAreaLoad = pMotorDriver->get_motor_cur_area_type(MOTORH2_TRANS);

                /* CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
                 if (true != transProcess->IsMotorLoadHAtWait()) {*/
                if (eAreaLoad == CMotorDriver::PAS_AREA)
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not move because load arm on right")
                                      .arg(sMotorName));
            }

            if (bCheckUnload) {
                CMotorDriver::MotorDestArea eAreaUnload = pMotorDriver->get_motor_cur_area_type(MOTORJ2_TRANS);
                //if (true != transProcess->IsMotorUnloadHAtWait()) {
                if (eAreaUnload == CMotorDriver::PAS_AREA)
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not move because unload arm on right")
                                      .arg(sMotorName));
            }

            //D轴在安全位置才能移动夹抓，向下为正
            CMotorDriver::MotorDestArea eAreatypeD = pMotorDriver->get_motor_cur_area_type(MOTORD_TRANS);
            if (eAreatypeD == CMotorDriver::NAG_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because %2 is down")
                                  .arg(sMotorName)
                                  .arg(m_mapNameList[MOTORD_TRANS]));
            }

            //检测夹爪防撞
            int clawCheck = pMotorDriver->get_iodata(IO_INPUT, IN_CLAW_Collision_Detection_Push, true);
            if (clawCheck == 0) {
                MQT_THROW_CODESTR(ALARM_TRANS_SAFE_PROTECT, QObject::trUtf8("Glaw strike sensor triggerd"));
            }

            //轨道夹紧为正
            //夹抓移动时，检查轨道是否打开
            CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            double dRailNearPos = pMotorDriver->get_posdata(MOTORB1_LOCK, true);
            if (transProcess->IsPosBigger(dRailNearPos-0.1, Var_Process_RailNear_PosClose))
            {
                MQT_THROW_CODESTR(ALARM_TRANS_SAFE_PROTECT, QObject::trUtf8("%1 Can't move,because %2 is clamped")
                                  .arg(sMotorName)
                                  .arg(m_mapNameList[MOTORB1_LOCK]));
            }

            //夹抓移动时，检查保护罩是否打开
            double dRailFarPos = pMotorDriver->get_posdata(MOTORB2_RAIL, true);
            if (transProcess->IsPosBigger(dRailFarPos - 0.1, Var_Process_RailFar_PosClose))
            {
                MQT_THROW_CODESTR(ALARM_TRANS_SAFE_PROTECT, QObject::trUtf8("%1 can't move,because %2 is clamped")
                                  .arg(sMotorName)
                                  .arg(m_mapNameList[MOTORB2_RAIL]));
            }
        }
#pragma endregion 夹抓
#pragma region TransD
        if (motorid == MOTORD_TRANS) {
            //升降轴不能超限
            CMotorDriver::MotorDestArea eAreatypeA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);

            //如果往负限位方向放，需要检查轨道和保护罩
            CMotorDriver::MotorDestArea eAreaTarget = pMotorDriver->get_motor_area_type(motorid, dTargetPos);
            //if (eAreatypeA == CMotorDriver::NAG_AREA) {
            //    CProcess_Trans* processTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            //    if(processTrans->IsPosLess(dTargetPos, Var_Process_Trans_PosRailNear) && "未打开轨道"）
            //    //如果不在清洗或涂覆位置，则不能往下降
            //    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
            //                      QObject::trUtf8("open RailNear Max curtain before transfer down")
            //                      .arg(sMotorName));
            //}
            if (eAreatypeA == CMotorDriver::NAG_AREA) {
                //夹抓在清洗台时，必须打开保护罩
                if (eAreaTarget == CMotorDriver::NAG_AREA) {
                    bool_t bCleanCutainOpened = pMotorDriver->get_iodata(IO_INPUT, IN_CLEAN_CURTAIN_OPENED, true);

                    if (!bCleanCutainOpened) {
                        MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                          QObject::trUtf8(" %1 can't move, open clean curtain before transfer down")
                                          .arg(sMotorName));
                    }

                    //正在关闭时，不能往清洗腔降
                    bool_t bCleanCutainClosing = !pMotorDriver->get_iodata(IO_OUTPUT, OUT_CLEAN_CURTAIN_OPENED, true);
                    if (bCleanCutainClosing) {
                        MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                          QObject::trUtf8("%1 can't move, clean curtain is closing before transfer down")
                                          .arg(sMotorName));
                    }


                    //检查清洗轨道打开
                    /*CProcess_Trans* processTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
                    processTrans->IsPosLess(dTargetPos, Var_Process_Trans_PosRailNearReady);*/
                    CMotorDriver::MotorDestArea eAreatypeB = pMotorDriver->get_motor_cur_area_type(MOTORB1_LOCK);
                    if (eAreatypeB != CMotorDriver::NAG_AREA) {
                        MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                          QObject::trUtf8("open rail(near) before transfer down"));
                    }

                    //检查摆臂是否摆过来了
                    CMotorDriver::MotorDestArea eAreaF1 =
                        pMotorDriver->get_motor_cur_area_type(MOTORF1_CLEAN_ARM);
                    if (eAreaF1 == CMotorDriver::PAS_AREA)
                    {
                        MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                          QObject::trUtf8("%1 can not move to neg area because %2  not in safe pos")
                                          .arg(sMotorName).arg(m_mapNameList[MOTORF1_CLEAN_ARM]));
                    }
                }
            }
            //如果往负限位方向放，则需要打开盖子
            if (eAreatypeA == CMotorDriver::PAS_AREA) {
                //在涂覆台时，必须打开涂覆保护罩
                if (eAreaTarget == CMotorDriver::NAG_AREA) {
                    bool_t bCoatCutainOpened = pMotorDriver->get_iodata(IO_INPUT, IN_COAT_CURTAIN_OPENED, true);
                    if (!bCoatCutainOpened) {
                        MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                          QObject::trUtf8("%1 can't move, open coat curtain before transfer down")
                                          .arg(sMotorName));
                    }

                    //正在关闭时，不能往涂覆腔降
                    bool_t bCoatCutainClosing = !pMotorDriver->get_iodata(IO_OUTPUT, OUT_COAT_CURTAIN_OPENED, true);
                    if (bCoatCutainClosing) {
                        MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                          QObject::trUtf8("%1 can't move, coat curtain is closing before transfer down")
                                          .arg(sMotorName));
                    }

                    //检查涂覆轨道打开
                    CMotorDriver::MotorDestArea eAreatypeB = pMotorDriver->get_motor_cur_area_type(MOTORB2_RAIL);
                    /*CProcess_Trans* processTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
                    processTrans->IsPosLess(dTargetPos, Var_Process_Trans_PosRailNearReady);*/
                    if (eAreatypeB != CMotorDriver::NAG_AREA) {
                        MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                          QObject::trUtf8("open rail(far) before transfer down"));
                    }

                    //检查摆臂是否摆过来了
                    CMotorDriver::MotorDestArea eAreaE1 =
                        pMotorDriver->get_motor_cur_area_type(MOTORE1_COAT_CLEAN_ARM);
                    if (eAreaE1 == CMotorDriver::PAS_AREA)
                    {
                        MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                          QObject::trUtf8("%1 can not move to neg area because %2  not in safe pos")
                                          .arg(sMotorName).arg(m_mapNameList[MOTORE1_COAT_CLEAN_ARM]));
                    }

                    CMotorDriver::MotorDestArea eAreaE2 =
                        pMotorDriver->get_motor_cur_area_type(MOTORE2_COAT_COAT_ARM);
                    if (eAreaE2 == CMotorDriver::PAS_AREA)
                    {
                        MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                          QObject::trUtf8("%1 can not move to neg area because %2  not in safe pos")
                                          .arg(sMotorName).arg(m_mapNameList[MOTORE2_COAT_COAT_ARM]));
                    }
                }
            }

            double dACurPos = pMotorDriver->get_posdata(MOTORA_CLAW, true);
            CProcess_Trans* processTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            if (processTrans->IsPosLess(dACurPos, Var_Process_Claw_PosCassOutReady)) {
                MQT_THROW_STR(QObject::trUtf8("%1 can not move because %2 is in casste.")
                              .arg(sMotorName)
                              .arg(m_mapNameList[MOTORA_CLAW]));
            }

            //规整台靠近料盒位置检测到有料不能移动
            //或者在料盒内
            //或者出料传感器有信号，D轴都不能升降
            bool_t bLockHasWafer = pMotorDriver->get_iodata(IO_INPUT, IN_Rail_NearCass_HasWafer, true);
            bool_t bCassFront = pMotorDriver->get_iodata(IO_INPUT, IN_WaferOutCass_Front_Cassete, true);
            /*CProcess_Trans* processTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            double dACurPos = pMotorDriver->get_posdata(MOTORA_CLAW, true);*/
            if ((bLockHasWafer || bCassFront) && processTrans->IsPosLess(dACurPos, Var_Process_Claw_PosCassOutReady)) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move up because %2 in not safe area")
                                  .arg(sMotorName).arg(m_mapNameList[MOTORA_CLAW]));
            }

            //如果夹爪不在涂敷或清洗位置，则不能往负向区域降
            if (eAreaTarget == CMotorDriver::NAG_AREA) {
                if (!processTrans->IsPosInRange(dACurPos, Var_Process_Claw_PosHCoat, 5)
                    && !processTrans->IsPosInRange(dACurPos, Var_Process_Claw_PosHClean, 5)) {
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not move to neg area because %2  not in Coat or Clean pos")
                                      .arg(sMotorName).arg(m_mapNameList[MOTORA_CLAW]));
                }
            }

            //TODO:如果轨道上有晶圆，不能往下压坏晶圆，理论不会发生，因为有轨道进行限制
            //检查摆臂是否摆过来了
        }
#pragma endregion TransD

#pragma region 上料
        if (motorid == MOTORH1_UPDOWN) {
            //在中间区域时不能降下
            CMotorDriver::MotorDestArea eAreaH2Trans = pMotorDriver->get_motor_cur_area_type(MOTORH2_TRANS);
            if (eAreaH2Trans == CMotorDriver::CENTER_AREA && idirect < 0) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not down because area not safe")
                                  .arg(sMotorName));
            }
            //在涂覆台时，不能往低于放片的位置移动
            CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            if (eAreaH2Trans == CMotorDriver::PAS_AREA && transProcess->IsPosLess(dTargetPos, Var_Process_Load_PosVRail)) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not down because area not safe")
                                  .arg(sMotorName));
            }
            //在切割平台时，不能往低于放片的位置移动
            if (eAreaH2Trans == CMotorDriver::NAG_AREA && transProcess->IsPosLess(dTargetPos, Var_Process_Load_PosVWT)) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not down because area not safe")
                                  .arg(sMotorName));
            }
        }
        if (motorid == MOTORH2_TRANS) {
            CMotorDriver::MotorDestArea eAreaH1 = pMotorDriver->get_motor_cur_area_type(MOTORH1_UPDOWN);
            if (eAreaH1 != CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because unload arm is down")
                                  .arg(sMotorName));
            }

            CMotorDriver::MotorDestArea eAreaA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            CMotorDriver::MotorDestArea eAreaTarget = pMotorDriver->get_motor_area_type(MOTORH2_TRANS, dTargetPos);
            if (eAreaA == CMotorDriver::PAS_AREA && eAreaTarget == CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move to coat area because trans arm on coat area.")
                                  .arg(sMotorName));
            }
        }
#pragma endregion 上料

#pragma region 下料
        if (motorid == MOTORJ1_UPDOWN) {
            CMotorDriver::MotorDestArea eAreaJ2Trans = pMotorDriver->get_motor_cur_area_type(MOTORJ2_TRANS);
            if (eAreaJ2Trans == CMotorDriver::CENTER_AREA && idirect < 0) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not down because area not safe")
                                  .arg(sMotorName));
            }

            //在清洗台时，不能往比放片位置低的地方放
            CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            if (eAreaJ2Trans == CMotorDriver::PAS_AREA && transProcess->IsPosLess(dTargetPos, Var_Process_Unload_PosVRail)) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not down because area not safe")
                                  .arg(sMotorName));
            }
            //在切割平台时，不能往低于放片的位置移动
            if (eAreaJ2Trans == CMotorDriver::NAG_AREA && transProcess->IsPosLess(dTargetPos, Var_Process_Unload_PosVWT)) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not down because area not safe")
                                  .arg(sMotorName));
            }
        }
        if (motorid == MOTORJ2_TRANS) {
            CMotorDriver::MotorDestArea eAreaJ1 = pMotorDriver->get_motor_cur_area_type(MOTORJ1_UPDOWN);
            if (eAreaJ1 != CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because unload arm is down")
                                  .arg(sMotorName));
            }

            CMotorDriver::MotorDestArea eAreaA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            CMotorDriver::MotorDestArea eAreaTarget = pMotorDriver->get_motor_area_type(MOTORJ2_TRANS, dTargetPos);
            if (eAreaA == CMotorDriver::NAG_AREA && eAreaTarget == CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move to clean area because trans arm on clean area.")
                                  .arg(sMotorName));
            }

        }
#pragma endregion 下料

#pragma region XYW检查
        if (motorid == MOTORX || motorid == MOTORY || motorid == MOTORW) {
            //上下料Z向不在安全位置，X，Y，W轴不能动
            CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);


            CMotorDriver::MotorDestArea eAreaType = pMotorDriver->get_motor_cur_area_type(MOTORH1_UPDOWN);
            CMotorDriver::MotorDestArea eAreaTypeTrans = pMotorDriver->get_motor_cur_area_type(MOTORH2_TRANS);
            //上料轴在平台区域，且不在正向安全区域
            //if (true != transProcess->IsMotorLoadVAtWait()) {
            if (eAreaTypeTrans != CMotorDriver::PAS_AREA
                && eAreaType != CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because load arm down")
                                  .arg(sMotorName));
            }

            //下料轴在平台区域，且不在正向安全区域
            eAreaType = pMotorDriver->get_motor_cur_area_type(MOTORJ1_UPDOWN);
            eAreaTypeTrans = pMotorDriver->get_motor_cur_area_type(MOTORJ2_TRANS);
            //if (true != transProcess->IsMotorUnloadVAtWait()) {
            if (eAreaTypeTrans != CMotorDriver::PAS_AREA
                && eAreaType != CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because unload arm down")
                                  .arg(sMotorName));
            }

            //Z轴在下方时不能移动平台,向上为正
            CMotorDriver::MotorDestArea eAreatypeZ = pMotorDriver->get_motor_cur_area_type(MOTORZ);
            if (eAreatypeZ == CMotorDriver::NAG_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT, QObject::trUtf8("%1 can not move because motor z down")
                              .arg(sMotorName));
            }

            //工作台底坐安全检查
            if(!pMotorDriver->get_iodata(IO_INPUT, IN_WT_Worktable_Install_Check, true))
            {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because worktable base not vaccum check failed")
                                  .arg(sMotorName));
            }
        }
#pragma endregion XYW

#pragma region 轨道
        if (motorid == MOTORB1_LOCK) {
            //上下料与夹紧轴的安全检查
            //在右边时，同时降下来了，不能操作
            /*CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            if(!transProcess->IsMotorLoadHAtWait()
                && !transProcess->IsMotorLoadHAtWait())
            {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT, QObject::trUtf8("%1 can not move because load arm down")
                    .arg(_strCompName[motorid]));
            }*/
            //上料轴在夹紧轴下方时能运动轴
           /* CMotorDriver::MotorDestArea eAreatypeH1 =
                pMotorDriver->get_motor_cur_area_type(MOTORH1_UPDOWN);
            if (eAreatypeH1 == CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT, QObject::trUtf8("%1 can not move because load arm down")
                                  .arg(sMotorName));
            }*/

            //夹紧轴在下方时，不能运动夹紧轴
            //CMotorDriver::MotorDestArea eAreaTarget = pMotorDriver->get_motor_area_type(MOTORB1_LOCK, dTargetPos);
            //TODO:控制D的区域，保证只要不是在放料的操作时，都可以打开关闭
            CMotorDriver::MotorDestArea eAreatypeD = pMotorDriver->get_motor_cur_area_type(MOTORD_TRANS);
            CMotorDriver::MotorDestArea eAreatypeA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            CProcess_Trans* pTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            if (idirect > 0 && eAreatypeD != CMotorDriver::PAS_AREA
                && eAreatypeA == CMotorDriver::NAG_AREA) {
                //晶圆在轨道时，可以加紧操作
                //if (pTrans->IsPosUpper(dTargetPos, Var_Process_RailNear_PosClose) && eAreatypeD == CMotorDriver::CENTER_AREA) {
                //	//D轴在

                //}
                //else 
                if (eAreatypeD == CMotorDriver::NAG_AREA) {
                    //在下面清洗桶时，轨道不能关闭了
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not move because %2 is down")
                                      .arg(sMotorName)
                                      .arg(m_mapNameList[MOTORD_TRANS]));
                } else if (eAreatypeD == CMotorDriver::CENTER_AREA 
                           && pTrans->IsPosBigger(dTargetPos, Var_Process_RailNear_PosClose)) {
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not move because %2 is in Rail Range")
                                      .arg(sMotorName)
                                      .arg(m_mapNameList[MOTORD_TRANS]));
                }
            }
            //如果上面有晶圆，则不能打开到最大位置，不然晶圆就掉了
            // 不能往Close更小了夹紧，不然会把晶圆夹坏
            //夹紧为正
            if (pMotorDriver->get_iodata(IO_INPUT, IN_Rail_NearCass_HasWafer, true) == 1
                || pMotorDriver->get_iodata(IO_INPUT, IN_Rail_NearLoc_HasWafer, true) == 1) {
                //CProcess_Trans* pTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
                if (pTrans->IsPosLess(dTargetPos, Var_Process_RailNear_PosOpen)) {
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not open because %1 has wafer")
                                      .arg(sMotorName));
                }

                if (pTrans->IsPosUpper(dTargetPos, Var_Process_RailNear_PosClose)) {
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not close lower because %1 has wafer")
                                      .arg(sMotorName));
                }

            }

            //这个保护是多余的，因为上面的夹紧保护已经保证了，所以这个保护不需要了
            /*bool_t bCassFront = pMotorDriver->get_iodata(IO_INPUT, IN_WaferOutCass_Front_Cassete, true);
            if (bCassFront) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because cass front sensor on")
                                  .arg(sMotorName));
            }*/
        }
        if (motorid == MOTORB2_RAIL) {

            //TODO:控制D的区域，保证只要不是在放料的操作时，都可以打开关闭
            CMotorDriver::MotorDestArea eAreatypeD = pMotorDriver->get_motor_cur_area_type(MOTORD_TRANS);
            CMotorDriver::MotorDestArea eAreatypeA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            CProcess_Trans* pTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            if (idirect > 0 && eAreatypeA == CMotorDriver::PAS_AREA) {
                if (eAreatypeD == CMotorDriver::NAG_AREA) {
                    //在下面涂敷桶时，轨道不能关闭了
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not move because %2 is down")
                                      .arg(sMotorName)
                                      .arg(m_mapNameList[MOTORD_TRANS]));
                } else if (eAreatypeD == CMotorDriver::CENTER_AREA && pTrans->IsPosBigger(dTargetPos, Var_Process_RailFar_PosClose)) {
                    //D轴在轨道里面时，轨道关得比关闭位置还小
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not move because %2 is in Rail Range")
                                      .arg(sMotorName)
                                      .arg(m_mapNameList[MOTORD_TRANS]));
                }
            }
            //TODO:如果上面有晶圆，则不能打开到最大位置，不然晶圆就掉了
            //夹紧为正
            if (pMotorDriver->get_iodata(IO_INPUT, IN_Rail_FarCass_HasWafer, true) == 1
                || pMotorDriver->get_iodata(IO_INPUT, IN_Rail_FarLoc_HasWafer, true) == 1) {
                CProcess_Trans* pTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
                if (pTrans->IsPosLess(dTargetPos, Var_Process_RailFar_PosOpen)) {
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not open because %1 has wafer")
                                      .arg(sMotorName));
                }

                if (pTrans->IsPosUpper(dTargetPos, Var_Process_RailFar_PosClose)) {
                    MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                      QObject::trUtf8("%1 can not close lower because %1 has wafer")
                                      .arg(sMotorName));
                }

            }
        }
#pragma endregion 轨道
#pragma region 料盒
        if (motorid == MOTORC_CASS) {
            //夹抓伸过来了不能移动料盒
            double dACurPos = pMotorDriver->get_posdata(MOTORA_CLAW, true);
            CProcess_Trans* pTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            if (pTrans->IsPosLess(dACurPos, Var_Process_Claw_PosCassOutReady)) {
                MQT_THROW_STR(QObject::trUtf8("%1 can not move because %2 is in casste.")
                              .arg(sMotorName)
                              .arg(m_mapNameList[MOTORA_CLAW]));
            }
            //首片料盒打开不能升降
            bool_t bCassFront = pMotorDriver->get_iodata(IO_INPUT, IN_WaferOutCass_Front_Cassete, true);
            bool_t bCassWaferOut = pMotorDriver->get_iodata(IO_INPUT, IN_WaferOutCass_Wafer_OutSide, true);
            if (bCassFront) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because cass front sensor on")
                                  .arg(sMotorName));
            }

            //bCassWaferOut = 0;
            if (bCassWaferOut) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because wafer out of cass")
                                  .arg(sMotorName));
            }
            //门打开时
            bool_t bCheckboxDoorOpened = pMotorDriver->get_iodata(IO_INPUT, IN_CHECKBOX_DOOR_OPENED, true);
            if (bCheckboxDoorOpened) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because cass checkbox door sensor off")
                                  .arg(sMotorName));
            }

            //规整台靠近料盒位置检测到有料不能移动
            bool_t bLockHasWafer = pMotorDriver->get_iodata(IO_INPUT, IN_Rail_NearCass_HasWafer, true);
            if (bLockHasWafer) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because %2 has wafer")
                                  .arg(sMotorName).arg(m_mapNameList[MOTORB1_LOCK]));
            }
        }
#pragma endregion 料盒
#pragma region 涂覆区
        //中转D轴在下方时，主轴不能运动
        if (motorid == MOTORE_COAT_SPINDLE) {
            CMotorDriver::MotorDestArea eAreaD = pMotorDriver->get_motor_cur_area_type(MOTORD_TRANS);
            CMotorDriver::MotorDestArea eAreaA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            if (eAreaA == CMotorDriver::PAS_AREA && eAreaD == CMotorDriver::NAG_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because %2 down")
                                  .arg(sMotorName).arg(m_mapNameList[MOTORD_TRANS]));
            }
        }
        //中转D轴在下方时，摆臂不能向中间摆
        if (motorid == MOTORE1_COAT_CLEAN_ARM || motorid == MOTORE2_COAT_COAT_ARM) {
            CMotorDriver::MotorDestArea eAreaA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            CMotorDriver::MotorDestArea eAreaD = pMotorDriver->get_motor_cur_area_type(MOTORD_TRANS);
            CMotorDriver::MotorDestArea eAreaTarget = pMotorDriver->get_motor_area_type(motorid, dTargetPos);
            if (eAreaA == CMotorDriver::PAS_AREA && eAreaD == CMotorDriver::NAG_AREA
                && eAreaTarget == CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because %2 down")
                                  .arg(sMotorName).arg(m_mapNameList[MOTORD_TRANS]));
            }
        }
        //涂覆区的清洗摆臂
        if (motorid == MOTORE1_COAT_CLEAN_ARM) {
            //涂覆摆臂在正区域时不能将清洗摆臂摆过去
            CMotorDriver::MotorDestArea eAreaTarget = pMotorDriver->get_motor_area_type(motorid, dTargetPos);
            CMotorDriver::MotorDestArea eAreaE1 =
                pMotorDriver->get_motor_cur_area_type(MOTORE2_COAT_COAT_ARM);
            if (eAreaTarget == CMotorDriver::PAS_AREA
                && eAreaE1 == CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("coattable %1 can not move because %2 in center area")
                                  .arg(sMotorName).arg(m_mapNameList[MOTORE2_COAT_COAT_ARM]));
            }
        }
        if (motorid == MOTORE2_COAT_COAT_ARM) {
            //只有升起来才能摆臂
            bool_t bArmUp = pMotorDriver->get_iodata(IO_INPUT, IN_COAT_ARM_UP_FORWARD, true);
            if (!bArmUp) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because it is down")
                                  .arg(sMotorName));
            }

            //清洗摆臂在正区域时不能将涂覆摆臂摆过去
            CMotorDriver::MotorDestArea eAreaTarget = pMotorDriver->get_motor_area_type(motorid, dTargetPos);
            CMotorDriver::MotorDestArea eAreaE1 =
                pMotorDriver->get_motor_cur_area_type(MOTORE1_COAT_CLEAN_ARM);
            if (eAreaTarget == CMotorDriver::PAS_AREA
                && eAreaE1 == CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("coattable %1 can not move because %2 in center area")
                                  .arg(sMotorName).arg(m_mapNameList[MOTORE1_COAT_CLEAN_ARM]));
            }
        }
        //胶泵不用限制
        if (motorid == MOTORE3_COAT_BUMP) {
            //不控制胶泵
            /*bool_t bArmUp=pMotorDriver->get_iodata(IO_INPUT,
            IN_COAT_ARM_UP_FORWARD,true);
            if(!bArmUp)
            {
            MQT_THROW_STR(QObject::trUtf8("%1 can not move because coat arm is down")
            .arg(_strCompName[motorid]));
            }*/

            //TODO:何时能涂胶
            /*CMotorDriver::MotorDestArea eAreatypeE2=pMotorDriver->
            get_motor_cur_area_type(MOTORE2_COAT_COAT_ARM);
            if(eAreatypeE2!=CMotorDriver::PAS_AREA)
            {
            MQT_THROW_STR(QObject::trUtf8("%1 can not move because coat arm on wait pos")
            .arg(_strCompName[motorid]));
            }*/
        }
#pragma endregion 涂覆区
#pragma region 清洗区
        //取料降下时，不能摆臂过来
        if (motorid == MOTORF1_CLEAN_ARM) {
            CMotorDriver::MotorDestArea eAreaA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            CMotorDriver::MotorDestArea eAreaD = pMotorDriver->get_motor_cur_area_type(MOTORD_TRANS);
            CMotorDriver::MotorDestArea eAreaTarget = pMotorDriver->get_motor_area_type(motorid, dTargetPos);
            if (eAreaA == CMotorDriver::NAG_AREA && eAreaD == CMotorDriver::NAG_AREA
                && eAreaTarget == CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because %2 down")
                                  .arg(sMotorName).arg(m_mapNameList[MOTORD_TRANS]));
            }
        }
        if (motorid == MOTORF_CLEAN_SPINDLE) {
            CMotorDriver::MotorDestArea eAreaD = pMotorDriver->get_motor_cur_area_type(MOTORD_TRANS);
            CMotorDriver::MotorDestArea eAreaA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            if (eAreaA == CMotorDriver::NAG_AREA && eAreaD == CMotorDriver::NAG_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not move because %2 down")
                                  .arg(sMotorName).arg(m_mapNameList[MOTORD_TRANS]));
            }
        }

#pragma endregion 清洗区
    } catch (QString& s) {
        MqDebug() << s;
        try {
            pMotorDriver->stopmove(motorid);
        } catch (QString& s1) {
            MqDebug() << s1;
        }
        throw(s);
    }
}

void CMAllsystem::CheckLimitAndHoming(int iMotorID, bool bChecklimit, int idirect, bool bIsHoming)
{
    CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    if (false == bIsHoming) {
        //检查轴上电状态
        if (false == pMotorDriver->is_motor_enabled(iMotorID)) {
            CMotor* pMotor = GET_CHDIRECT(iMotorID, CMotor);
            MQT_THROW_CODESTR(ALARM_MOTION_CANTMOVE_NOTENABLED, QObject::trUtf8("%1 can't move because axis not enabled.")
                              .arg(pMotor->m_sName));
        }

        {
            //检查轴回原状态
            pMotorDriver->freshHomeStatus(iMotorID);
            CMotor* pMotor = GET_CHDIRECT(iMotorID, CMotor);
            if (!pMotor->m_Variants.get_VData(Var_Motor_Hashome_ID)->toBool()) {
                MQT_THROW_CODESTR(ALARM_MOTION_CANTMOVE_NOTINITED,
                                  QObject::trUtf8("%1 can't move because axis not homed.")
                                  .arg(pMotor->m_sName));
            }
        }
    }

    if (bChecklimit) {
        if (idirect > 0) {
            //正限位
            if (pMotorDriver->is_motor_onpaslimit(iMotorID)) {
                CMotor* pMotor = GET_CHDIRECT(iMotorID, CMotor);
                Q_ASSERT(pMotor);
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 on pas limit before moving pas direct")
                                  .arg(pMotor->m_sName));
            }
        } else if (idirect < 0) {
            //在负限位不能再往负向走
            if (pMotorDriver->is_motor_onnaglimit(iMotorID)) {
                CMotor* pMotor = GET_CHDIRECT(iMotorID, CMotor);
                Q_ASSERT(pMotor);
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 on nag limit before moving nag direct")
                                  .arg(pMotor->m_sName));
            }
        }
    }
}

void CMAllsystem::OnIsIOSetAvailable(int32_t iIOID, int32_t bSet)
{
    if (IsSimulator())return;

    //LOG_DEBUG(fmt::format("IsMotorIOSetAvailable:{} {}", iIOID, bSet));
    CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
    QString sIoName = pMotorDriver->getioname(IO_OUTPUT, iIOID);

#pragma region 保护罩
    //清洗保护罩
    if (iIOID == OUT_CLEAN_CURTAIN_OPENED) {

        //清洗保护罩
        if (bSet) {

            //涂覆保护罩正在打开或者已经打开了，则不能打开清洗保护罩
            bool_t bCoatCurtainOpened = pMotorDriver->get_iodata(IO_INPUT, IN_COAT_CURTAIN_OPENED, true);
            bool_t bCleanCurtainClosed = pMotorDriver->get_iodata(IO_INPUT, IN_COAT_CURTAIN_CLOSED, true);
            if (!bCleanCurtainClosed || bCoatCurtainOpened) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not open because %2 is not closed")
                                  .arg(sIoName).arg("Coat Curtain"));
            }

            bool_t bCoatCurtainOpenOutput = pMotorDriver->get_iodata(IO_OUTPUT, OUT_COAT_CURTAIN_OPENED, true);
            if (bCoatCurtainOpenOutput) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not open because %2 is opening")
                                  .arg(sIoName).arg("Coat Curtain"));
            }
        } else {
            //关闭保护罩，夹抓在桶里面不能关闭
            CMotorDriver::MotorDestArea eAreatypeA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            CMotorDriver::MotorDestArea eAreatypeD = pMotorDriver->get_motor_cur_area_type(MOTORD_TRANS);
            if (eAreatypeD == CMotorDriver::NAG_AREA && eAreatypeA == CMotorDriver::NAG_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can't close because %2 is down")
                                  .arg(sIoName)
                                  .arg(m_mapNameList[MOTORD_TRANS]));
            }
        }
    }

    //涂覆保护罩
    if (iIOID == OUT_COAT_CURTAIN_OPENED) {
        //涂覆保护罩
        if (bSet) {
            bool_t bCleanCurtainOpened = pMotorDriver->get_iodata(IO_INPUT, IN_CLEAN_CURTAIN_OPENED, true);
            bool_t bCleanCurtainClosed = pMotorDriver->get_iodata(IO_INPUT, IN_CLEAN_CURTAIN_CLOSED, true);
            if (!bCleanCurtainClosed || bCleanCurtainOpened) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not open because %2 is not closed")
                                  .arg(sIoName).arg("Clean Curtain"));
            }

            bool_t bCleanCurtainOpenedOut = pMotorDriver->get_iodata(IO_OUTPUT, OUT_CLEAN_CURTAIN_OPENED, true);
            if (bCleanCurtainOpenedOut) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can not open because %2 is opening")
                                  .arg(sIoName).arg("Clean Curtain"));
            }

        } else {
            //关闭保护罩，夹抓在桶里面不能关闭
            CMotorDriver::MotorDestArea eAreatypeA = pMotorDriver->get_motor_cur_area_type(MOTORA_CLAW);
            CMotorDriver::MotorDestArea eAreatypeD = pMotorDriver->get_motor_cur_area_type(MOTORD_TRANS);
            if (eAreatypeD == CMotorDriver::NAG_AREA && eAreatypeA == CMotorDriver::PAS_AREA) {
                MQT_THROW_CODESTR(ALARM_MOTOR_MOVE_SAFER_PROTECT,
                                  QObject::trUtf8("%1 can't close because %2 is down")
                                  .arg(sIoName)
                                  .arg(m_mapNameList[MOTORD_TRANS]));
            }
        }
    }
#pragma endregion
    if (IsDebug())return;
#pragma region 真空
    if (iIOID == OUT_LOAD_VACUUM) {
        //   if(!bSet)
        {
            //不能直接从平台到涂敷台
            //如果升起时，并且真空开，并且真空有信号时，不能关真空
            CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            if (!bSet
                && pMotorDriver->get_iodata(IO_INPUT, IN_LOAD_VACUUM, true)
                && !transProcess->IsMotorLoadVAtWT()
                && !transProcess->IsMotorInRange(MOTORH1_UPDOWN, Var_Process_Load_PosVRail)) {

                MQT_THROW_CODESTR(ALARM_IO_SAFER_PROTECT, QObject::trUtf8("%1 can not take off while load arm up")
                                  .arg(pMotorDriver->getioname(IO_OUTPUT, iIOID)));
            }
        }
    }
    if (iIOID == OUT_LOAD_VACUUM_BREAK) {
        //保证晶圆在平台位置才能破真空
        //如果升起时，并且真空有信号时，不能破掉真空，可能吸住的晶圆会掉
        CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
        if (bSet
            && pMotorDriver->get_iodata(IO_INPUT, IN_LOAD_VACUUM, true)
            && !transProcess->IsMotorLoadVAtWT()
            && !transProcess->IsMotorLoadVAtRail()) {
            MQT_THROW_CODESTR(ALARM_IO_SAFER_PROTECT, QObject::trUtf8("%1 can not take on while load arm up")
                              .arg(pMotorDriver->getioname(IO_OUTPUT, iIOID)));
        }
    }
    if (iIOID == OUT_UNLOAD_VACUUM) {
        {
            //不在取放料位置时不能开关真空
            CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            //if(bSet){
            //	if(!transProcess->IsMotorUnloadVAtWT()&&!transProcess->IsMotorUnloadHAtWait())
            //	{
            //		MQT_THROW_STR(QObject::trUtf8("%1 can not take off because unload arm up")
            //			.arg(pMotorDriver->getioname(IO_OUTPUT,iIOID)));
            //	}
            //}
            //else{

                //有晶圆时，并且不在放晶圆位置，不能关掉真空,在清洗平台或者加工平台位置可以打开真空
            if (!bSet
                && pMotorDriver->get_iodata(IO_INPUT, IN_LOAD_VACUUM, true)
                && !transProcess->IsMotorUnloadVAtRail()
                && !transProcess->IsMotorUnloadVAtWT()) {
                MQT_THROW_CODESTR(ALARM_IO_SAFER_PROTECT, QObject::trUtf8("%1 can not take off because unload arm up")
                                  .arg(pMotorDriver->getioname(IO_OUTPUT, iIOID)));
            }
            //}
        }
    }
    if (iIOID == OUT_UNLOAD_VACUUM_BREAK) {
        CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
        if (bSet
            && pMotorDriver->get_iodata(IO_INPUT, IN_LOAD_VACUUM, true)
            && !transProcess->IsMotorUnloadVAtRail()
            && !transProcess->IsMotorUnloadVAtWT()) {
            MQT_THROW_CODESTR(ALARM_IO_SAFER_PROTECT, QObject::trUtf8("%1 can not take on because unload arm up")
                              .arg(pMotorDriver->getioname(IO_OUTPUT, iIOID)));

            //if(!bSet){

            //	if(!transProcess->IsMotorUnloadVAtWT()&&!transProcess->IsMotorUnloadHAtWait())
            //	{
            //		MQT_THROW_STR(QObject::trUtf8("%1 can not take off because unload arm up")
            //			.arg(pMotorDriver->getioname(IO_OUTPUT,iIOID)));
            //	}
            //}
            //else{
            //	if(!transProcess->IsMotorUnloadVAtClean()&&!transProcess->IsMotorUnloadHAtClean())
            //	{
            //		MQT_THROW_STR(QObject::trUtf8("%1 can not take off because unload arm up")
            //			.arg(pMotorDriver->getioname(IO_OUTPUT,iIOID)));
            //	}
            //}
        }
    }


    if (iIOID == OUT_TRANSFER_VACUUM || iIOID == OUT_TRANSFER_VACUUM_BREAK) {
        //  if(!bSet)
        {
            /*CProcess_Trans* transProcess = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
            transProcess->IsMotorInRange(MOTORD_TRANS, )*/
            CMotorDriver::MotorDestArea eAreatypeD = pMotorDriver->
                get_motor_cur_area_type(MOTORD_TRANS);
            if (eAreatypeD == CMotorDriver::NAG_AREA) {
                MQT_THROW_CODESTR(ALARM_IO_SAFER_PROTECT, QObject::trUtf8("%1 can not take off because trans arm on nag area.")
                                  .arg(pMotorDriver->getioname(IO_OUTPUT, iIOID)));
            }
        }
    }
#pragma endregion

    //涂覆摆臂
    if (iIOID == OUT_COAT_ARM_UP) {
        if (!bSet) {
            //如果在Wait和Prepare区域，才能降下摆臂
            CMotorDriver::MotorDestArea eAreatypeE2 = pMotorDriver->
                get_motor_cur_area_type(MOTORE2_COAT_COAT_ARM);
            if (eAreatypeE2 == CMotorDriver::NAG_AREA) {
                MQT_THROW_CODESTR(ALARM_IO_SAFER_PROTECT, QObject::trUtf8("Move coat arm to side before coat arm down"));
            }
        }
    }

}

void CMAllsystem::OnFireOn(int32_t iLaserId, bool bOpen)
{
    CMotorDriver* pMotorDriver = static_cast<CMotorDriver*>(GET_CARD(MOTOR_DRIVER, CMotorDriver));
    if (bOpen == true) {
        pMotorDriver->setio(IO_OUTPUT, OUT_LASERGATE, LASER_ON);
    } else {
        pMotorDriver->setio(IO_OUTPUT, OUT_LASERGATE, LASER_OFF);
    }
}

bool CMAllsystem::CheckAutoStart(QString& msg, bool bAsk)
{
    if (IsSimulator()) {
        return true;
    }

    //检查安全门关闭
    try {
        m_gSystem.SafeDoorCheck();
    } catch (const QString& ex) {
        msg = ex;

        CloseSafeDoor();

        return false;
    }

    if (m_gSystem.m_bEnbaleLaserOpen && !IsSimulator()) {
        //检查激光器是否打开
        CLaserDriver_SP* pLaser = GET_CARD(LASER_DRIVER, CLaserDriver_SP);
        if (!pLaser->m_bInited) {
            msg = QObject::tr("Laser is not connected");
            return false;
        }

        if (pLaser->m_bError) {
            msg = QObject::tr("Laser is error, please contact manager");
            return false;
        }

        if (pLaser->m_bPreheat) {
            msg = QObject::tr("Laser is preheating,please waiting");
            return false;
        }

        if (!pLaser->m_bEmissionOn) {
            CWorker* pWorker = GET_CHDIRECT(M_WORKER, CWorker);
            if (pWorker->m_workLevel < LEVEL_FACTORAY) {
                msg = QObject::tr("Laser is not opened");
                return false;
            }
        }

        if (!pLaser->m_bInternalGate) {
            msg = QObject::tr("Laser Inner Gate not opened");
            return false;
        }
    }

	//检查是否回原点
	CMotorDriver* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);
	CHANNELMAP::const_iterator ii = pMotorDriver->mchannels.cbegin();
	for (; ii != pMotorDriver->mchannels.cend(); ii++) {
		if ((*ii)->m_itype == CMotorDriver::MODULE_MOTOR) {
			int motorId = (*ii)->m_iID;
			if (motorId == MOTORG3_WIDEINDEX || motorId == MOTORG4_WIDE5050
				|| motorId == MOTORG1_PCHANGE) {
				continue;
			}
#ifndef __USE_G5_G6__
			if (motorId == MOTORG5_NARROWINDEX || motorId == MOTORG6_NARROW5050)
			{
				continue;
			}
#endif
			pMotorDriver->freshHomeStatus(motorId);
			bool homed = (*ii)->m_Variants.get_VData(Var_Motor_Hashome_ID)->toBool();
			if (!homed) {
				msg = QObject::tr("%1 is not homed").arg((*ii)->m_sName);
				return false;
			}
			if (false == pMotorDriver->is_motor_enabled(motorId)) {
				msg = QObject::tr("%1 is disabled").arg((*ii)->m_sName);
				return false;
			}
		}
	}

    //如果有一个是自动暂停状态，则可以直接启动
    if (IsSMAutoPaused(SM_TRANS)
        || IsSMAutoPaused(SM_MAIN)
        || IsSMAutoPaused(SM_COAT)
        || IsSMAutoPaused(SM_CLEAN)
		|| IsSMAutoPaused(SM_Schedular)
		|| IsSMAutoPaused(SM_WTUnload)
		|| IsSMAutoPaused(SM_WTLoad)) {
        bAsk = false;
        return true;
    }

    //检查涂覆胶量
    CCoatVolumeSensor* pVolumeSensor = GET_CARD(COATVOLUME_SENSOR, CCoatVolumeSensor);
    double dValume = pVolumeSensor->m_dGrams;
    double dAlarmVolume = pVolumeSensor->m_Variants.get_VData(Var_CoatVolume_AlarmVolume)->toDouble();
    if (dValume < dAlarmVolume) {
        msg = QObject::tr("Coat liquid volume %1 ml less than %2 ml").arg(dValume, 0, 'f', 1).arg(dAlarmVolume, 0, 'f', 1);
        return false;
    }

    QDate date = QDate::fromString(pVolumeSensor->m_Variants.get_VData(Var_CoatVolume_ReplaceDate)->toString(), "yyyy-MM-dd");
    int days = pVolumeSensor->m_Variants.get_VData(Var_CoatVolume_InvalidDays)->toInt();
    if (QDate::currentDate() > date.addDays(days)) {
        msg = QObject::tr("Coat liquid invalid at %1").arg(date.addDays(days).toString("yyyy-MM-dd"));
        return false;
    }

    //检查平台是否有料
    CProcess_Trans* ptrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS,
                                         CProcess_Trans);
    msg = QObject::tr("Worktable has wafer");
    if (ptrans->m_pSlotRailNear) {
        msg = QObject::tr("RailNear has wafer");
        return false;
    }

    if (ptrans->m_pSlotRailFar) {
        msg = QObject::tr("RailFar has wafer");
        return false;
    }
    if (ptrans->m_pSlotTrans) {
        msg = QObject::tr("Transfer has wafer");
        return false;
    }
    if (ptrans->m_pSlotCoat) {
        msg = QObject::tr("Coat table has wafer");
        return false;
    }
    if (ptrans->m_pSlotLoad) {
        msg = QObject::tr("Load has wafer");
        return false;
    }
    if (ptrans->m_pSlotWT) {
        msg = QObject::tr("Worktable has wafer");
        return false;
    }
    if (ptrans->m_pSlotUnLoad) {
        msg = QObject::tr("Unload has wafer");
        return false;
    }
    if (ptrans->m_pSlotClean) {
        msg = QObject::tr("Clean table has wafer");
        return false;
    }
    if (ptrans->m_pSlotCheckBox) {
        msg = QObject::tr("Cupboard has wafer");
        return false;
    }

    //检查激光器使用时间
    CLaser* pLaser = GET_CHANNEL(LASER, LASER_DRIVER, CLaser);
    int totalLaserTime = pLaser->m_Variants.get_VData(Var_Laser_LaserTime_ID)->toInt();;
    int totalLaserTimeLimit = pLaser->m_Variants.get_VData(Var_Laser_LaserTime_Limit_ID)->toInt();
    if (totalLaserTimeLimit <= totalLaserTime) {
        msg = QObject::trUtf8("Laser use time :%1 hours "
                              "bigger then limit time :%2 hours").arg(totalLaserTime).arg(totalLaserTimeLimit);
        return false;
    }


    double dErrUseTime = pLaser->m_Variants.get_VData(Var_LaserUseTimeErr)->toDouble();
    CLaserDriver_Base* pLaserDriver = GET_CARD(LASER_DRIVER, CLaserDriver_Base);
    if (pLaserDriver->m_dCurThgUseHours > dErrUseTime) {
        msg = QObject::tr("Laser use time limit (%1 hours) upper (%2 hours).\nPlease contact manager PM\n").arg(pLaserDriver->m_dCurThgUseHours).arg(dErrUseTime);
        return false;
    }

    QString info;
    double dWarningUseTime = pLaser->m_Variants.get_VData(Var_LaserUseTimeWarning)->toDouble();
    if (pLaserDriver->m_dCurThgUseHours > dWarningUseTime) {
        info += QObject::tr("Notice:Task already starting. Laser use time limit (%1 hours) upper (%2 hours).\nPlease contact manager PM\n").arg(pLaserDriver->m_dCurThgUseHours).arg(dWarningUseTime);
    }

    //检查胶量
    double dWarningVolume = pVolumeSensor->m_Variants.get_VData(Var_CoatVolume_WarningVolume)->toDouble();
    if (dValume < dWarningVolume) {
        info += QObject::tr("Notice:Task already starting. Coat liquid %1 low, please prepare to replace coat liquid").arg(dValume);

    }

    if (!info.isEmpty())
        m_SysMsg.SetMsg(info);

    //检查破真空或真空都应该关闭
    //平台真空和破真空是否
    if (pMotorDriver->get_iodata(IO_OUTPUT, OUT_WT_RING_VACUUM_BREAK, true)
        || pMotorDriver->get_iodata(IO_OUTPUT, OUT_WT_RING_VACUUM, true)) {
        msg = QObject::tr("WT Ring Vaccum or Vaccum Break is opened");
        return false;
    }

    //平台真空和破真空
    if (pMotorDriver->get_iodata(IO_OUTPUT, OUT_WT_WAFER_VACUUM, true)
        || pMotorDriver->get_iodata(IO_OUTPUT, OUT_WT_WAFER_VACUUM_BREAK, true)) {
        msg = QObject::tr("WT Wafer Vaccum or Vaccum Break is opened");
        return false;
    }

    //Coat真空和破真空
    if (pMotorDriver->get_iodata(IO_OUTPUT, OUT_COAT_VACUUM, true)
        || pMotorDriver->get_iodata(IO_OUTPUT, OUT_COAT_VACUUM_BREAK, true)) {
        msg = QObject::tr("Coat table Vaccum or Vaccum Break is opened");
        return false;
    }
    //Clean真空和破真空
    if (pMotorDriver->get_iodata(IO_OUTPUT, OUT_CLEAN_VACUUM, true)
        || pMotorDriver->get_iodata(IO_OUTPUT, OUT_CLEAN_VACUUM_BREAK, true)) {
        msg = QObject::tr("Clean table Vaccum or Vaccum Break is opened");
        return false;
    }

    //Load真空和破真空
    if (pMotorDriver->get_iodata(IO_OUTPUT, OUT_LOAD_VACUUM, true)
        || pMotorDriver->get_iodata(IO_OUTPUT, OUT_LOAD_VACUUM_BREAK, true)) {
        msg = QObject::tr("Load Claw Vaccum or Vaccum Break is opened");
        return false;
    }

    //Unload真空和破真空
    if (pMotorDriver->get_iodata(IO_OUTPUT, OUT_UNLOAD_VACUUM, true)
        || pMotorDriver->get_iodata(IO_OUTPUT, OUT_UNLOAD_VACUUM_BREAK, true)) {
        msg = QObject::tr("Unload Claw Vaccum or Vaccum Break is opened");
        return false;
    }

    //Transfer真空和破真空
    if (pMotorDriver->get_iodata(IO_OUTPUT, OUT_TRANSFER_VACUUM, true)
        || pMotorDriver->get_iodata(IO_OUTPUT, OUT_TRANSFER_VACUUM_BREAK, true)) {
        msg = QObject::tr("Trans Claw Vaccum or Vaccum Break is opened");
        return false;
    }

	//轨道上检查
	if (pMotorDriver->get_iodata(IO_INPUT, IN_Rail_NearCass_HasWafer, true)
		|| pMotorDriver->get_iodata(IO_INPUT, IN_Rail_NearLoc_HasWafer, true)) {
		msg = QObject::tr("RailNear has wafer");
		return false;
	}

    //轨道上检查
	if (pMotorDriver->get_iodata(IO_INPUT, IN_Rail_FarCass_HasWafer, true)) {
		msg = QObject::tr("RailFar has wafer");
		return false;
	}

	if (pMotorDriver->get_iodata(IO_INPUT, IN_COAT_CURTAIN_OPENED, true)) {
		msg = QObject::tr("Coat Curtain opened");
		return false;
	}

	if (pMotorDriver->get_iodata(IO_INPUT, IN_CLEAN_CURTAIN_OPENED, true)) {
		msg = QObject::tr("Clean Curtain opened");
		return false;
	}

    bAsk = true;
    return true;
}

void CMAllsystem::publish_msg(const V_Msg& msg)
{
    SMMAP::const_iterator ii = msms.cbegin();
    for (; ii != msms.cend(); ii++) {
        (*ii)->pushfront_Msg(msg);
    }
}

bool CMAllsystem::IsAutoMode()
{
    return false;
    //FATAL:直接使用原始指针，有可能在使用的时候刚好m_pCurState已经被释放了
   /* QMutexLocker lckTrans(&m_gSystem.FindSM(SM_TRANS)->m_SMMutex);
    bool isAutoTrans = m_gSystem.FindSM(SM_TRANS)->m_pCurState->m_iStateType == VS_Thread::State_Work_Auto;
    if (isAutoTrans)return true;
    lckTrans.unlock();


    QMutexLocker lckMain(&m_gSystem.FindSM(SM_MAIN)->m_SMMutex);
    bool isAutoMain = m_gSystem.FindSM(SM_MAIN)->m_pCurState->m_iStateType == VS_Thread::State_Work_Auto;
    if (isAutoMain)return true;
    lckMain.unlock();

    QMutexLocker lckCoat(&m_gSystem.FindSM(SM_COAT)->m_SMMutex);
    bool isAutoCoat = m_gSystem.FindSM(SM_COAT)->m_pCurState->m_iStateType == VS_Thread::State_Work_Auto;
    if (isAutoCoat)return true;
    lckCoat.unlock();


    QMutexLocker lckClean(&m_gSystem.FindSM(SM_CLEAN)->m_SMMutex);
    bool isAutoClean = m_gSystem.FindSM(SM_CLEAN)->m_pCurState->m_iStateType == VS_Thread::State_Work_Auto;
    if (isAutoClean)return true;
    lckClean.unlock();

    return false;*/
}

void CMAllsystem::GetSaveDoorCtrl(bool& bLeft, bool& bRight)
{
    int iSafeDoorConfig = m_Variants.get_VData(Var_AllSystem_SafeDoorConfig_ID)->toInt();
    //0 不使用 1左 2右 3所有

    bLeft = false;
    bRight = false;
    if (iSafeDoorConfig == 3) {
        bLeft = true;
        bRight = true;
    } else if (iSafeDoorConfig == 1) {
        bLeft = true;
    } else if (iSafeDoorConfig == 2) {
        bRight = true;
    }
}

bool CMAllsystem::IsAcsInited()
{
    if (IsSimulator()) return true;

    CMotorDriver_ACS* pMotorDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver_ACS);
    int bufferInited28 = 0;
    int bufferInited29 = 0;
    int bufferInited30 = 0;
    int bufferInited31 = 0;
    pMotorDriver->ReadGlobalInt("G_Buffer28_Status", bufferInited28);
    pMotorDriver->ReadGlobalInt("G_Buffer29_Status", bufferInited29);
    pMotorDriver->ReadGlobalInt("G_Buffer30_Status", bufferInited30);
    pMotorDriver->ReadGlobalInt("G_Buffer31_Status", bufferInited31);

    if (bufferInited28 && bufferInited29 && bufferInited30 && bufferInited31) {
        return true;
    } else {
        return false;
    }

}

void CMAllsystem::SetLotId(const QString& lotId)
{
    QWriteLocker l(&m_mutexWaferId);
    m_sLotID = lotId.toStdString();
}

void CMAllsystem::SetWaferId(int processId, const QString& waferId)
{
    QWriteLocker l(&m_mutexWaferId);
    //CASSSLOT* pCass = nullptr;
    //CProcess_Trans* pTrans = GET_PROCESS(PROCESS_TRANS, SM_TRANS, CProcess_Trans);
    switch (processId) {
    case PROCESS_TRANS:
        m_sTransWafterId = waferId.toStdString();
        break;
    case PROCESS_LEVELING:
    case PROCESS_LOCATE:
    case PROCESS_CUT:
        m_sMainWaferId = waferId.toStdString();
        break;
    case PROCESS_COAT:
        m_sCoatWaferId = waferId.toStdString();
        break;
    case PROCESS_CLEAN:
        m_sCleanWaferId = waferId.toStdString();
        break;
    default:
        break;
    }
}

void CMAllsystem::SetWaferId(int processId, CASSSLOT* pSlot)
{
    if (pSlot == nullptr) {
        LOG_ERR(fmt::format("ProcessId {} Casslot is nullptr", processId));
        return;
    }

    SetWaferId(processId, pSlot->WaferID);
}

void CMAllsystem::SetWaferIdEmpty(int processId)
{
    SetWaferId(processId, "");
}

QString CMAllsystem::MakeRecoverPath(const QString& fileName)
{
    QDir curPath = QDir(QDir::currentPath());
    curPath.cdUp();

    QString path = curPath.absoluteFilePath("RecoverdRecord");
    curPath.setPath(path);
    QString filePath = curPath.absoluteFilePath(fileName);
    return filePath;
}

bool CMAllsystem::WriteRecoverData()
{
    try {
        //TODO:记录的时候清空其他的记录数据

        QString filePath = m_gSystem.MakeRecoverPath("SlotInfo.dat");
        QFile file(filePath);
        if (!file.open(QIODevice::WriteOnly)) {
            LOG_ERR(fmt::format("WriteRecoverData file failed {}", filePath.toLocal8Bit().data()));
            return false;
        }

        QDataStream stream(&file);
        stream << m_strCurFile;
        stream << QString(GetLotId().c_str());
        file.close();
        return true;
    } catch (std::exception ex) {
        LOG_ERR("WriteRecoveredData failed ");
        m_gSystem.LogInfo("Write Recovered data success");
        return false;
    }
}

bool CMAllsystem::ReadRecoverData(QString& recipeName, QString& slotNo)
{
    try {
        QString filePath = m_gSystem.MakeRecoverPath("SlotInfo.dat");
        QFile file(filePath);
        if (!file.open(QIODevice::ReadOnly)) {
            LOG_ERR(fmt::format("create WriteRecoveredData file failed {}", filePath.toLocal8Bit().data()));
            return false;
        }

        QDataStream stream(&file);
        stream >> recipeName;
        stream >> slotNo;

        m_gSystem.LogInfo("Read Recovered data success");
        return true;
    } catch (std::exception ex) {
        LOG_ERR("ReadRecoveredData Failed");
        return false;
    }
}

std::string CMAllsystem::GetTransWaferId()
{
    QReadLocker l(&m_mutexWaferId);
    return m_sTransWafterId;
}

std::string CMAllsystem::GetMainWaferId()
{
    QReadLocker l(&m_mutexWaferId);
    return m_sMainWaferId;
}

std::string CMAllsystem::GetCoatWaferId()
{
    QReadLocker l(&m_mutexWaferId);
    return m_sCoatWaferId;
}

std::string CMAllsystem::GetCleanWaferId()
{
    QReadLocker l(&m_mutexWaferId);
    return m_sCleanWaferId;
}

std::string CMAllsystem::GetLotId()
{
    QReadLocker l(&m_mutexWaferId);
    return m_sLotID;
}

void CMAllsystem::SendLogMessage(const QString& info, int type)
{
    if (nullptr != m_pfnNotifyLogMessage) {
        m_pfnNotifyLogMessage(info, type);
    }
}

void CMAllsystem::SendTerminalMessage(const std::string& info)
{
	if (nullptr != m_pfnNotifyLogMessage) {
		m_pfnNotifyTerminalMessage(info);
	}
}

bool CMAllsystem::SendEvent(_EventID eventID)
{
    return g_SecsManager.SendEvent(eventID);
}

bool CMAllsystem::SetVariable(_SVID svid, const std::string newValue)
{
    return g_SecsManager.SetVariable(svid, newValue);
}

CMAllsystem& CMSystemHelper::GetSysInstance()
{
    Q_ASSERT(m_pInstance && "instance not inited");
    return *m_pInstance;
}

void CMSystemHelper::SetInstance(CMAllsystem* pInstance)
{
    m_pInstance = pInstance;
}

CMSystemHelper& CMSystemHelper::Instance()
{
    static CMSystemHelper instance;
    return instance;
}
