using Aitex.Core.Common;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Aitex.Sorter.Common;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.LoadPortBase;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.TDK;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Xml;
using Aitex.Core.RT.Device.Devices;

//namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.NCD
namespace Aitex.Core.RT.Device.Unit
{
    public class NcdIoLoadPort:LoadPortBaseDevice
    {
        public NcdIoLoadPort(string module, XmlElement node, string ioModule = ""):
            base(node.GetAttribute("module"), node.GetAttribute("id"))
        {
            base.Module = node.GetAttribute("module");//string.IsNullOrEmpty(node.GetAttribute("module")) ? module : node.GetAttribute("module");
            base.Name = node.GetAttribute("id");
            
            ioModule = node.GetAttribute("ioModule");
            _doRecipeSaveCommand = ParseDoNode("DO_RecipeSaveCommand", node, ioModule);
            _doRecipeLoadCommand = ParseDoNode("DO_RecipeLoadCommand", node, ioModule);
            _doIntialCommand = ParseDoNode("DO_IntialCommand", node, ioModule);
            _doResetCommand = ParseDoNode("DO_ResetCommand", node, ioModule);
            _doSingleMappingCommand = ParseDoNode("DO_SingleMappingCommand", node, ioModule);
            _doLoadLight = ParseDoNode("DO_LoadLight", node, ioModule);
            _doUnloadLight = ParseDoNode("DO_UnloadLight", node, ioModule);
            _doStatu1Light = ParseDoNode("DO_Statu1Light", node, ioModule);
            _doStatu2Light = ParseDoNode("DO_Statu2Light", node, ioModule);
            _doLoadCommand = ParseDoNode("DO_LoadCommand", node, ioModule);
            _doUnloadCommand = ParseDoNode("DO_UnloadCommand", node, ioModule);
            _doMapDisableCommand = ParseDoNode("DO_MapDisableCommand", node, ioModule);
            _doMapEnableCommand = ParseDoNode("DO_MapEnableCommand", node, ioModule);
            _doClampOnCommand = ParseDoNode("DO_ClampOnCommand", node, ioModule);
            _doClampOffCommand = ParseDoNode("DO_ClampOffCommand", node, ioModule);
            _doDOCKForwardCommand = ParseDoNode("DO_DOCKForwardCommand", node, ioModule);
            _doDOCKHomeCommand = ParseDoNode("DO_DOCKHomeCommand", node, ioModule);
            _doLatchOnCommand = ParseDoNode("DO_LatchOnCommand", node, ioModule);
            _doLatchOffCommand = ParseDoNode("DO_LatchOffCommand", node, ioModule);
            _doDoorCloseCommand = ParseDoNode("DO_DoorCloseCommand", node, ioModule);
            _doDoorOpenCommand = ParseDoNode("DO_DoorOpenCommand", node, ioModule);
            _doVACOnCommand = ParseDoNode("DO_VACOnCommand", node, ioModule);
            _doVACOffCommand = ParseDoNode("DO_VACOffCommand", node, ioModule);
            _doVertiaclDownCommand = ParseDoNode("DO_VertiaclDownCommand", node, ioModule);
            _doVertiaclUpCommand = ParseDoNode("DO_VertiaclUpCommand", node, ioModule);
            _doZtoMAPPINGSTARTPOSI = ParseDoNode("DO_ZtoMAPPINGSTARTPOSI", node, ioModule);
            _doZtoMAPPINGENDPOSI = ParseDoNode("DO_ZtoMAPPINGENDPOSI", node, ioModule);
            _doMAPIN = ParseDoNode("DO_MAPIN", node, ioModule);
            _doMAPOUT = ParseDoNode("DO_MAPOUT", node, ioModule);

            _aoSAVECurrentRecipeNumber = ParseAoNode("AO_SAVECurrentRecipeNumber", node, ioModule);
            _aoMAPSTAR = ParseAoNode("AO_MAPSTAR", node, ioModule);
            _aoMAPEND = ParseAoNode("AO_MAPEND", node, ioModule);
            _aoSENSOR = ParseAoNode("AO_SENSOR", node, ioModule);
            _aoSLOT = ParseAoNode("AO_SLOT", node, ioModule);
            _aoPITCH = ParseAoNode("AO_PITCH", node, ioModule);
            _aoPOSITIONRANGE = ParseAoNode("AO_POSITIONRANGE", node, ioModule);
            _aoPOSITIONRANGEUPPER = ParseAoNode("AO_POSITIONRANGEUPPER", node, ioModule);
            _aoPOSITIONRANGELOWER = ParseAoNode("AO_POSITIONRANGELOWER", node, ioModule);
            _aoTHICK = ParseAoNode("AO_THICK", node, ioModule);
            _aoTHICKRANGE = ParseAoNode("AO_THICKRANGE", node, ioModule);
            _aoOFFSET = ParseAoNode("AO_OFFSET", node, ioModule);
            _aoCarrierType = ParseAoNode("AO_CarrierType", node, ioModule);

            _aiSlot1MapResult = ParseAiNode("AI_Slot1MapResult", node, ioModule);
            _aiSlot2MapResult = ParseAiNode("AI_Slot2MapResult", node, ioModule);
            _aiSlot3MapResult = ParseAiNode("AI_Slot3MapResult", node, ioModule);
            _aiSlot4MapResult = ParseAiNode("AI_Slot4MapResult", node, ioModule);
            _aiSlot5MapResult = ParseAiNode("AI_Slot5MapResult", node, ioModule);
            _aiSlot6MapResult = ParseAiNode("AI_Slot6MapResult", node, ioModule);
            _aiSlot7MapResult = ParseAiNode("AI_Slot7MapResult", node, ioModule);
            _aiSlot8MapResult = ParseAiNode("AI_Slot8MapResult", node, ioModule);
            _aiSlot9MapResult = ParseAiNode("AI_Slot9MapResult", node, ioModule);
            _aiSlot10MapResult = ParseAiNode("AI_Slot10MapResult", node, ioModule);
            _aiSlot11MapResult = ParseAiNode("AI_Slot11MapResult", node, ioModule);
            _aiSlot12MapResult = ParseAiNode("AI_Slot12MapResult", node, ioModule);
            _aiSlot13MapResult = ParseAiNode("AI_Slot13MapResult", node, ioModule);
            _aiSlot14MapResult = ParseAiNode("AI_Slot14MapResult", node, ioModule);
            _aiSlot15MapResult = ParseAiNode("AI_Slot15MapResult", node, ioModule);
            _aiSlot16MapResult = ParseAiNode("AI_Slot16MapResult", node, ioModule);
            _aiSlot17MapResult = ParseAiNode("AI_Slot17MapResult", node, ioModule);
            _aiSlot18MapResult = ParseAiNode("AI_Slot18MapResult", node, ioModule);
            _aiSlot19MapResult = ParseAiNode("AI_Slot19MapResult", node, ioModule);
            _aiSlot20MapResult = ParseAiNode("AI_Slot20MapResult", node, ioModule);
            _aiSlot21MapResult = ParseAiNode("AI_Slot21MapResult", node, ioModule);
            _aiSlot22MapResult = ParseAiNode("AI_Slot22MapResult", node, ioModule);
            _aiSlot23MapResult = ParseAiNode("AI_Slot23MapResult", node, ioModule);
            _aiSlot24MapResult = ParseAiNode("AI_Slot24MapResult", node, ioModule);
            _aiSlot25MapResult = ParseAiNode("AI_Slot25MapResult", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot1 = ParseAiNode("AI__WAFERPOSITIONUPPEREDGE_Slot1", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot1 = ParseAiNode("AI__WAFERPOSITIONLOWEREDGE_Slot1", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot2 = ParseAiNode("AI__WAFERPOSITIONUPPEREDGE_Slot2", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot2 = ParseAiNode("AI__WAFERPOSITIONLOWEREDGE_Slot2", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot3 = ParseAiNode("AI__WAFERPOSITIONUPPEREDGE_Slot3", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot3 = ParseAiNode("AI__WAFERPOSITIONLOWEREDGE_Slot3", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot4 = ParseAiNode("AI__WAFERPOSITIONUPPEREDGE_Slot4", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot4 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot4", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot5 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot5", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot5 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot5", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot6 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot6", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot6 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot6", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot7 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot7", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot7 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot7", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot8 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot8", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot8 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot8", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot9 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot9", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot9 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot9", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot10 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot10", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot10 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot10", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot11 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot11", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot11 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot11", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot12 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot12", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot12 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot12", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot13 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot13", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot13 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot13", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot14 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot14", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot14 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot14", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot15 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot15", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot15 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot15", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot16 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot16", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot16 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot16", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot17 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot17", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot17 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot17", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot18 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot18", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot18 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot18", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot19 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot19", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot19 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot19", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot20 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot20", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot20 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot20", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot21 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot21", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot21 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot21", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot22 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot22", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot22 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot22", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot23 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot23", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot23 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot23", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot24 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot24", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot24 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot24", node, ioModule);
            _aiWAFERPOSITIONUPPEREDGE_Slot25 = ParseAiNode("AI_WAFERPOSITIONUPPEREDGE_Slot25", node, ioModule);
            _aiWAFERPOSITIONLOWEREDGE_Slot25 = ParseAiNode("AI_WAFERPOSITIONLOWEREDGE_Slot25", node, ioModule);
            _aiErrorCode = ParseAiNode("AI_ErrorCode", node, ioModule);
            _aiLastErrorCode = ParseAiNode("AI_LastErrorCode", node, ioModule);

            _aiRECIPE_TYPE_FEEDBACK = ParseAiNode("AI_RECIPE_TYPE_FEEDBACK", node, ioModule);



            _diAck_RecieSave = ParseDiNode("DI_Ack_RecieSave", node, ioModule);
            _diAck_RecipeLoad = ParseDiNode("DI_Ack_RecipeLoad", node, ioModule);
            _diAck_Init = ParseDiNode("DI_Ack_Init", node, ioModule);
            _diAck_Reset = ParseDiNode("DI_Ack_Reset", node, ioModule);
            _diAck_SingleMap = ParseDiNode("DI_Ack_SingleMap", node, ioModule);


            _diAck_HomePos = ParseDiNode("DI_Ack_HomePos", node, ioModule);
            _diSensor_Presence = ParseDiNode("DI_Sensor_Presence", node, ioModule);
            _diSensor_Placement = ParseDiNode("DI_Sensor_Placement", node, ioModule);
            _diSensor_Protrude = ParseDiNode("DI_Sensor_Protrude", node, ioModule);
            _diSensor_VerticalDown = ParseDiNode("DI_Sensor_VerticalDown", node, ioModule);
            _diAck_Load = ParseDiNode("DI_Ack_Load", node, ioModule);
            _diAck_Unload = ParseDiNode("DI_Ack_Unload", node, ioModule);
            _diAck_MapDisable = ParseDiNode("DI_Ack_MapDisable", node, ioModule);
            _diAck_MapEnable = ParseDiNode("DI_Ack_MapEnable", node, ioModule);
            _diAck_ClampOn = ParseDiNode("DI_Ack_ClampOn", node, ioModule);
            _diAck_ClampOff = ParseDiNode("DI_Ack_ClampOff", node, ioModule);
            _diAck_DockFwd = ParseDiNode("DI_Ack_DockFwd", node, ioModule);
            _diAck_DockHome = ParseDiNode("DI_Ack_DockHome", node, ioModule);
            _diAck_LatchOn = ParseDiNode("DI_Ack_LatchOn", node, ioModule);
            _diAck_LatchOff = ParseDiNode("DI_Ack_LatchOff", node, ioModule);
            _diAck_DoorClose = ParseDiNode("DI_Ack_DoorClose", node, ioModule);
            _diAck_DoorOpen = ParseDiNode("DI_Ack_DoorOpen", node, ioModule);
            _diAck_VacOn = ParseDiNode("DI_Ack_VacOn", node, ioModule);
            _diAck_VacOff = ParseDiNode("DI_Ack_VacOff", node, ioModule);
            _diAck_VerticalDown = ParseDiNode("DI_Ack_VerticalDown", node, ioModule);
            _diAck_VerticalUp = ParseDiNode("DI_Ack_VerticalUp", node, ioModule);
            _diAck_ZtoMapStart = ParseDiNode("DI_Ack_ZtoMapStart", node, ioModule);
            _diAck_ZtoMapEnd = ParseDiNode("DI_Ack_ZtoMapEnd", node, ioModule);
            _diAck_Mapin = ParseDiNode("DI_Ack_Mapin", node, ioModule);
            _diAck_MapOut = ParseDiNode("DI_Ack_MapOut", node, ioModule);
            _diAck_CmdClear = ParseDiNode("DI_Ack_CmdClear", node, ioModule);
            _diAck_E84Disable = ParseDiNode("DI_Ack_E84Disable", node, ioModule);
            _diAck_E84Enable = ParseDiNode("DI_Ack_E84Enable", node, ioModule);


            _di12MapSensor = ParseDiNode("DI_12MapSensor", node, ioModule);
            _di8MapSensor = ParseDiNode("DI_8MapSensor", node, ioModule);
            _diSERVOHOME = ParseDiNode("DI_SERVOHOME", node, ioModule);
            _diFoupPlacementSensor = ParseDiNode("DI_FoupPlacementSensor", node, ioModule);
            _diDoorCheckSensor = ParseDiNode("DI_DoorCheckSensor", node, ioModule);
            _diCDASensor = ParseDiNode("DI_CDASensor", node, ioModule);
            _diDockHomeSensor = ParseDiNode("DI_DockHomeSensor", node, ioModule);
            _diClampOffSensor = ParseDiNode("DI_ClampOffSensor", node, ioModule);
            _diPodForwardSensor = ParseDiNode("DI_PodForwardSensor", node, ioModule);
            _diClampOnSensor = ParseDiNode("DI_ClampOnSensor", node, ioModule);
            _diVACSensor = ParseDiNode("DI_VACSensor", node, ioModule);
            _diLatchLockSensor = ParseDiNode("DI_LatchLockSensor", node, ioModule);
            _diLatchUnlockSensor = ParseDiNode("DI_LatchUnlockSensor", node, ioModule);
            _diDoorOpenSensor = ParseDiNode("DI_DoorOpenSensor", node, ioModule);
            _diDoorCloseSensor = ParseDiNode("DI_DoorCloseSensor", node, ioModule);
            _diVerticalMiddleSensor = ParseDiNode("DI_VerticalMiddleSensor", node, ioModule);
            _diVerticalDownSensor = ParseDiNode("DI_VerticalDownSensor", node, ioModule);
            _diOPSwitchButton = ParseDiNode("DI_OPSwitchButton", node, ioModule);
            _diMapin = ParseDiNode("DI_Mapin", node, ioModule);
            _diMapout = ParseDiNode("DI_Mapout", node, ioModule);
            _diProtrudesensor = ParseDiNode("DI_Protrudesensor", node, ioModule);
            _diInfoPadA = ParseDiNode("DI_InfoPadA", node, ioModule);
            _diInfoPadB = ParseDiNode("DI_InfoPadB", node, ioModule);
            _diInfoPadC = ParseDiNode("DI_InfoPadC", node, ioModule);
            _diInfoPadD = ParseDiNode("DI_InfoPadD", node, ioModule);
            _diServoOn = ParseDiNode("DI_ServoOn", node, ioModule);
            _diPresence = ParseDiNode("DI_Presence", node, ioModule);
            _diStepError = ParseDiNode("DI_StepError", node, ioModule);
            _diServoerror = ParseDiNode("DI_Servoerror", node, ioModule);
            _diDoorSafe = ParseDiNode("DI_DoorSafe", node, ioModule);
            _diSERVO = ParseDiNode("DI_SERVO", node, ioModule);
            _diSTEP = ParseDiNode("DI_STEP", node, ioModule);

            _diClampOnCylinder = ParseDiNode("DI_ClampOnCylinder", node, ioModule);
            _diClampOffCylinder = ParseDiNode("DI_ClampOffCylinder", node, ioModule);
            _diLatchOnCylinder = ParseDiNode("DI_LatchOnCylinder", node, ioModule);
            _diLatchOffCylinder = ParseDiNode("DI_LatchOffCylinder", node, ioModule);
            _diDoorOpenCylinder = ParseDiNode("DI_DoorOpenCylinder", node, ioModule);
            _diDoorCloseCylinder = ParseDiNode("DI_DoorCloseCylinder", node, ioModule);
            _diSERVOCLEAR1 = ParseDiNode("DI_SERVOCLEAR1", node, ioModule);
            _diSERVOON1 = ParseDiNode("DI_SERVOON1", node, ioModule);
            _diD3UBIN = ParseDiNode("DI_D3UBIN", node, ioModule);
            _diMapForwardCylinder = ParseDiNode("DI_MapForwardCylinder", node, ioModule);
            _diSERVOCLEAR2 = ParseDiNode("DI_SERVOCLEAR2", node, ioModule);
            _diSERVOON2 = ParseDiNode("DI_SERVOON2", node, ioModule);
            _diSERVOCLCOUNT = ParseDiNode("DI_SERVOCLCOUNT", node, ioModule);
            _diVAC = ParseDiNode("DI_VAC", node, ioModule);
            _diSERVOBRAKE = ParseDiNode("DI_SERVOBRAKE", node, ioModule);

            _diLoadLight = ParseDiNode("DI_LoadLight", node, ioModule);
            _diUnloadLight = ParseDiNode("DI_UnloadLight", node, ioModule);
            _diPOWERLIGHT = ParseDiNode("DI_POWERLIGHT", node, ioModule);
            _diFoupPlacementLight = ParseDiNode("DI_FoupPlacementLight", node, ioModule);
            _diFoupPresenceLight = ParseDiNode("DI_FoupPresenceLight", node, ioModule);
            _diAlarmOccurLight = ParseDiNode("DI_AlarmOccurLight", node, ioModule);
            _diStatu1Light = ParseDiNode("DI_Statu1Light", node, ioModule);
            _diStatu2Light = ParseDiNode("DI_Statu2Light", node, ioModule);


            SubscribeData();
            SubscribeEventAndAlarm();
            IsMapWaferByLoadPort = true;
            _carrierArrived = new R_TRIG();
            _errorOccurredTrig = new R_TRIG();
            _lastErrorOccurredTrig = new R_TRIG();
            _alarmWaferProtrudeTrig = new R_TRIG();
            _thread = new PeriodicJob(10, OnTimer, $"{Module}.{Name} MonitorHandler", true);
            

        }        

        public string[] AlarmNcdLoadPortErrors;
        public string[] AlarmNcdLoadPortLastErrors;

        private void SubscribeEventAndAlarm()
        {
            AlarmNcdLoadPortErrors = new string[73];
            for(int i=0;i<73;i++)
            {
                AlarmNcdLoadPortErrors[i] = "Ncd " + LPModuleName.ToString() + "Error" + (i + 1).ToString();
                EV.Subscribe(new EventItem("Alarm", AlarmNcdLoadPortErrors[i], $"Load Port {Name} occurred error, D2801 error code is {i+1}.", EventLevel.Alarm, EventType.EventUI_Notify));
            }
            AlarmNcdLoadPortLastErrors = new string[29];
            for (int i = 0; i < 29; i++)
            {
                AlarmNcdLoadPortLastErrors[i] = "Ncd " + LPModuleName.ToString() + "LastError" + (i + 1).ToString();
                EV.Subscribe(new EventItem("Alarm", AlarmNcdLoadPortLastErrors[i], $"Load Port {Name} occurred error, D2802 error code is {i + 1}.", EventLevel.Alarm, EventType.EventUI_Notify));
            }

            EV.Subscribe(new EventItem("Alarm", AlarmLoadPortLoadRecipeFailed, $"Load Port {Name} load recipe Timeout.", EventLevel.Alarm, EventType.EventUI_Notify));
        }

        private string AlarmLoadPortLoadRecipeFailed 
        { 
            get => LPModuleName.ToString() + "LoadRecipeFailed";
    
        }

        private void SubscribeData()
        {

            DATA.Subscribe($"{Module}.{Name}.SystemStatus", () => CurrentState.ToString());
            DATA.Subscribe($"{Module}.{Name}.Mode", () => Mode.ToString());
            DATA.Subscribe($"{Module}.{Name}.InitPosMovement", () => InitPosMovement.ToString());
            DATA.Subscribe($"{Module}.{Name}.OperationStatus", () => OperationStatus.ToString());
            DATA.Subscribe($"{Module}.{Name}.ErrorCode", () => ErrorCode.ToString());
            DATA.Subscribe($"{Module}.{Name}.ContainerStatus", () => ContainerStatus.ToString());
            DATA.Subscribe($"{Module}.{Name}.ClampPosition", () => ClampPosition.ToString());
            DATA.Subscribe($"{Module}.{Name}.LPDoorLatchPosition", () => LPDoorLatchPosition.ToString());
            DATA.Subscribe($"{Module}.{Name}.VacuumStatus", () => VacuumStatus.ToString());
            DATA.Subscribe($"{Module}.{Name}.LPDoorState", () => LPDoorState.ToString());
            DATA.Subscribe($"{Module}.{Name}.WaferProtrusion", () => WaferProtrusion.ToString());
            DATA.Subscribe($"{Module}.{Name}.ElevatorAxisPosition", () => ElevatorAxisPosition.ToString());
            DATA.Subscribe($"{Module}.{Name}.MapperPostion", () => MapperPostion.ToString());
            DATA.Subscribe($"{Module}.{Name}.MappingStatus", () => MappingStatus.ToString());
            DATA.Subscribe($"{Module}.{Name}.Model", () => Model.ToString());
            DATA.Subscribe($"{Module}.{Name}.IsFosbModeActual", () => IsFosbModeActual.ToString());

            DATA.Subscribe($"{Module}.{Name}.DockPosition", () => DockPosition.ToString());


            DATA.Subscribe($"{Name}.SystemStatus", () => CurrentState.ToString());
            DATA.Subscribe($"{Name}.Mode", () => Mode.ToString());
            DATA.Subscribe($"{Name}.InitPosMovement", () => InitPosMovement.ToString());
            DATA.Subscribe($"{Name}.OperationStatus", () => OperationStatus.ToString());
            DATA.Subscribe($"{Name}.ErrorCode", () => ErrorCode.ToString());
            DATA.Subscribe($"{Name}.ContainerStatus", () => ContainerStatus.ToString());
            DATA.Subscribe($"{Name}.ClampPosition", () => ClampPosition.ToString());
            DATA.Subscribe($"{Name}.LPDoorLatchPosition", () => LPDoorLatchPosition.ToString());
            DATA.Subscribe($"{Name}.VacuumStatus", () => VacuumStatus.ToString());
            DATA.Subscribe($"{Name}.LPDoorState", () => LPDoorState.ToString());
            DATA.Subscribe($"{Name}.WaferProtrusion", () => WaferProtrusion.ToString());
            DATA.Subscribe($"{Name}.ElevatorAxisPosition", () => ElevatorAxisPosition.ToString());
            DATA.Subscribe($"{Name}.MapperPostion", () => MapperPostion.ToString());
            DATA.Subscribe($"{Name}.MappingStatus", () => MappingStatus.ToString());
            DATA.Subscribe($"{Name}.Model", () => Model.ToString());
            DATA.Subscribe($"{Name}.IsFosbModeActual", () => IsFosbModeActual.ToString());

            DATA.Subscribe($"{Name}.DockPosition", () => DockPosition.ToString());
        }

        private PeriodicJob _thread;
        private DOAccessor _doRecipeSaveCommand;
        private DOAccessor _doRecipeLoadCommand;
        private DOAccessor _doIntialCommand;
        private DOAccessor _doResetCommand;
        private DOAccessor _doSingleMappingCommand;


        private DOAccessor _doLoadLight;
        private DOAccessor _doUnloadLight;
        private DOAccessor _doStatu1Light;
        private DOAccessor _doStatu2Light;
        private DOAccessor _doLoadCommand;
        private DOAccessor _doUnloadCommand;
        private DOAccessor _doMapDisableCommand;
        private DOAccessor _doMapEnableCommand;
        private DOAccessor _doClampOnCommand;
        private DOAccessor _doClampOffCommand;
        private DOAccessor _doDOCKForwardCommand;
        private DOAccessor _doDOCKHomeCommand;
        private DOAccessor _doLatchOnCommand;
        private DOAccessor _doLatchOffCommand;
        private DOAccessor _doDoorCloseCommand;
        private DOAccessor _doDoorOpenCommand;
        private DOAccessor _doVACOnCommand;
        private DOAccessor _doVACOffCommand;
        private DOAccessor _doVertiaclDownCommand;
        private DOAccessor _doVertiaclUpCommand;
        private DOAccessor _doZtoMAPPINGSTARTPOSI;
        private DOAccessor _doZtoMAPPINGENDPOSI;
        private DOAccessor _doMAPIN;
        private DOAccessor _doMAPOUT;

        private AOAccessor _aoSAVECurrentRecipeNumber;
        private AOAccessor _aoMAPSTAR; //MAP STAR(10um)    [ 2000<VALUE<30000]		
        private AOAccessor _aoMAPEND;//MAP END(10um)   [2000<VALUE<30000]	
        private AOAccessor _aoSENSOR; //SENSOR (1：12寸   ;    2：8寸）	
        private AOAccessor _aoSLOT;
        private AOAccessor _aoPITCH;
        private AOAccessor _aoPOSITIONRANGE; //POSITION RANGE(10um)
        private AOAccessor _aoPOSITIONRANGEUPPER; //POSITION RANGE UPPER(％)	
        private AOAccessor _aoPOSITIONRANGELOWER; //POSITION RANGE LOWER(％)		
        private AOAccessor _aoTHICK;//THICK(10um)		
        private AOAccessor _aoTHICKRANGE;//THICK RANGE(10um)	
        private AOAccessor _aoOFFSET;//OFFSET(10um)
        private AOAccessor _aoCarrierType;//料盒种类（1-FOUP，2-FOSB，3-Open Cassette）

        private AIAccessor _aiSlot1MapResult;    // ( 0:No Wafer, 1:Wafer, 2:Crossed )
        private AIAccessor _aiSlot2MapResult;
        private AIAccessor _aiSlot3MapResult;
        private AIAccessor _aiSlot4MapResult;
        private AIAccessor _aiSlot5MapResult;
        private AIAccessor _aiSlot6MapResult;
        private AIAccessor _aiSlot7MapResult;
        private AIAccessor _aiSlot8MapResult;
        private AIAccessor _aiSlot9MapResult;
        private AIAccessor _aiSlot10MapResult;
        private AIAccessor _aiSlot11MapResult;
        private AIAccessor _aiSlot12MapResult;
        private AIAccessor _aiSlot13MapResult;
        private AIAccessor _aiSlot14MapResult;
        private AIAccessor _aiSlot15MapResult;
        private AIAccessor _aiSlot16MapResult;
        private AIAccessor _aiSlot17MapResult;
        private AIAccessor _aiSlot18MapResult;
        private AIAccessor _aiSlot19MapResult;
        private AIAccessor _aiSlot20MapResult;
        private AIAccessor _aiSlot21MapResult;
        private AIAccessor _aiSlot22MapResult;
        private AIAccessor _aiSlot23MapResult;
        private AIAccessor _aiSlot24MapResult;
        private AIAccessor _aiSlot25MapResult;

        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot1;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot1;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot2;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot2;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot3;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot3;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot4;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot4;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot5;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot5;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot6;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot6;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot7;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot7;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot8;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot8;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot9;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot9;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot10;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot10;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot11;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot11;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot12;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot12;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot13;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot13;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot14;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot14;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot15;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot15;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot16;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot16;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot17;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot17;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot18;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot18;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot19;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot19;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot20;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot20;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot21;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot21;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot22;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot22;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot23;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot23;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot24;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot24;
        private AIAccessor _aiWAFERPOSITIONUPPEREDGE_Slot25;
        private AIAccessor _aiWAFERPOSITIONLOWEREDGE_Slot25;
        private AIAccessor _aiErrorCode;
        private AIAccessor _aiLastErrorCode;




        private AIAccessor _aiTYPE1_CurrentRecipeNumber;
        private AIAccessor _aiTYPE1_MAPSTAR;
        private AIAccessor _aiTYPE1_MAPEND;
        private AIAccessor _aiTYPE1_SENSOR_WaferSize;
        private AIAccessor _aiTYPE1_SLOT;
        private AIAccessor _aiTYPE1_PITCH;
        private AIAccessor _aiTYPE1_POSITIONRANGE;
        private AIAccessor _aiTYPE1_POSITIONRANGEUPPER;
        private AIAccessor _aiTYPE1_POSITIONRANGELOWER;
        private AIAccessor _aiTYPE1_THICK;
        private AIAccessor _aiTYPE1_THICKRANGE;
        private AIAccessor _aiTYPE1_OFFSET;


        private AIAccessor _aiTYPE2_CurrentRecipeNumber;
        private AIAccessor _aiTYPE2_MAPSTAR;
        private AIAccessor _aiTYPE2_MAPEND;
        private AIAccessor _aiTYPE2_SENSOR_WaferSize;
        private AIAccessor _aiTYPE2_SLOT;
        private AIAccessor _aiTYPE2_PITCH;
        private AIAccessor _aiTYPE2_POSITIONRANGE;
        private AIAccessor _aiTYPE2_POSITIONRANGEUPPER;
        private AIAccessor _aiTYPE2_POSITIONRANGELOWER;
        private AIAccessor _aiTYPE2_THICK;
        private AIAccessor _aiTYPE2_THICKRANGE;
        private AIAccessor _aiTYPE2_OFFSET;


        private AIAccessor _aiTYPE3_CurrentRecipeNumber;
        private AIAccessor _aiTYPE3_MAPSTAR;
        private AIAccessor _aiTYPE3_MAPEND;
        private AIAccessor _aiTYPE3_SENSOR_WaferSize;
        private AIAccessor _aiTYPE3_SLOT;
        private AIAccessor _aiTYPE3_PITCH;
        private AIAccessor _aiTYPE3_POSITIONRANGE;
        private AIAccessor _aiTYPE3_POSITIONRANGEUPPER;
        private AIAccessor _aiTYPE3_POSITIONRANGELOWER;
        private AIAccessor _aiTYPE3_THICK;
        private AIAccessor _aiTYPE3_THICKRANGE;
        private AIAccessor _aiTYPE3_OFFSET;


        private AIAccessor _aiTYPE4_CurrentRecipeNumber;
        private AIAccessor _aiTYPE4_MAPSTAR;
        private AIAccessor _aiTYPE4_MAPEND;
        private AIAccessor _aiTYPE4_SENSOR_WaferSize;
        private AIAccessor _aiTYPE4_SLOT;
        private AIAccessor _aiTYPE4_PITCH;
        private AIAccessor _aiTYPE4_POSITIONRANGE;
        private AIAccessor _aiTYPE4_POSITIONRANGEUPPER;
        private AIAccessor _aiTYPE4_POSITIONRANGELOWER;
        private AIAccessor _aiTYPE4_THICK;
        private AIAccessor _aiTYPE4_THICKRANGE;
        private AIAccessor _aiTYPE4_OFFSET;

        private AIAccessor _aiTYPE5_CurrentRecipeNumber;
        private AIAccessor _aiTYPE5_MAPSTAR;
        private AIAccessor _aiTYPE5_MAPEND;
        private AIAccessor _aiTYPE5_SENSOR_WaferSize;
        private AIAccessor _aiTYPE5_SLOT;
        private AIAccessor _aiTYPE5_PITCH;
        private AIAccessor _aiTYPE5_POSITIONRANGE;
        private AIAccessor _aiTYPE5_POSITIONRANGEUPPER;
        private AIAccessor _aiTYPE5_POSITIONRANGELOWER;
        private AIAccessor _aiTYPE5_THICK;
        private AIAccessor _aiTYPE5_THICKRANGE;
        private AIAccessor _aiTYPE5_OFFSET;

        private AIAccessor _aiTYPE6_CurrentRecipeNumber;
        private AIAccessor _aiTYPE6_MAPSTAR;
        private AIAccessor _aiTYPE6_MAPEND;
        private AIAccessor _aiTYPE6_SENSOR_WaferSize;
        private AIAccessor _aiTYPE6_SLOT;
        private AIAccessor _aiTYPE6_PITCH;
        private AIAccessor _aiTYPE6_POSITIONRANGE;
        private AIAccessor _aiTYPE6_POSITIONRANGEUPPER;
        private AIAccessor _aiTYPE6_POSITIONRANGELOWER;
        private AIAccessor _aiTYPE6_THICK;
        private AIAccessor _aiTYPE6_THICKRANGE;
        private AIAccessor _aiTYPE6_OFFSET;

        private AIAccessor _aiRECIPE_TYPE_FEEDBACK;

       
        private DIAccessor _diAck_RecieSave;
        private DIAccessor _diAck_RecipeLoad;
        private DIAccessor _diAck_Init;
        private DIAccessor _diAck_Reset;
        private DIAccessor _diAck_SingleMap;


        private DIAccessor _diAck_HomePos;
        private DIAccessor _diSensor_Presence;
        private DIAccessor _diSensor_Placement;
        private DIAccessor _diSensor_Protrude;
        private DIAccessor _diSensor_VerticalDown;
        private DIAccessor _diAck_Load;
        private DIAccessor _diAck_Unload;
        private DIAccessor _diAck_MapDisable;
        private DIAccessor _diAck_MapEnable;
        private DIAccessor _diAck_ClampOn;
        private DIAccessor _diAck_ClampOff;
        private DIAccessor _diAck_DockFwd;
        private DIAccessor _diAck_DockHome;
        private DIAccessor _diAck_LatchOn;
        private DIAccessor _diAck_LatchOff;
        private DIAccessor _diAck_DoorClose;
        private DIAccessor _diAck_DoorOpen;
        private DIAccessor _diAck_VacOn;
        private DIAccessor _diAck_VacOff;
        private DIAccessor _diAck_VerticalDown;
        private DIAccessor _diAck_VerticalUp;
        private DIAccessor _diAck_ZtoMapStart;
        private DIAccessor _diAck_ZtoMapEnd;
        private DIAccessor _diAck_Mapin;
        private DIAccessor _diAck_MapOut;
        private DIAccessor _diAck_CmdClear;
        private DIAccessor _diAck_E84Disable;
        private DIAccessor _diAck_E84Enable;

        //原X,Y
        private DIAccessor _di12MapSensor;
        private DIAccessor _di8MapSensor;
        private DIAccessor _diSERVOHOME;
        private DIAccessor _diFoupPlacementSensor;
        private DIAccessor _diDoorCheckSensor;
        private DIAccessor _diCDASensor;
        private DIAccessor _diDockHomeSensor;
        private DIAccessor _diClampOffSensor;
        private DIAccessor _diPodForwardSensor;
        private DIAccessor _diClampOnSensor;
        private DIAccessor _diVACSensor;
        private DIAccessor _diLatchLockSensor;
        private DIAccessor _diLatchUnlockSensor;
        private DIAccessor _diDoorOpenSensor;
        private DIAccessor _diDoorCloseSensor;
        private DIAccessor _diVerticalMiddleSensor;
        private DIAccessor _diVerticalDownSensor;
        private DIAccessor _diOPSwitchButton;
        private DIAccessor _diMapin;
        private DIAccessor _diMapout;
        private DIAccessor _diProtrudesensor;
        private DIAccessor _diInfoPadA;
        private DIAccessor _diInfoPadB;
        private DIAccessor _diInfoPadC;
        private DIAccessor _diInfoPadD;
        private DIAccessor _diServoOn;
        private DIAccessor _diPresence;
        private DIAccessor _diStepError;
        private DIAccessor _diServoerror;
        private DIAccessor _diDoorSafe;
        private DIAccessor _diSERVO;
        private DIAccessor _diSTEP;






        private DIAccessor _diClampOnCylinder;
        private DIAccessor _diClampOffCylinder;
        private DIAccessor _diLatchOnCylinder;
        private DIAccessor _diLatchOffCylinder;
        private DIAccessor _diDoorOpenCylinder;
        private DIAccessor _diDoorCloseCylinder;
        private DIAccessor _diSERVOCLEAR1;
        private DIAccessor _diSERVOON1;
        private DIAccessor _diD3UBIN;
        private DIAccessor _diMapForwardCylinder;
        private DIAccessor _diSERVOCLEAR2;
        private DIAccessor _diSERVOON2;
        private DIAccessor _diSERVOCLCOUNT;
        private DIAccessor _diVAC;
        private DIAccessor _diSERVOBRAKE;

        private DIAccessor _diLoadLight;
        private DIAccessor _diUnloadLight;
        private DIAccessor _diPOWERLIGHT;
        private DIAccessor _diFoupPlacementLight;
        private DIAccessor _diFoupPresenceLight;
        private DIAccessor _diAlarmOccurLight;
        private DIAccessor _diStatu1Light;
        private DIAccessor _diStatu2Light;

        private IoSensor _diIronCassetteDoorClose;
        public IoSensor DiIronCassetteDoorClose 
        {
            get => _diIronCassetteDoorClose;
            set
            {
                _diIronCassetteDoorClose = value;
                _diIronCassetteDoorClose.OnSignalChanged += _diIronCassetteDoorClose_OnSignalChanged;
            } 
        }

        private void _diIronCassetteDoorClose_OnSignalChanged(IoSensor arg1, bool arg2)
        {
            if (!IsPlacement || !IsMapped) return;
            if (arg2) return;
            if (_diIronCassetteDoorClose.Value) return;
            if (!_diDockHomeSensor.Value) return;
            if (!IsReady()) return;
            Unclamp(out _);
        }        

        private DateTime _actionStartTime;
        private int _actionTimeLimit;

        protected R_TRIG _carrierArrived;
        protected R_TRIG _errorOccurredTrig;
        protected R_TRIG _lastErrorOccurredTrig;

        protected R_TRIG _alarmWaferProtrudeTrig;

        private int _errorCode = 0;
        private int _lastErrorCode = 0;

        public override string ErrorCode 
        {
            get => _aiErrorCode.Value.ToString();
         }

        public TDKMode Mode { get; set; } = TDKMode.Online;
        public TDKInitPosMovement InitPosMovement { get; set; }
        public TDKOperationStatus OperationStatus { get; set; }
        public TDKContainerStatus ContainerStatus 
        {
            get 
            { 
                if (_isPlaced && _isPresent)
                    return TDKContainerStatus.NormalMount;
                if (!_isPlaced && !_isPresent)
                    return TDKContainerStatus.Absence;
                return TDKContainerStatus.MountError;
            }
        }
        public TDKPosition ClampPosition
        {
            get
            {
                if (_diClampOffSensor.Value && !_diClampOnCylinder.Value)
                    return TDKPosition.Open;
                if (!_diClampOffSensor.Value && _diClampOnCylinder.Value)
                    return TDKPosition.Close;
                return TDKPosition.TBD;
            }
        }
        public TDKPosition LPDoorLatchPosition
        {
            get
            {
                if (_diLatchLockSensor.Value && !_diLatchUnlockSensor.Value)
                    return TDKPosition.Close;
                if (!_diLatchLockSensor.Value && _diLatchUnlockSensor.Value)
                    return TDKPosition.Open;
                return TDKPosition.TBD;
            }
        }
        public TDKVacummStatus VacuumStatus 
        {
            get
            {
                if (_diVACSensor.Value)
                    return TDKVacummStatus.ON;
                return TDKVacummStatus.OFF;
            }
        }
        public TDKPosition LPDoorState 
        {
            get
            {
                if (_diDoorOpenSensor.Value && !_diDoorCloseSensor.Value)
                    return TDKPosition.Open;
                if(!_diDoorOpenSensor.Value && _diDoorCloseSensor.Value)
                    return TDKPosition.Close;
                return TDKPosition.TBD;
            }
        }

        

        public TDKWaferProtrusion WaferProtrusion 
        {
            get
            {
                if (!_diProtrudesensor.Value)
                    return TDKWaferProtrusion.ShadingStatus;
                return TDKWaferProtrusion.LightIncidentStatus;
            }
        }
        public TDKElevatorAxisPosition ElevatorAxisPosition 
        { 
            get
            {
                if (_diVerticalDownSensor.Value)
                    return TDKElevatorAxisPosition.Down;
                if (_diAck_ZtoMapEnd.Value)
                    return TDKElevatorAxisPosition.MappingStartPos;
                if (_diAck_ZtoMapStart.Value)
                    return TDKElevatorAxisPosition.MappingEndPos;
                return TDKElevatorAxisPosition.TBD;
            }
        }
        public TDKDockPosition DockPosition 
        { 
            get
            {
                if (_diDockHomeSensor.Value && !_diPodForwardSensor.Value)
                    return TDKDockPosition.Undock;
                if (!_diDockHomeSensor.Value && _diPodForwardSensor.Value)
                    return TDKDockPosition.Dock;
                return TDKDockPosition.TBD;
            }                
        }
        public TDKMapPosition MapperPostion
        {
            get => TDKMapPosition.TBD;
         }
        public TDKMappingStatus MappingStatus { get; set; } = TDKMappingStatus.NormalEnd;

        public TDKModel Model { get; set; }

        public CarrierMode LPCarrierMode
        {
            get
            {
                if(SC.ContainsItem($"CarrierInfo.CarrierFosbMode{InfoPadCarrierIndex}"))
                {
                    int intvalue = SC.GetValue<int>($"CarrierInfo.CarrierFosbMode{InfoPadCarrierIndex}");
                    if (intvalue == 0)
                        return CarrierMode.Foup;
                    if (intvalue == 1)
                        return CarrierMode.Fosb;
                    if (intvalue == 2)
                        return CarrierMode.OpenCassette;
                }
                return CarrierMode.Foup;
            }
        }
        public override bool IsWaferProtrude
        { 
            get 
            {
                //_alarmWaferProtrudeTrig.CLK = !_diProtrudesensor.Value;
                //if(_alarmWaferProtrudeTrig.Q)
                //{
                //    EV.Notify(AlarmLoadPortWaferProtrusion);
                //}
                return (!_diProtrudesensor.Value);
            }
            
        }

        public override bool IsEnableLoad(out string reason)
        {
            //if(IsWaferProtrude)
            //{
            //    reason = "Wafer Protrusion";
            //    return false;
            //}
            if(SC.ContainsItem($"CarrierInfo.NeedCheckIronDoorCarrier{InfoPadCarrierIndex}") &&
            (SC.GetValue<bool>($"CarrierInfo.NeedCheckIronDoorCarrier{InfoPadCarrierIndex}")))
            {
                if(DiIronCassetteDoorClose!=null && !DiIronCassetteDoorClose.Value)
                {
                    reason = "Iron Door Closed";
                    return false;
                }                
            }

            return base.IsEnableLoad(out reason);
        }
        public override bool IsEnableMapWafer(out string reason)
        {
            if (IsWaferProtrude)
            {
                reason = "Wafer Protrusion";
                return false;
            }
            if (SC.ContainsItem($"CarrierInfo.NeedCheckIronDoorCarrier{InfoPadCarrierIndex}") &&
            (SC.GetValue<bool>($"CarrierInfo.NeedCheckIronDoorCarrier{InfoPadCarrierIndex}")))
            {
                if (DiIronCassetteDoorClose != null && !DiIronCassetteDoorClose.Value)
                {
                    reason = "Iron Door Closed";
                    return false;
                }
            }

            return base.IsEnableMapWafer(out reason);
        }
        public override bool IsEnableTransferWafer(out string reason)
        {  
            if(!IsLoaded)
            {
                reason = "Carrier Is not loaded";
                return false;
            }
            if(!IsMapped)
            {
                reason = "Not Mapped";
                return false;
            }
            if(!IsReady())
            {
                reason = "Not Ready";
                return false;
            }

            if (IsWaferProtrude)
            {
                EV.Notify(AlarmLoadPortWaferProtrusion);
                OnError("Wafer Protrusion");
                reason = "Wafer Protrusion";
                return false;
            }           

            if (SC.ContainsItem($"CarrierInfo.NeedCheckIronDoorCarrier{InfoPadCarrierIndex}") &&
            (SC.GetValue<bool>($"CarrierInfo.NeedCheckIronDoorCarrier{InfoPadCarrierIndex}")))
            {
                if (DiIronCassetteDoorClose != null && !DiIronCassetteDoorClose.Value)
                {
                    reason = "Iron Door Closed";
                    return false;
                }
            }
            if(ErrorCode !="0")
            {
                reason = "ErrorCode is " + ErrorCode;
                return false;
            }
            if (IsVerifyPreDefineWaferCount && WaferCount != PreDefineWaferCount)
            {
                reason = "Mapping Error:WaferCount not matched";
                return false;
            }

            return base.IsEnableTransferWafer(out reason);
        }
       

        public override FoupClampState ClampState
        {
            get
            {
                if (_diClampOffSensor.Value && !_diClampOnCylinder.Value)
                    return FoupClampState.Open;
                if (!_diClampOffSensor.Value && _diClampOnCylinder.Value)
                    return FoupClampState.Close;
                return FoupClampState.Unknown;
            }
        }
        public override FoupDockState DockState
        {
            get
            {
                if(_diDockHomeSensor.Value && !_diPodForwardSensor.Value)
                    return FoupDockState.Undocked;
                if(!_diDockHomeSensor.Value && _diPodForwardSensor.Value)
                    return FoupDockState.Docked;
                return FoupDockState.Unknown;
            }
        }

        public override LoadportCassetteState CassetteState
        {
            get
            {
                if (_isPlaced && _isPresent)
                    return LoadportCassetteState.Normal;
                if (!_isPlaced)
                    return LoadportCassetteState.Absent;
                return LoadportCassetteState.Unknown;
            }
        }
        public override FoupDoorState DoorState
        {
            get
            {
                if (LPDoorState == TDKPosition.Close)
                    return FoupDoorState.Close;
                if (LPDoorState == TDKPosition.Open)
                    return FoupDoorState.Open;
                return FoupDoorState.Unknown;
            }
        }

        public override FoupDoorPostionEnum DoorPosition 
        { 
            get
            {
                if (_diVerticalDownSensor.Value && !_diVerticalMiddleSensor.Value)
                    return FoupDoorPostionEnum.Down;
                if (!_diAck_ZtoMapEnd.Value && !_diVerticalMiddleSensor.Value)
                    return FoupDoorPostionEnum.Unknown;
                return FoupDoorPostionEnum.Unknown;
            }
        }


        public override bool IsVacuumON
        {
            get
            {
                return _diVACSensor.Value;
            }
        }

        public override WaferSize GetCurrentWaferSize()
        {
            int intvalue = SC.GetValue<int>($"CarrierInfo.CarrierWaferSize{InfoPadCarrierIndex}");
            if (intvalue == 8)
                return WaferSize.WS8;
            if (intvalue == 12)
                return WaferSize.WS12;
            return WaferSize.WS0;
            
            
        }
        public override int InfoPadCarrierIndex 
        {
            get
            {
                if (IsAutoDetectCarrierType)
                {

                    return (_diInfoPadA.Value ? 8 : 0) + (_diInfoPadB.Value ? 4 : 0) +
                        (_diInfoPadC.Value ? 2 : 0) + (_diInfoPadD.Value ? 1 : 0);
                }
                return base.InfoPadCarrierIndex;
            }
            set
            {
                base.InfoPadCarrierIndex = value;
            }
        }

        public override bool IsVerifyPreDefineWaferCount
        {
            get
            {
                if (SC.ContainsItem($"LoadPort.{LPModuleName}.IsVerifyPreDefineWaferCount"))
                    return SC.GetValue<bool>($"LoadPort.{LPModuleName}.IsVerifyPreDefineWaferCount");
                return false;
            }
        }
        private bool OnTimer()
        {
            try
            {
                _errorOccurredTrig.CLK = (int)_aiErrorCode.Value != _errorCode;
                _errorCode = (int)_aiErrorCode.Value;

                _lastErrorOccurredTrig.CLK = (int)_aiLastErrorCode.Value != _lastErrorCode;
                _lastErrorCode = (int)_aiLastErrorCode.Value;
               

                if(_errorOccurredTrig.Q && _errorCode >0)
                {
                    if (AlarmNcdLoadPortErrors.Length >= _errorCode - 1000)
                    {
                        EV.Notify(AlarmNcdLoadPortErrors[_errorCode - 1001]);
                        OnError(AlarmNcdLoadPortErrors[_errorCode - 1001]);
                    }
                }
                if(_lastErrorOccurredTrig.Q && _lastErrorCode>0)
                {
                    if (AlarmNcdLoadPortLastErrors.Length > _lastErrorCode - 1000)
                    {
                        EV.Notify(AlarmNcdLoadPortLastErrors[_lastErrorCode - 1001]);
                        OnError(AlarmNcdLoadPortLastErrors[_errorCode - 1001]);
                    }
                }




                _isPresent = _diSensor_Presence.Value;
                _isPlaced = _diSensor_Placement.Value;
                SetPresent(_isPresent);

                SetPlaced(_diSensor_Placement.Value);   

                _carrierArrived.CLK = _diSensor_Placement.Value;                

                if (_isPlaced)
                {
                    if (SC.ContainsItem($"CarrierInfo.CarrierName{InfoPadCarrierIndex}"))
                        SpecCarrierType = SC.GetStringValue($"CarrierInfo.CarrierName{InfoPadCarrierIndex}");

                }
                else
                    SpecCarrierType = "";

                if (_carrierArrived.Q)
                {
                    CheckAndLoadRecipe();
                }

                






            }
            catch(Exception ex)
            {
                LOG.Write(ex);
            }


            return true;
        }
        private bool CheckAndLoadRecipe()
        {
            int intRecipeNo = SC.GetValue<int>($"CarrierInfo.CarrierRecipeNumber{InfoPadCarrierIndex}");
            int timelimit = SC.ContainsItem($"LoadPort.{Name}.TimeLimitAction") ?
                SC.GetValue<int>($"LoadPort.{Name}.TimeLimitAction") : 45;

            if (_aiRECIPE_TYPE_FEEDBACK.Value == intRecipeNo)
                return true;

            if (_doRecipeLoadCommand.Value)
            {
                _doRecipeLoadCommand.SetValue(false, out _);
                Thread.Sleep(1000);
            }
            _aoSAVECurrentRecipeNumber.Value = (short)intRecipeNo;
            Thread.Sleep(200);
            _doRecipeLoadCommand.SetValue(true, out _);
            DateTime _stTime = DateTime.Now;
            while(!_diAck_RecipeLoad.Value || _aiRECIPE_TYPE_FEEDBACK.Value != intRecipeNo)
            {
                if (DateTime.Now - _stTime > TimeSpan.FromSeconds(timelimit))
                {                    
                    _doRecipeLoadCommand.SetValue(false, out _);
                    EV.Notify($"{LPModuleName}LoadRecipeFailed");
                    OnError($"{LPModuleName}LoadRecipeFailed");
                    return false;
                }
            }
            _doRecipeLoadCommand.SetValue(false, out _);
            _stTime = DateTime.Now;
            while (_diAck_RecipeLoad.Value)
            {
                if (DateTime.Now - _stTime > TimeSpan.FromSeconds(timelimit))
                {
                    _doRecipeLoadCommand.SetValue(false, out _);
                    EV.Notify($"{LPModuleName}LoadRecipeFailed");
                    OnError($"{LPModuleName}LoadRecipeFailed");
                    return false;
                }
            }
            return true;

        }



        protected override bool fStartInit(object[] param)
        {
            ResetRoutine();
            _actionTimeLimit = SC.ContainsItem($"LoadPort.{Name}.TimeLimitLoadportHome") ?
                SC.GetValue<int>($"LoadPort.{Name}.TimeLimitLoadportHome") : 45;

            //if(!_diProtrudesensor.Value)
            //{
            //    EV.Notify(AlarmLoadPortWaferProtrusion);
            //    return false;
            //}
            return true;


            //_actionStartTime = DateTime.Now;



            //if (!CheckAndLoadRecipe())
            //    return false;
            //return _doIntialCommand.SetValue(true, out _);

        }

        protected override bool fMonitorInit(object[] param)
        {
            IsBusy = false;
            int intRecipeNo = SC.GetValue<int>($"CarrierInfo.CarrierRecipeNumber{InfoPadCarrierIndex}");

            try
            {
                SetAoValue((int)LoadPortStepEnum.LoadRecipe1, _aoSAVECurrentRecipeNumber, (short)intRecipeNo, Notify);
                SetDoState((int)LoadPortStepEnum.LoadRecipe2, _doRecipeLoadCommand, true, Notify);
                WaitDiState((int)LoadPortStepEnum.LoadRecipe3, _actionTimeLimit, _diAck_RecipeLoad, true, Notify, Stop);
                WaitAiValue((int)LoadPortStepEnum.LoadRecipe4, _actionTimeLimit, _aiRECIPE_TYPE_FEEDBACK, (short)intRecipeNo, Notify, Stop);
                SetDoState((int)LoadPortStepEnum.LoadRecipe5, _doRecipeLoadCommand, false, Notify);
                WaitDiState((int)LoadPortStepEnum.LoadRecipe6, _actionTimeLimit, _diAck_RecipeLoad, false, Notify, Stop);

                SetDoState((int)LoadPortStepEnum.ActionStep1, _doIntialCommand, true, Notify);
                WaitDiState((int)LoadPortStepEnum.ActionStep2, _actionTimeLimit, _diAck_Init, true, Notify, Stop);
                SetDoState((int)LoadPortStepEnum.ActionStep3, _doIntialCommand, false, Notify);
                WaitDiState((int)LoadPortStepEnum.ActionStep4, _actionTimeLimit, _diAck_Init, false, Notify, Stop);



            }
            catch (RoutineBreakException)
            {
                return false;
            }
            catch (RoutineFaildException)
            {
                EV.Notify(AlarmLoadPortHomeTimeout);
                OnError("Home failed");
                return true;
            }
            OnHomed();
            return true;



        }


        

        protected override bool fStartLoad(object[] param)
        {
            _actionTimeLimit = SC.ContainsItem($"LoadPort.{Name}.TimeLimitLoadportLoad") ?
                SC.GetValue<int>($"LoadPort.{Name}.TimeLimitLoadportLoad") : 45;

            ResetRoutine();
            if (param == null || param.Length == 0)
            {
                _doMapEnableCommand.SetValue(true, out _);
                _doMapDisableCommand.SetValue(false, out _);
                _currentloadCommand = "LoadWithMap";
            }
            if (param.Length >= 1 && param[0].ToString() == "LoadWithMap")
            {
                _doMapEnableCommand.SetValue(true, out _);
                _doMapDisableCommand.SetValue(false, out _);
                _currentloadCommand = "LoadWithMap";

            }
            if (param.Length >= 1 && param[0].ToString() == "LoadWithoutMap")
            {
                _doMapEnableCommand.SetValue(false, out _);
                _doMapDisableCommand.SetValue(true, out _);
                _currentloadCommand = "LoadWithoutMap";
            }
            if (param.Length >= 1 && param[0].ToString() == "LoadWithCloseDoor")
            {
                _doMapEnableCommand.SetValue(true, out _);
                _doMapDisableCommand.SetValue(false, out _);
                _currentloadCommand = "LoadWithCloseDoor";
            }
            if (param.Length >= 1 && param[0].ToString() == "LoadWithoutMapWithCloseDoor")
            {
                _doMapEnableCommand.SetValue(false, out _);
                _doMapDisableCommand.SetValue(true, out _);
                _currentloadCommand = "LoadWithoutMapWithCloseDoor";
            }
            _isNeedLoadRecipe = _aiRECIPE_TYPE_FEEDBACK.Value != 
                (short)SC.GetValue<int>($"CarrierInfo.CarrierRecipeNumber{InfoPadCarrierIndex}");
            return true;
        }
        private string _currentloadCommand = "";
        private bool _isNeedLoadRecipe;
        protected override bool fMonitorLoad(object[] param)
        {
            IsBusy = false;

            try
            {
                int intRecipeNo = SC.GetValue<int>($"CarrierInfo.CarrierRecipeNumber{InfoPadCarrierIndex}");


                if (_isNeedLoadRecipe)
                {
                    SetAoValue((int)LoadPortStepEnum.LoadRecipe1, _aoSAVECurrentRecipeNumber, (short)intRecipeNo, Notify);
                    SetDoState((int)LoadPortStepEnum.LoadRecipe2, _doRecipeLoadCommand, true, Notify);
                    WaitDiState((int)LoadPortStepEnum.LoadRecipe3, _actionTimeLimit, _diAck_RecipeLoad, true, Notify, Stop);
                    WaitAiValue((int)LoadPortStepEnum.LoadRecipe4, _actionTimeLimit, _aiRECIPE_TYPE_FEEDBACK, (short)intRecipeNo, Notify, Stop);
                    SetDoState((int)LoadPortStepEnum.LoadRecipe5, _doRecipeLoadCommand, false, Notify);
                    WaitDiState((int)LoadPortStepEnum.LoadRecipe6, _actionTimeLimit, _diAck_RecipeLoad, false, Notify, Stop);
                }

                SetDoState((int)LoadPortStepEnum.ActionStep1, _doLoadCommand, true, Notify);
                WaitDiState((int)LoadPortStepEnum.ActionStep2, _actionTimeLimit, _diAck_Load, true, Notify, Stop);
                SetDoState((int)LoadPortStepEnum.ActionStep3, _doLoadCommand, false, Notify);
                WaitDiState((int)LoadPortStepEnum.ActionStep4, _actionTimeLimit, _diAck_Load, false, Notify, Stop);

                if(_currentloadCommand == "LoadWithCloseDoor")
                {
                    SetDoState((int)LoadPortStepEnum.ActionStep5, _doVertiaclUpCommand, true, Notify);
                    WaitDiState((int)LoadPortStepEnum.ActionStep6, _actionTimeLimit, _diAck_VerticalUp, true, Notify, Stop);
                    SetDoState((int)LoadPortStepEnum.ActionStep7, _doVertiaclUpCommand, false, Notify);
                    WaitDiState((int)LoadPortStepEnum.ActionStep8, _actionTimeLimit, _diAck_VerticalUp, false, Notify, Stop);

                    SetDoState((int)LoadPortStepEnum.ActionStep9, _doVertiaclUpCommand, true, Notify);
                    WaitDiState((int)LoadPortStepEnum.ActionStep10, _actionTimeLimit, _diAck_VerticalUp, true, Notify, Stop);
                    SetDoState((int)LoadPortStepEnum.ActionStep11, _doVertiaclUpCommand, false, Notify);
                    WaitDiState((int)LoadPortStepEnum.ActionStep12, _actionTimeLimit, _diAck_VerticalUp, false, Notify, Stop);

                    SetDoState((int)LoadPortStepEnum.ActionStep13, _doDoorCloseCommand, true, Notify);
                    WaitDiState((int)LoadPortStepEnum.ActionStep14, _actionTimeLimit, _diAck_DoorClose, true, Notify, Stop);
                    SetDoState((int)LoadPortStepEnum.ActionStep15, _doDoorCloseCommand, false, Notify);
                    WaitDiState((int)LoadPortStepEnum.ActionStep16, _actionTimeLimit, _diAck_DoorClose, false, Notify, Stop);

                }
            }

            catch (RoutineBreakException)
            {
                return false;
            }
            catch (RoutineFaildException)
            {
                EV.Notify(AlarmLoadPortLoadTimeOut);
                OnError("LoadFailed");
                return true;
            }
            OnLoaded();
            if(_currentloadCommand == "LoadWithMap" || _currentloadCommand == "LoadWithCloseDoor")
            {
                ReadSlotMap();
            }
            return true;











            //if (DateTime.Now - _actionStartTime > TimeSpan.FromSeconds(timelimit))
            //{
            //    _doLoadCommand.SetValue(false, out _);
            //    OnError("Load timeout");
            //    return false;
            //}
           


            //if (_diAck_Load.Value && _diPodForwardSensor.Value && _diDoorOpenSensor.Value && _diVerticalDownSensor.Value)
            //{
            //    _doLoadCommand.SetValue(false, out _);
            //    switch (_currentloadCommand)
            //    {
            //        case "LoadWithMap":
            //            //if (!IsMapped)
            //                ReadSlotMap();
            //            return true;
            //        case "LoadWithCloseDoor":
            //            if (!_diAck_VerticalUp.Value || _diVerticalDownSensor.Value)
            //            {
            //                _doVertiaclUpCommand.SetValue(true, out _);
            //                _doVertiaclDownCommand.SetValue(false, out _);
            //            }
            //            if(_diAck_VerticalUp.Value && !_diVerticalDownSensor.Value)
            //            {
            //                _doVertiaclUpCommand.SetValue(false, out _);
            //                _doVertiaclDownCommand.SetValue(false, out _);

            //                _doDoorOpenCommand.SetValue(false, out _);
            //                _doDoorCloseCommand.SetValue(true, out _);
            //            }

            //            if(!_diVerticalDownSensor.Value && _diAck_DoorClose.Value && _diDoorCloseSensor.Value)
            //            {
            //                _doDoorOpenCommand.SetValue(false, out _);
            //                _doDoorCloseCommand.SetValue(false, out _);
            //                ReadSlotMap();
            //                return true;
            //            }
            //            break;
            //        default:
            //            break;
            //    }
            //    _doLoadCommand.SetValue(false, out _);
            //    return true;
            //}
            //return base.fMonitorLoad(param);
        }

        protected override bool fMonitorTransferBlock(object[] param)
        {
            if (!_isPlaced)
            {
                OnError("Placement Error");
                return false;
            }
            return base.fMonitorTransferBlock(param);
        }
        private void ReadSlotMap()
        {
            string strslotmap = "";
            AIAccessor[] ais = new AIAccessor[]
            {
               _aiSlot25MapResult,_aiSlot24MapResult,_aiSlot23MapResult,_aiSlot22MapResult ,_aiSlot21MapResult,
               _aiSlot20MapResult,_aiSlot19MapResult, _aiSlot18MapResult, _aiSlot17MapResult ,_aiSlot16MapResult,
               _aiSlot15MapResult,_aiSlot14MapResult,_aiSlot13MapResult,_aiSlot12MapResult ,_aiSlot11MapResult,
               _aiSlot10MapResult,_aiSlot9MapResult,_aiSlot8MapResult,_aiSlot7MapResult ,_aiSlot6MapResult,
               _aiSlot5MapResult,_aiSlot4MapResult,_aiSlot3MapResult,_aiSlot2MapResult,_aiSlot1MapResult,
            };
            WaferCount = 0;
            for(int i=25-ValidSlotsNumber; i<25;i++)
            {
                strslotmap = strslotmap + ais[i].Value.ToString("D1");
                if (ais[i].Value != 0)
                    WaferCount++;
            }

            if(IsVerifyPreDefineWaferCount)
            {
                if(WaferCount != PreDefineWaferCount)
                {
                    EV.PostAlarmLog("LoadPort", $"{LPModuleName} mapping error,predefine _count is {PreDefineWaferCount}, " +
                        $"Mapping result is {WaferCount}.");
                    OnError("Mapping Error");
                }
            }
            OnSlotMapRead(strslotmap);
        }

        protected override bool fStartRead(object[] param)
        {
            return true;
        }

        protected override bool fStartReset(object[] param)
        {
            if(!_doResetCommand.Value)
            {
                _doResetCommand.SetValue(true, out _);
            }
            else
            {
                _doResetCommand.SetValue(false, out _);
                Thread.Sleep(1000);
                _doResetCommand.SetValue(true, out _);                
            }
            _doLoadCommand.SetValue(false, out _);
            _doUnloadCommand.SetValue(false, out _);
            _actionStartTime = DateTime.Now;
            return true;
        }


        protected override bool fMonitorReset(object[] param)
        {
            IsBusy = false;
            if(DateTime.Now - _actionStartTime>TimeSpan.FromSeconds(10))
            {
                OnError("Reset Timeout");
                _doResetCommand.SetValue(false, out _);
                return false;
            }

            if(_diAck_Reset.Value)
            {
                _doResetCommand.SetValue(false, out _);
                _errorCode = 0;
                _lastErrorCode = 0;
                return true;
            }
            return false;

        }
        
        protected override bool fStartUnload(object[] param)
        {
            _actionTimeLimit = SC.ContainsItem($"LoadPort.{Name}.TimeLimitLoadportUnload") ?
                SC.GetValue<int>($"LoadPort.{Name}.TimeLimitLoadportUnload") : 45;

            ResetRoutine();

            _isNeedLoadRecipe = _aiRECIPE_TYPE_FEEDBACK.Value !=
                (short)SC.GetValue<int>($"CarrierInfo.CarrierRecipeNumber{InfoPadCarrierIndex}");
            return true;
        }

        public override int ValidSlotsNumber
        {
            get
            {
                if (SC.ContainsItem($"CarrierInfo.CarrierSlotsNumber{InfoPadCarrierIndex}"))
                    return SC.GetValue<int>($"CarrierInfo.CarrierSlotsNumber{InfoPadCarrierIndex}");
                return 25;
            }
        }


        protected override bool fMonitorUnload(object[] param)
        {
            IsBusy = false;
            try
            {
                int intRecipeNo = SC.GetValue<int>($"CarrierInfo.CarrierRecipeNumber{InfoPadCarrierIndex}");
                if (_isNeedLoadRecipe)
                {
                    SetAoValue((int)LoadPortStepEnum.LoadRecipe1, _aoSAVECurrentRecipeNumber, (short)intRecipeNo, Notify);
                    SetDoState((int)LoadPortStepEnum.LoadRecipe2, _doRecipeLoadCommand, true, Notify);
                    WaitDiState((int)LoadPortStepEnum.LoadRecipe3, _actionTimeLimit, _diAck_RecipeLoad, true, Notify, Stop);
                    WaitAiValue((int)LoadPortStepEnum.LoadRecipe4, _actionTimeLimit, _aiRECIPE_TYPE_FEEDBACK, (short)intRecipeNo, Notify, Stop);
                    SetDoState((int)LoadPortStepEnum.LoadRecipe5, _doRecipeLoadCommand, false, Notify);
                    WaitDiState((int)LoadPortStepEnum.LoadRecipe6, _actionTimeLimit, _diAck_RecipeLoad, false, Notify, Stop);
                }
                SetDoState((int)LoadPortStepEnum.ActionStep1, _doUnloadCommand, true, Notify);
                WaitDiState((int)LoadPortStepEnum.ActionStep2, _actionTimeLimit, _diAck_Unload, true, Notify, Stop);
                SetDoState((int)LoadPortStepEnum.ActionStep3, _doUnloadCommand, false, Notify);
                WaitDiState((int)LoadPortStepEnum.ActionStep4, _actionTimeLimit, _diAck_Unload, false, Notify, Stop);      
                
                if(SC.ContainsItem($"CarrierInfo.KeepClampedAfterUnloadCarrier{InfoPadCarrierIndex}") &&
                    SC.GetValue<bool>($"CarrierInfo.KeepClampedAfterUnloadCarrier{InfoPadCarrierIndex}"))
                {
                    SetDoState((int)LoadPortStepEnum.ActionStep5, _doClampOnCommand, true, Notify);
                    WaitDiState((int)LoadPortStepEnum.ActionStep6, _actionTimeLimit, _diAck_ClampOn, true, Notify, Stop);
                    SetDoState((int)LoadPortStepEnum.ActionStep7, _doClampOnCommand, false, Notify);
                    WaitDiState((int)LoadPortStepEnum.ActionStep8, _actionTimeLimit, _diAck_ClampOn, false, Notify, Stop);
                }
                else
                {
                    base.OnUnloaded();
                }
               

            }

            catch (RoutineBreakException)
            {
                return false;
            }
            catch (RoutineFaildException)
            {
                EV.Notify(AlarmLoadPortUnloadTimeOut);
                OnError("UnloadFailed");
                return true;
            }
         
            return true;



        }

        protected override bool fStartWrite(object[] param)
        {
            return true;
        }

        protected override bool fStartExecute(object[] param)
        {
            if (!CheckAndLoadRecipe())
                return false;
            _actionStartTime = DateTime.Now;
            try
            {
                switch (param[0].ToString())
                {
                    case "SetIndicator":
                        _currentExecuteCommand = "SetIndicator";
                        Indicator light = (Indicator)param[1];
                        IndicatorState state = (IndicatorState)param[2];
                        switch(light)
                        {
                            case Indicator.LOAD:
                                if (state == IndicatorState.BLINK || state == IndicatorState.ON)
                                    _doLoadLight.SetValue(true, out _);
                                if (state == IndicatorState.OFF)
                                    _doLoadLight.SetValue(false, out _);
                                break;
                            case Indicator.UNLOAD:
                                if (state == IndicatorState.BLINK || state == IndicatorState.ON)
                                    _doUnloadLight.SetValue(true, out _);
                                if (state == IndicatorState.OFF)
                                    _doUnloadLight.SetValue(false, out _);
                                break;

                            case Indicator.ACCESSAUTO:
                                if (state == IndicatorState.BLINK || state == IndicatorState.ON)
                                    _doStatu1Light.SetValue(true, out _);
                                if (state == IndicatorState.OFF)
                                    _doStatu1Light.SetValue(false, out _);
                                break;
                            case Indicator.ACCESSMANUL:
                                if (state == IndicatorState.BLINK || state == IndicatorState.ON)
                                    _doStatu2Light.SetValue(true, out _);
                                if (state == IndicatorState.OFF)
                                    _doStatu2Light.SetValue(false, out _);
                                break;
                        }
                        break;

                    case "QueryIndicator":
                        break;
                    case "QueryState":
                        _currentExecuteCommand = "QueryState";
                        break;
                    case "Undock":
                        _currentExecuteCommand = "Undock";
                        _doDOCKHomeCommand.SetValue(true, out _);
                        _doDOCKForwardCommand.SetValue(false, out _);                        
                        break;
                    case "Dock":
                        _currentExecuteCommand = "Dock";
                        _doDOCKHomeCommand.SetValue(false, out _);
                        _doDOCKForwardCommand.SetValue(true, out _);
                        break;
                    case "CloseDoor":
                        _currentExecuteCommand = "CloseDoor";
                        _doDoorOpenCommand.SetValue(false, out _);
                        _doDoorCloseCommand.SetValue(true, out _);
                        break;
                    case "OpenDoor":
                        _currentExecuteCommand = "CloseDoor";
                        _doDoorOpenCommand.SetValue(true, out _);
                        _doDoorCloseCommand.SetValue(false, out _);
                        break;
                    case "Unclamp":
                        _currentExecuteCommand = "Unclamp";
                        _doClampOffCommand.SetValue(true, out _);
                        _doClampOnCommand.SetValue(false, out _);
                        break;
                    case "Clamp":
                        _currentExecuteCommand = "Clamp";
                        _doClampOffCommand.SetValue(false, out _);
                        _doClampOnCommand.SetValue(true, out _);
                        break;
                    case "DoorUp":
                        _currentExecuteCommand = "DoorUp";
                        _doVertiaclDownCommand.SetValue(false, out _);
                        _doVertiaclUpCommand.SetValue(true, out _);
                        break;
                    case "DoorDown":
                        _currentExecuteCommand = "DoorDown";
                        _doVertiaclDownCommand.SetValue(true, out _);
                        _doVertiaclUpCommand.SetValue(false, out _);
                        break;
                        
                    case "MapWafer":
                        //_currentExecuteCommand = "MapWafer";
                        //_doZtoMAPPINGSTARTPOSI.SetValue(true, out _);
                        break;
                    case "DoorUpAndClose":
                        _currentExecuteCommand = "DoorUpAndClose";
                        _doVertiaclUpCommand.SetValue(true, out _);
                        break;

                    case "OpenDoorAndDown":
                        _currentExecuteCommand = "DoorUpAndClose";
                        _doDoorOpenCommand.SetValue(true, out _);
                        break;
                        
                    case "Move":
                        HandlerMoveCommand(param[1].ToString());
                        break;
                    case "Set":
                        
                        break;
                    case "Get":
                       
                        break;
                }
                return true;
            }
            catch (Exception ex)
            {
                LOG.Write(ex);
                EV.PostAlarmLog(Name, $"Parameter invalid");
                return false;

            }
        }

        private void HandlerMoveCommand(string movecommand)
        {
            
            switch(movecommand)
            {
                case "PODCL":
                    _currentExecuteCommand = "Clamp";
                    _doClampOffCommand.SetValue(false, out _);
                    _doClampOnCommand.SetValue(true, out _);
                    break;
                case "YDOOR":
                    _currentExecuteCommand = "Dock";
                    _doDOCKHomeCommand.SetValue(false, out _);
                    _doDOCKForwardCommand.SetValue(true, out _);
                    break;
                case "VACON":
                    _currentExecuteCommand = "VacuumOn";
                    _doVACOnCommand.SetValue(true, out _);
                    _doVACOffCommand.SetValue(false, out _);
                    break;
                case "DOROP":
                    _currentExecuteCommand = "UnlatchDoor";
                    _doLatchOffCommand.SetValue(true, out _);
                    _doLatchOnCommand.SetValue(false, out _);
                    break;
                case "ZMPST":
                    _currentExecuteCommand = "MoveToMapStart";
                    _doZtoMAPPINGSTARTPOSI.SetValue(true, out _);
                    _doZtoMAPPINGENDPOSI.SetValue(false, out _);
                    break;
                case "MAPOP":
                    _currentExecuteCommand = "MoveToMapMeasurement";
                    
                    break;
                case "ZDRMP":
                    _currentExecuteCommand = "MoveToMapEnd";
                    _doZtoMAPPINGSTARTPOSI.SetValue(false, out _);
                    _doZtoMAPPINGENDPOSI.SetValue(true, out _);
                    break;
                case "MAPCL":
                    _currentExecuteCommand = "MoveToMapWait";
                    break;
                case "ZDRDW":
                    _currentExecuteCommand = "MoveToLoadPosition";

                    break;
                case "ZDRUP":
                    _currentExecuteCommand = "MoveToDoorOpenClosePostion";
                    _doVertiaclUpCommand.SetValue(true, out _);
                    _doVertiaclDownCommand.SetValue(false, out _);
                    break;
                case "DORFW":
                    _currentExecuteCommand = "CloseDoor";
                    _doDoorCloseCommand.SetValue(true, out _);
                    _doDoorOpenCommand.SetValue(false, out _);
                    break;
                case "DORCL":
                    _currentExecuteCommand = "LatchDoor";
                    _doLatchOnCommand.SetValue(true, out _);
                    _doLatchOffCommand.SetValue(false, out _);
                    break;
                case "VACOF":
                    _currentExecuteCommand = "VacuumOff";
                    _doVACOffCommand.SetValue(true, out _);
                    _doVACOnCommand.SetValue(false, out _);
                    break;
                case "YWAIT":
                    _currentExecuteCommand = "Undock";
                    _doDOCKHomeCommand.SetValue(true, out _);
                    _doDOCKForwardCommand.SetValue(false, out _);
                    break;
                case "PODOP":
                    _currentExecuteCommand = "Unclamp";
                    _doClampOffCommand.SetValue(true, out _);
                    _doClampOnCommand.SetValue(false, out _);
                    break;
                case "ORGSH":
                    _currentExecuteCommand = "ORGSH";
                    _doIntialCommand.SetValue(true, out _);
                    break;
                default:
                    break;

            }
        }

        private string _currentExecuteCommand;

        protected override bool fMonitorExecuting(object[] param)
        {
            IsBusy = false;
            int timelimit = SC.ContainsItem($"LoadPort.{Name}.TimeLimitAction") ?
                SC.GetValue<int>($"LoadPort.{Name}.TimeLimitAction") : 45;
            if (DateTime.Now - _actionStartTime > TimeSpan.FromSeconds(timelimit))
            {
                OnError("Execute command timeout");
                return true;
            }
            switch(_currentExecuteCommand)
            {
                case "SetIndicator":
                    return true;
                case "Clamp":
                    if (_diAck_ClampOn.Value)
                    {
                        _doClampOnCommand.SetValue(false, out _);


                        return true;
                    }
                    break;
                case "Unclamp":
                    if (_diAck_ClampOff.Value)
                    {
                        _doClampOffCommand.SetValue(false, out _);
                        if (_diDockHomeSensor.Value)
                            base.OnUnloaded();
                        return true;
                    }
                    break;
                case "Dock":
                    if (_diAck_DockFwd.Value)
                    {
                        _doDOCKForwardCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "Undock":
                    
                        if (_diAck_DockFwd.Value)
                        {
                        _doDOCKHomeCommand.SetValue(false, out _);
                            return true;
                        }
                    break;
                case "VacuumOn":
                    if(_diAck_VacOn.Value)
                    {
                        _doVACOnCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "VacuumOff":
                    if(_diAck_VacOff.Value)
                    {
                        _doVACOffCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "LatchDoor":
                    if(_diAck_LatchOn.Value)
                    {
                        _doLatchOnCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "UnlatchDoor":
                    if(_diAck_LatchOff.Value)
                    {
                        _doLatchOffCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "OpenDoor":
                    if(_diAck_DoorOpen.Value)
                    {
                        _doDoorOpenCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "CloseDoor":
                    if(_diAck_DoorClose.Value)
                    {
                        _doDoorCloseCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "MoveToDoorOpenClosePostion":
                case "DoorUp":
                    if (_diAck_VerticalUp.Value)
                    {
                        _doVertiaclUpCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "MoveToMapStart":
                    if(_diAck_ZtoMapStart.Value)
                    {
                        _doZtoMAPPINGSTARTPOSI.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "MoveToMapEnd":
                    if(_diAck_ZtoMapEnd.Value)
                    {
                        _doZtoMAPPINGENDPOSI.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "DoorDown":
                    if(_diAck_VerticalDown.Value)
                    {
                        _doVertiaclDownCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                case "ORGSH":
                    if(_diAck_Init.Value)
                    {
                        _doIntialCommand.SetValue(false, out _);
                        return true;
                    }
                    break;
                
                case "MapWafer":
                //if(_diAck_Mapin)
                default:
                    return true;
            }
            return base.fMonitorExecuting(param);
        }

        public override bool SetIndicator(Indicator light, IndicatorState state, out string reason)
        {
            reason = "";
            return fStartExecute(new object[] { "SetIndicator", light, state });
        }

        public DOAccessor ParseDoNode(string name, XmlElement node, string ioModule = "")
        {
            if (!string.IsNullOrEmpty(node.GetAttribute(name).Trim()))
                return IO.DO[string.IsNullOrEmpty(ioModule) ? node.GetAttribute(name).Trim() : $"{ioModule}.{node.GetAttribute(name).Trim()}"];

            return null;
        }

        public DIAccessor ParseDiNode(string name, XmlElement node, string ioModule = "")
        {
            if (!string.IsNullOrEmpty(node.GetAttribute(name).Trim()))
                return IO.DI[string.IsNullOrEmpty(ioModule) ? node.GetAttribute(name).Trim() : $"{ioModule}.{node.GetAttribute(name).Trim()}"];
            return null;
        }

        public AOAccessor ParseAoNode(string name, XmlElement node, string ioModule = "")
        {
            if (!string.IsNullOrEmpty(node.GetAttribute(name).Trim()))
                return IO.AO[string.IsNullOrEmpty(ioModule) ? node.GetAttribute(name).Trim() : $"{ioModule}.{node.GetAttribute(name).Trim()}"];
            return null;
        }

        public AIAccessor ParseAiNode(string name, XmlElement node, string ioModule = "")
        {
            if (!string.IsNullOrEmpty(node.GetAttribute(name).Trim()))
                return IO.AI[string.IsNullOrEmpty(ioModule) ? node.GetAttribute(name).Trim() : $"{ioModule}.{node.GetAttribute(name).Trim()}"];
            return null;
        }
        public SCConfigItem ParseScNode(string name, XmlElement node, string ioModule = "", string defaultScPath = "")
        {
            SCConfigItem result = null;

            if (!string.IsNullOrEmpty(node.GetAttribute(name).Trim()))
                result = SC.GetConfigItem(node.GetAttribute(name));

            if (result == null && !string.IsNullOrEmpty(defaultScPath) && SC.ContainsItem(defaultScPath))
                result = SC.GetConfigItem(defaultScPath);

            return result;
        }

        public static T ParseDeviceNode<T>(string name, XmlElement node) where T : class, IDevice
        {
            if (!string.IsNullOrEmpty(node.GetAttribute(name).Trim()))
                return DEVICE.GetDevice<T>(node.GetAttribute(name));
            LOG.Write(string.Format("{0}，未定义{1}", node.InnerXml, name));
            return null;
        }

        public static T ParseDeviceNode<T>(string module, string name, XmlElement node) where T : class, IDevice
        {
            string device_id = node.GetAttribute(name);
            if (!string.IsNullOrEmpty(device_id) && !string.IsNullOrEmpty(device_id.Trim()))
            {
                return DEVICE.GetDevice<T>($"{module}.{device_id}");
            }
            LOG.Write(string.Format("{0},undefined {1}", node.InnerXml, name));
            return null;
        }
        public enum CarrierMode
        {
            Foup,
            Fosb,
            OpenCassette,
        }

        private void SetAoValue(int id, AOAccessor ao, short value,Action<string> notify)
        {
            var ret = Execute(id, () =>
            {
                notify($"{LPModuleName} set {ao.Name} to {value}.");
                ao.Value = value;
                return true;
            });

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw new RoutineFaildException();
                }
            }
        }
        private void WaitAiValue(int id, int time, AIAccessor ai, short value, Action<string> notify, Action<string> error)
        {
            var ret = ExecuteAndWait(id, () =>
            {
                notify($"Wait {LPModuleName} {ai.Name} to be {value}");
                return true;
            }, () =>
            {
                if (ai.Value == value)
                    return true;

                return false;
            }, time * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw new RoutineFaildException();
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    EV.Notify(AlarmLoadPortError);
                    error($"Wait {LPModuleName} {ai.Name} to be {value} timeout after {time} seconds");
                    throw new RoutineFaildException();
                }
                else
                {
                    throw new RoutineBreakException();
                }
            }
        }
        private void WaitDiState(int id, int time, DIAccessor di,bool state, Action<string> notify, Action<string> error)
        {
            var ret = ExecuteAndWait(id, () =>
            {
                notify($"Wait {LPModuleName} {di.Name} to be {state}");                
                return true;
            }, () =>
            {
                if (di.Value == state)
                    return true;

                return false;
            }, time * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw new RoutineFaildException();
                }
                else if (ret.Item2 == Result.TIMEOUT) //timeout
                {
                    EV.Notify(AlarmLoadPortError);
                    error($"Wait {LPModuleName} {di.Name} to be {state} timeout after {time} seconds");
                    throw new RoutineFaildException();
                }
                else
                {
                    throw new RoutineBreakException();
                }
            }
        }       
        private void SetDoState(int id, DOAccessor _do, bool state, Action<string> notify)
        {
            var ret = Execute(id, () =>
            {
                notify($"{LPModuleName} start set {_do.Name} to {state}.");
                if (_do.Value == state)
                {
                    _do.Value = !state;
                    Thread.Sleep(500);
                }
                return _do.SetValue(state, out _);                
            });

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw new RoutineFaildException();
                }               
            }
        }





        protected void Notify(string message)
        {
            EV.PostMessage(Name, EventEnum.GeneralInfo, string.Format("{0}:{1}", Name, message));
        }
        protected void Stop(string failReason)
        {
            OnError(string.Format("Failed {0}, {1} ", Name, failReason));
        }





        private enum LoadPortStepEnum
        {
            LoadRecipe1,
            LoadRecipe2,
            LoadRecipe3,
            LoadRecipe4,
            LoadRecipe5,
            LoadRecipe6,

            ActionStep1,
            ActionStep2,
            ActionStep3,
            ActionStep4,
            ActionStep5,
            ActionStep6,
            ActionStep7,
            ActionStep8,

            ActionStep9,
            ActionStep10,
            ActionStep11,
            ActionStep12,

            ActionStep13,
            ActionStep14,
            ActionStep15,
            ActionStep16,
        }

        //timer, 计算routine时间
        protected DeviceTimer counter = new DeviceTimer();
        protected DeviceTimer delayTimer = new DeviceTimer();

        private enum STATE
        {
            IDLE,
            WAIT,
        }

        public int TokenId
        {
            get { return _id; }
        }
        private int _id;         //step index

        /// <summary>
        /// already done steps
        /// </summary>
        private Stack<int> _steps = new Stack<int>();

        private STATE state;    //step state //idel,wait,

        //loop control
        private int loop = 0;
        private int loopCount = 0;
        private int loopID = 0;

        private DeviceTimer timer = new DeviceTimer();

        public int LoopCounter { get { return loop; } }
        public int LoopTotalTime { get { return loopCount; } }

        // public int Timeout { get { return (int)(timer.GetTotalTime() / 1000); } }

        //状态持续时间，单位为秒
        public int Elapsed { get { return (int)(timer.GetElapseTime() / 1000); } }

        protected RoutineResult RoutineToken = new RoutineResult() { Result = RoutineState.Running };

        public void ResetRoutine()
        {
            _id = 0;
            _steps.Clear();

            loop = 0;
            loopCount = 0;

            state = STATE.IDLE;
            counter.Start(60 * 60 * 100);   //默认1小时

            RoutineToken.Result = RoutineState.Running;
        }
        protected void PerformRoutineStep(int id, Func<RoutineState> execution, RoutineResult result)
        {
            if (!Acitve(id))
                return;

            result.Result = execution();
        }



        #region interface

        public void StopLoop()
        {
            loop = loopCount;
        }

        public Tuple<bool, Result> Loop<T>(T id, Func<bool> func, int count)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);

            if (bActive)
            {
                if (!func())
                {
                    return Tuple.Create(bActive, Result.FAIL);   //执行错误
                }

                loopID = idx;
                loopCount = count;

                next();
                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }

        public Tuple<bool, Result> EndLoop<T>(T id, Func<bool> func)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);

            if (bActive)
            {
                if (++loop >= loopCount)   //Loop 结束
                {
                    if (!func())
                    {
                        return Tuple.Create(bActive, Result.FAIL);   //执行错误
                    }

                    loop = 0;
                    loopCount = 0;  // Loop 结束时，当前loop和loop总数都清零

                    next();
                    return Tuple.Create(true, Result.RUN);
                }

                //继续下一LOOP

                next(loopID);

                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }

        public Tuple<bool, Result> ExecuteAndWait<T>(T id, IRoutine routine)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);

            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    Result startRet = routine.Start();
                    if (startRet == Result.FAIL)
                    {
                        return Tuple.Create(true, Result.FAIL);   //执行错误
                    }
                    else if (startRet == Result.DONE)
                    {
                        next();
                        return Tuple.Create(true, Result.DONE);
                    }
                    state = STATE.WAIT;
                }

                Result ret = routine.Monitor();

                if (ret == Result.DONE)
                {
                    next();
                    return Tuple.Create(true, Result.DONE);
                }
                else if (ret == Result.FAIL || ret == Result.TIMEOUT)
                {
                    return Tuple.Create(true, Result.FAIL);
                }
                else
                {
                    return Tuple.Create(true, Result.RUN);
                }

            }

            return Tuple.Create(false, Result.RUN);
        }


        public Tuple<bool, Result> ExecuteAndWait<T>(T id, List<IRoutine> routines)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);

            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    foreach (var item in routines)
                    {
                        if (item.Start() == Result.FAIL)
                            return Tuple.Create(true, Result.FAIL);
                    }

                    state = STATE.WAIT;
                }
                //wait all sub failed or completedboo

                bool bFail = false;
                bool bDone = true;

                foreach (var item in routines)
                {
                    Result ret = item.Monitor();

                    bDone &= (ret == Result.FAIL || ret == Result.DONE);
                    bFail |= ret == Result.FAIL;
                }

                if (bDone)
                {
                    next();

                    if (bFail)
                        return Tuple.Create(true, Result.FAIL);

                    return Tuple.Create(true, Result.DONE);
                }
                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }



        public Tuple<bool, Result> Check<T>(T id, Func<bool> func)   //顺序执行
        {
            return Check(Check(Convert.ToInt32(id), func));
        }

        public Tuple<bool, Result> Execute<T>(T id, Func<bool> func)   //顺序执行
        {
            return Check(execute(Convert.ToInt32(id), func));
        }

        public Tuple<bool, Result> Wait<T>(T id, Func<bool> func, double timeout = int.MaxValue)  //Wait condition
        {
            return Check(wait(Convert.ToInt32(id), func, timeout));
        }

        public Tuple<bool, Result> Wait<T>(T id, Func<bool?> func, double timeout = int.MaxValue)  //Wait condition
        {
            return Check(wait(Convert.ToInt32(id), func, timeout));
        }

        public Tuple<bool, Result> ExecuteAndWait<T>(T id, Func<bool> execute, Func<bool?> check, double timeout = int.MaxValue)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);
            bool? bExecute = false;

            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    if (!execute())
                    {
                        return Tuple.Create(bActive, Result.FAIL);   //执行错误
                    }
                    timer.Start(timeout);
                    state = STATE.WAIT;
                }

                bExecute = check();

                if (bExecute == null)
                {
                    return Tuple.Create(bActive, Result.FAIL);    //Termianate
                }
                else
                {
                    if (bExecute.Value)       //检查Success, next
                    {
                        next();
                        return Tuple.Create(true, Result.RUN);
                    }
                }

                if (timer.IsTimeout())
                    return Tuple.Create(true, Result.TIMEOUT);

                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }

        public Tuple<bool, Result> ExecuteAndWait<T>(T id, Func<bool> execute, Func<bool?> check, Func<double> time)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);
            bool? bExecute = false;
            double timeout = 0;
            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    timeout = time();
                    if (!execute())
                    {
                        return Tuple.Create(true, Result.FAIL);   //执行错误
                    }
                    timer.Start(timeout);
                    state = STATE.WAIT;
                }

                bExecute = check();

                if (bExecute == null)
                {
                    return Tuple.Create(true, Result.FAIL);    //Termianate
                }
                if (bExecute.Value)       //检查Success, next
                {
                    next();
                    return Tuple.Create(true, Result.RUN);
                }

                if (timer.IsTimeout())
                    return Tuple.Create(true, Result.TIMEOUT);

                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }

        public Tuple<bool, Result> Wait<T>(T id, IRoutine rt)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);

            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    rt.Start();
                    state = STATE.WAIT;
                }

                Result ret = rt.Monitor();

                return Tuple.Create(true, ret);
            }

            return Tuple.Create(false, Result.RUN);
        }

        //Monitor
        public Tuple<bool, Result> Monitor<T>(T id, Func<bool> func, Func<bool> check, double time)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);
            bool bCheck = false;
            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    if ((func != null) && !func())
                    {
                        return Tuple.Create(true, Result.FAIL);
                    }

                    timer.Start(time);
                    state = STATE.WAIT;
                }

                bCheck = check();

                if (!bCheck)
                {
                    return Tuple.Create(true, Result.FAIL);    //Termianate
                }

                if (timer.IsTimeout())
                {
                    next();
                }
                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }

        //Delay
        public Tuple<bool, Result> Delay<T>(T id, Func<bool> func, double time)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);
            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    if ((func != null) && !func())
                    {
                        return Tuple.Create(true, Result.FAIL);
                    }

                    timer.Start(time);
                    state = STATE.WAIT;
                }

                if (timer.IsTimeout())
                {
                    next();
                }
                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }

        //先delay 再运行
        public Tuple<bool, Result> DelayCheck<T>(T id, Func<bool> func, double time)
        {
            int idx = Convert.ToInt32(id);
            bool bActive = Acitve(idx);
            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    timer.Start(time);
                    state = STATE.WAIT;
                }

                if (timer.IsTimeout())
                {
                    if (func != null && !func())
                    {
                        return Tuple.Create(true, Result.FAIL);
                    }
                    next();
                }
                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }
        #endregion


        private Tuple<bool, bool> execute(int id, Func<bool> func)   //顺序执行
        {
            bool bActive = Acitve(id);
            bool bExecute = false;
            if (bActive)
            {
                bExecute = func();
                if (bExecute)
                {
                    next();
                }
            }

            return Tuple.Create(bActive, bExecute);
        }


        private Tuple<bool, bool> Check(int id, Func<bool> func)   //check
        {
            bool bActive = Acitve(id);
            bool bExecute = false;
            if (bActive)
            {
                bExecute = func();
                next();
            }

            return Tuple.Create(bActive, bExecute);
        }


        /// <summary>

        /// </summary>
        /// <param name="id"></param>
        /// <param name="func"></param>
        /// <param name="timeout"></param>
        /// <returns>
        ///  item1 Active
        ///  item2 execute
        ///  item3 Timeout
        ///</returns>

        private Tuple<bool, bool, bool> wait(int id, Func<bool> func, double timeout = int.MaxValue)  //Wait condition
        {
            bool bActive = Acitve(id);
            bool bExecute = false;
            bool bTimeout = false;

            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    timer.Start(timeout);
                    state = STATE.WAIT;
                }

                bExecute = func();
                if (bExecute)
                {
                    next();
                }

                bTimeout = timer.IsTimeout();
            }

            return Tuple.Create(bActive, bExecute, bTimeout);
        }

        private Tuple<bool, bool?, bool> wait(int id, Func<bool?> func, double timeout = int.MaxValue)  //Wait condition && Check error
        {
            bool bActive = Acitve(id);
            bool? bExecute = false;
            bool bTimeout = false;

            if (bActive)
            {
                if (state == STATE.IDLE)
                {
                    timer.Start(timeout);
                    state = STATE.WAIT;
                }

                bExecute = func();
                if (bExecute.HasValue && bExecute.Value)
                {
                    next();
                }

                bTimeout = timer.IsTimeout();
            }

            return Tuple.Create(bActive, bExecute, bTimeout);
        }

        /// <summary>      
        /// </summary>
        /// <param name="value"></param>
        /// <returns>
        /// item1 true, return item2
        /// </returns>
        private Tuple<bool, Result> Check(Tuple<bool, bool> value)
        {
            if (value.Item1)
            {
                if (!value.Item2)
                {
                    return Tuple.Create(true, Result.FAIL);
                }

                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }

        private Tuple<bool, Result> Check(Tuple<bool, bool, bool> value)
        {
            if (value.Item1)   // 当前执行
            {
                if (CheckTimeout(value))  //timeout
                {
                    return Tuple.Create(true, Result.TIMEOUT);
                }
                return Tuple.Create(true, Result.RUN);
            }

            return Tuple.Create(false, Result.RUN);
        }

        private Tuple<bool, Result> Check(Tuple<bool, bool?, bool> value)
        {
            if (value.Item1)   // 当前执行
            {
                if (value.Item2 == null)
                {
                    return Tuple.Create(true, Result.FAIL);
                }
                else
                {
                    if (value.Item2 == false && value.Item3 == true)  //timeout
                    {
                        return Tuple.Create(true, Result.TIMEOUT);
                    }
                    return Tuple.Create(true, Result.RUN);
                }
            }

            return Tuple.Create(false, Result.RUN);
        }

        private bool CheckTimeout(Tuple<bool, bool, bool> value)
        {
            return value.Item1 == true && value.Item2 == false && value.Item3 == true;
        }

        private bool Acitve(int id) //
        {
            if (_steps.Contains(id))
                return false;

            this._id = id;
            return true;
        }

        private void next()
        {
            _steps.Push(this._id);
            state = STATE.IDLE;
        }

        private void next(int step)   //loop
        {
            while (_steps.Pop() != step) ;

            state = STATE.IDLE;
        }


        public void Delay(int id, double delaySeconds)
        {
            Tuple<bool, Result> ret = Delay(id, () =>
            {
                return true;
            }, delaySeconds * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.RUN)
                {
                    throw (new RoutineBreakException());
                }
            }
        }



        public bool IsActived(int id)
        {
            return _steps.Contains(id);
        }








    }
}
