using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Device.Devices; using Aitex.Core.RT.Device.Unit; using Aitex.Core.RT.Event; using Aitex.Core.RT.Fsm; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Utilities; using Aitex.Sorter.Common; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Event; using MECF.Framework.Common.PLC; using SicModules.Devices; using SicModules.TMs.Routines; using SicAds = SicModules.Devices.SicAds; namespace SicModules.TMs { public class TMModule : TMModuleBase { public enum STATE { NotInstall, Init, Idle, Homing, Picking, Placing, PickAndPlacing, Pump, Vent, Error, Purge, LeakCheck, ServoPressure, PrepareTransfer, PostTransfer, Transfer, RobotMove, OpenSlitValve, CloseSlitValve, RobotHome, RobotGoto, RobotExtend, RobotRetract, NotConnect, } public enum MSG { Home, Reset, Abort, Error, Connected, Disconnected, Transfer, Pump, Vent, Purge, LeakCheck, PrepareTransfer, PostTransfer, OpenSlitValve, CloseSlitValve, ServoPressure, RobotMove, RobotHome, RobotPick, RobotPlace, RobotGoto, RobotExtend, RobotRetract, RobotPickAndPlace, SetOnline, SetOffline, ToInit, }; public bool IsBypassInterlock => SC.GetValue($"TM.BypassInterlock"); public bool IsBypassEnableTable => SC.GetValue($"TM.BypassEnableTable"); public bool IsPressureAbs_TM_PMA_DValue_In50 => (Math.Abs(TMDevice.ChamberPressure - (PM1ChamberGuage?.FeedBack ?? 0)) < 50); public bool IsPressureAbs_TM_PMB_DValue_In50 => (Math.Abs(TMDevice.ChamberPressure - (PM2ChamberGuage?.FeedBack ?? 0)) < 50); public bool IsPressureAbs_TM_Unload_DValue_In50 => (Math.Abs(TMDevice.ChamberPressure - TMDevice.UnLoadPressure) < 50); public bool IsPressureAbs_TM_Load_DValue_In50 => (Math.Abs(TMDevice.ChamberPressure - TMDevice.LoadLockPressure) < 50); public bool IsAlarm { get { return FsmState == (int)STATE.Error; } } public bool IsWarning { get { int count = 0; var warnings = EV.GetAlarmEvent(); foreach (var warm in warnings) { if (warm.Level == EventLevel.Warning && warm.Source == Name) count++; } return !IsAlarm && count > 0; } } public override bool IsReady { get { return FsmState == (int)STATE.Idle && CheckAllMessageProcessed(); } } public override bool IsError { get { return FsmState == (int)STATE.Error; } } public override bool IsInit { get { return FsmState == (int)STATE.Init; } } public bool IsBusy { get { return !IsInit && !IsError && !IsReady; } } public override bool IsIdle { get { return FsmState == (int)STATE.Idle && CheckAllMessageProcessed(); } } public int CurrentRoutineLoop { get { if (FsmState == (int)STATE.Purge) { return _purgeRoutine.LoopCounter + 1; } else if (FsmState == (int)STATE.LeakCheck) { return _leakCheckRoutine.LoopCounter + 1; } return 0; } } public int CurrentRoutineLoopTotal { get { if (FsmState == (int)STATE.Purge) { return _purgeRoutine.LoopTotalTime; } else if (FsmState == (int)STATE.LeakCheck) { return _leakCheckRoutine.LoopTotalTime; } return 0; } } public event Action OnEnterError; [Tag("Mfc60")] public IoMFC Mfc60 { get; set; } public SicTMRobot RobotDevice { get; set; } public SicTM TMDevice { get; set; } public IoValve VentValve { get; set; } public IoValve PumpValve { get; set; } public IoPressureMeter3 ForelineGuage { get; set; } public IoPressureMeter3 ChamberGuage { get; set; } public IoPressure PM1ChamberGuage { get; set; } public IoPressure PM2ChamberGuage { get; set; } public Dictionary SlitValves { get; set; } = new Dictionary(); public Dictionary SlitValveInstalled { get; set; } = new Dictionary(); private TMRobotGotoRoutine _gotoRoutine; private TMRobotPickRoutine _pickRoutine; private TMRobotPlaceRoutine _placeRoutine; private TMRobotHomeRoutine _homeRobotRoutine; private TMHomeRoutine _homeTMRoutine; private TMPumpRoutine _dryPumpRoutine; private TMVentRoutine _ventRoutine; private TMPurgeRoutine _purgeRoutine; private TMLeakCheckRoutine _leakCheckRoutine; private TMSlitValveRoutine _slitValveRoutine; private TMRobotExtendRoutine _extendRoutine; private TMRobotRetractRoutine _retractRoutine; private TMVerifySlitValveRoutine _slitValveVerifyRoutine; private TMServoRoutine _servoTMRoutine; private IoInterLockEx _tmIoInterLock; private bool _isInit; private bool _isStartTMRobotHome; public bool IsTMRobotHomed { get; set; } public IAdsPlc Plc { get; set; } private List _allModuleDevice = new List(); Func _hasTagAttribute; Func _isTagAttribute; public TMModule(ModuleName module) : base(1) { Module = module.ToString(); Name = module.ToString(); IsOnline = false; _tmIoInterLock = DEVICE.GetDevice("TM.IoInterLock"); EnumLoop.ForEach((item) => { MapState((int)item, item.ToString()); }); EnumLoop.ForEach((item) => { MapMessage((int)item, item.ToString()); }); EnableFsm(50, IsInstalled ? STATE.Init : STATE.NotInstall); } public override bool Initialize() { InitRoutine(); InitDevice(); InitFsm(); InitOp(); InitData(); InitScChangeCallback(); return base.Initialize(); } private void InitScChangeCallback() { // Bypass Interlock时自动Offline SC.RegisterValueChangedCallback($"TM.BypassInterlock", isBypassed => { if (isBypassed is true && IsOnline) { PutOffline(); EV.PostWarningLog(Module, "Offline automatically due to interlock bypassed"); } }); } private void InitRoutine() { _gotoRoutine = new TMRobotGotoRoutine(); _pickRoutine = new TMRobotPickRoutine(); _placeRoutine = new TMRobotPlaceRoutine(); _homeRobotRoutine = new TMRobotHomeRoutine(); _homeTMRoutine = new TMHomeRoutine(); _dryPumpRoutine = new TMPumpRoutine(); _ventRoutine = new TMVentRoutine(); _leakCheckRoutine = new TMLeakCheckRoutine(); _slitValveRoutine = new TMSlitValveRoutine(); _extendRoutine = new TMRobotExtendRoutine(); _retractRoutine = new TMRobotRetractRoutine(); _slitValveVerifyRoutine = new TMVerifySlitValveRoutine(); _purgeRoutine = new TMPurgeRoutine(); _servoTMRoutine = new TMServoRoutine(); } public void InitDevice() { if (IsInstalled) { if (SC.GetValue("System.IsSimulatorMode")) { Plc = DEVICE.GetOptionDevice($"{Module}.MainPLC", typeof(WcfPlc)) as IAdsPlc; (Plc as WcfPlc).Initialize(); } else { Plc = DEVICE.GetOptionDevice($"{Module}.MainPLC", typeof(SicAds)) as IAdsPlc; (Plc as SicAds).Initialize(); } } //System.Diagnostics.Debug.Assert(Plc != null, "System.TcAds not define"); if (Plc != null) { Plc.OnDeviceAlarmStateChanged += OnModuleDeviceAlarmStateChanged; Plc.OnConnected += PlcConnected; Plc.OnDisconnected += PlcDisconnected; _allModuleDevice.Add(Plc); } _isTagAttribute = attribute => attribute is TagAttribute; _hasTagAttribute = mi => mi.GetCustomAttributes(false).Any(_isTagAttribute); Parallel.ForEach(this.GetType().GetProperties().Where(_hasTagAttribute), field => { TagAttribute tag = field.GetCustomAttributes(false).First(_isTagAttribute) as TagAttribute; IDevice device = DEVICE.GetDevice($"{Module}.{tag.Tag}"); device.OnDeviceAlarmStateChanged += OnModuleDeviceAlarmStateChanged; _allModuleDevice.Add(device); PropertyInfo pi = (PropertyInfo)field; var convertedValue = Convert.ChangeType(device, pi.PropertyType); System.Diagnostics.Debug.Assert(convertedValue != null); pi.SetValue(this, convertedValue); }); RobotDevice = DEVICE.GetDevice($"{ModuleName.TMRobot}.{ModuleName.TMRobot}"); TMDevice = DEVICE.GetDevice($"{ModuleName.System}.{ModuleName.TM}"); TMDevice.OnDeviceAlarmStateChanged += TMDevice_OnDeviceAlarmStateChanged; VentValve = DEVICE.GetDevice("TM.TMVent"); PumpValve = DEVICE.GetDevice("TM.TMFastRough"); ChamberGuage = DEVICE.GetDevice("TM.TMPressure"); ForelineGuage = DEVICE.GetDevice("TM.ForelinePressure"); PM1ChamberGuage = (IoPressure)DEVICE.GetDevice("PM1.PT1"); PM2ChamberGuage = (IoPressure)DEVICE.GetDevice("PM2.PT1"); //SlitValves[ModuleName.PM1] = DEVICE.GetDevice("TM.PM1Door"); //SlitValves[ModuleName.PM2] = DEVICE.GetDevice("TM.PM2Door"); //SlitValves[ModuleName.UnLoad] = DEVICE.GetDevice("TM.TMUnLoadDoor"); //SlitValves[ModuleName.LoadLock] = DEVICE.GetDevice("TM.LLDoor"); //SlitValves[ModuleName.Buffer] = DEVICE.GetDevice("TM.LLDoor"); //SlitValveInstalled[ModuleName.PM1] = SC.GetValue("TM.PM1SlitValveEnabled"); //SlitValveInstalled[ModuleName.PM2] = SC.GetValue("TM.PM2SlitValveEnabled"); //SlitValveInstalled[ModuleName.UnLoad] = SC.GetValue("TM.UnLoadSlitValveEnabled"); //SlitValveInstalled[ModuleName.LoadLock] = SC.GetValue("TM.LoadLockSlitValveEnabled"); //SlitValveInstalled[ModuleName.Buffer] = SC.GetValue("TM.BufferSlitValveEnabled"); } private void InitFsm() { //Error AnyStateTransition(MSG.Error, FsmOnError, STATE.Error); AnyStateTransition(FSM_MSG.ALARM, FsmOnError, STATE.Error); Transition(STATE.Error, MSG.Reset, FsmReset, STATE.Idle); EnterExitTransition(STATE.Error, FsmEnterError, FSM_MSG.NONE, FsmExitError); //connection AnyStateTransition(MSG.Disconnected, FsmOnDisconnected, STATE.NotConnect); Transition(STATE.NotConnect, MSG.Connected, FsmOnConnected, STATE.Init); Transition(STATE.NotConnect, MSG.Reset, FsmResetConnect, STATE.NotConnect); //Home Transition(STATE.Init, MSG.Home, FsmStartHome, STATE.Homing); Transition(STATE.Error, MSG.Home, FsmStartHome, STATE.Homing); Transition(STATE.Idle, MSG.Home, FsmStartHome, STATE.Homing); Transition(STATE.Homing, FSM_MSG.TIMER, FsmMonitorHomeTask, STATE.Idle); Transition(STATE.Homing, MSG.Error, null, STATE.Init); Transition(STATE.Homing, MSG.Abort, FsmAbortTask, STATE.Init); EnterExitTransition((int)STATE.Homing, FsmEnterIdle, (int)FSM_MSG.NONE, FsmExitIdle); AnyStateTransition(MSG.ToInit, FsmToInit, STATE.Init); //robot home Transition(STATE.Idle, MSG.RobotHome, FsmStartRobotHome, STATE.RobotHome); Transition(STATE.RobotHome, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.RobotHome, MSG.Abort, FsmAbortTask, STATE.Idle); //Online Transition(STATE.Idle, MSG.SetOnline, FsmStartSetOnline, STATE.Idle); Transition(STATE.Idle, MSG.SetOffline, FsmStartSetOffline, STATE.Idle); //robot pick Transition(STATE.Idle, MSG.RobotPick, FsmStartRobotPick, STATE.Picking); Transition(STATE.Picking, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.Picking, MSG.Abort, FsmAbortTask, STATE.Idle); //robot place Transition(STATE.Idle, MSG.RobotPlace, FsmStartRobotPlace, STATE.Placing); Transition(STATE.Placing, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.Placing, MSG.Abort, FsmAbortTask, STATE.Idle); //robot gtot Transition(STATE.Idle, MSG.RobotGoto, FsmStartRobotGoto, STATE.RobotGoto); Transition(STATE.RobotGoto, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.RobotGoto, MSG.Abort, FsmAbortTask, STATE.Idle); //robot extend Transition(STATE.Idle, MSG.RobotExtend, FsmStartRobotExtend, STATE.RobotExtend); Transition(STATE.RobotExtend, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.RobotExtend, MSG.Abort, FsmAbortTask, STATE.Idle); //robot retract Transition(STATE.Idle, MSG.RobotRetract, FsmStartRobotRetract, STATE.RobotRetract); Transition(STATE.RobotRetract, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.RobotRetract, MSG.Abort, FsmAbortTask, STATE.Idle); //prepare transfer Transition(STATE.Idle, MSG.PrepareTransfer, FsmStartPrepareTransfer, STATE.PrepareTransfer); Transition(STATE.PrepareTransfer, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.PrepareTransfer, MSG.Abort, FsmAbortTask, STATE.Idle); //post transfer Transition(STATE.Idle, MSG.PostTransfer, FsmStartPostTransfer, STATE.PostTransfer); Transition(STATE.PostTransfer, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.PostTransfer, MSG.Abort, FsmAbortTask, STATE.Idle); //Pump Transition(STATE.Idle, MSG.Pump, FsmStartPump, STATE.Pump); Transition(STATE.Pump, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.Pump, MSG.Abort, FsmAbortTask, STATE.Idle); //ServoToLL Transition(STATE.Idle, MSG.ServoPressure, FsmStartServoTM, STATE.ServoPressure); Transition(STATE.ServoPressure, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.ServoPressure, MSG.Abort, FsmAbortTask, STATE.Idle); //Vent Transition(STATE.Idle, MSG.Vent, FsmStartVent, STATE.Vent); Transition(STATE.Vent, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.Vent, MSG.Abort, FsmAbortTask, STATE.Idle); //Purge Transition(STATE.Idle, MSG.Purge, FsmStartPurge, STATE.Purge); Transition(STATE.Purge, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.Purge, MSG.Abort, FsmAbortTask, STATE.Idle); //Leak check Transition(STATE.Idle, MSG.LeakCheck, FsmStartLeakCheck, STATE.LeakCheck); Transition(STATE.LeakCheck, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.LeakCheck, MSG.Abort, FsmAbortTask, STATE.Idle); //open SlitValve Transition(STATE.Idle, MSG.OpenSlitValve, FsmStartOpenSlitValve, STATE.OpenSlitValve); Transition(STATE.OpenSlitValve, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.OpenSlitValve, MSG.Abort, FsmAbortTask, STATE.Idle); //close SlitValve Transition(STATE.Idle, MSG.CloseSlitValve, FsmStartCloseSlitValve, STATE.CloseSlitValve); Transition(STATE.CloseSlitValve, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.CloseSlitValve, MSG.Abort, FsmAbortTask, STATE.Idle); } private void InitOp() { OP.Subscribe("Robot.MoveWafer", (string cmd, object[] args) => { if (!Enum.TryParse((string)args[0], out ModuleName source)) { EV.PostWarningLog(Name, $"Parameter source {(string)args[0]} not valid"); return false; } if (!Enum.TryParse((string)args[1], out ModuleName destination)) { EV.PostWarningLog(Name, $"Parameter destination {(string)args[1]} not valid"); return false; } return CheckToPostMessage((int)MSG.Transfer, source, destination); }); OP.Subscribe($"{Name}.Home", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.Home); }); OP.Subscribe($"{Name}.Pump", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.Pump); }); OP.Subscribe($"{Name}.Vent", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.Vent); }); OP.Subscribe($"{Name}.Purge", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.Purge); }); OP.Subscribe($"{Name}.ServoPressure", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.ServoPressure); }); OP.Subscribe($"{Name}.LeakCheck", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.LeakCheck, args); }); OP.Subscribe($"{Name}.OpenSlitValve", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.OpenSlitValve, args[0]); }); OP.Subscribe($"{Name}.CloseSlitValve", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.CloseSlitValve, args[0]); }); OP.Subscribe($"{Name}.Reset", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.Reset); }); OP.Subscribe($"{Name}.Abort", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.Abort); }); OP.Subscribe($"TMRobot.Home", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.RobotHome); }); OP.Subscribe($"TMRobot.Pick", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.RobotPick, args[0], args[1], args[2]); }); OP.Subscribe($"TMRobot.Place", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.RobotPlace, args[0], args[1], args[2]); }); OP.Subscribe($"TMRobot.Goto", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.RobotGoto, args[0], args[1], args[2], args[3], args[4]); }); OP.Subscribe($"TMRobot.Extend", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.RobotExtend, args[0], args[1], args[2]); }); OP.Subscribe($"TMRobot.Retract", (string cmd, object[] args) => { return CheckToPostMessage((int)MSG.RobotRetract, args[0], args[1], args[2]); }); OP.Subscribe($"{Module}.SetOnline", (string cmd, object[] args) => PutOnline()); OP.Subscribe($"{Module}.SetOffline", (string cmd, object[] args) => PutOffline()); } private void InitData() { DATA.Subscribe($"{Name}.IsPressureAbs_TM_PMA_DValue_In50", () => IsPressureAbs_TM_PMA_DValue_In50, Aitex.Core.Util.SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Name}.IsPressureAbs_TM_PMB_DValue_In50", () => IsPressureAbs_TM_PMB_DValue_In50, Aitex.Core.Util.SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Name}.IsPressureAbs_TM_Unload_DValue_In50", () => IsPressureAbs_TM_Unload_DValue_In50, Aitex.Core.Util.SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Name}.IsPressureAbs_TM_Load_DValue_In50", () => IsPressureAbs_TM_Load_DValue_In50, Aitex.Core.Util.SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Name}.Status", () => StringFsmStatus); DATA.Subscribe($"{Name}.IsOnline", () => IsOnline); DATA.Subscribe($"TMRobot.IsHomed", () => IsTMRobotHomed); DATA.Subscribe($"{Module}.IsError", () => IsError); DATA.Subscribe($"{Module}.IsAlarm", () => IsAlarm); DATA.Subscribe($"{Module}.IsWarning", () => IsWarning); DATA.Subscribe($"{Module}.IsBypassInterlock", () => IsBypassInterlock); DATA.Subscribe($"{Module}.IsBypassEnableTable", () => IsBypassEnableTable); DATA.Subscribe($"{Name}.CurrentRoutineLoop", () => CurrentRoutineLoop); DATA.Subscribe($"{Name}.CurrentRoutineLoopTotal", () => CurrentRoutineLoopTotal); DATA.Subscribe($"{Name}.LeakCheckElapseTime", () => { if (FsmState == (int)STATE.LeakCheck) return _leakCheckRoutine.ElapsedTime; return 0; }); DATA.Subscribe($"{Name}.AtATM", () => { if (TMDevice.CheckAtm()) { return true; } return false; }); DATA.Subscribe($"{Name}.UnderVAC", () => { if (TMDevice.CheckVacuum()) { return true; } return false; }); } private void PlcDisconnected() { CheckToPostMessage(MSG.Disconnected); } private void PlcConnected() { CheckToPostMessage(MSG.Connected); } private void OnModuleDeviceAlarmStateChanged(string deviceId, AlarmEventItem alarmItem) { if (!alarmItem.IsAcknowledged) { if (alarmItem.Level == EventLevel.Alarm) { EV.PostAlarmLog(alarmItem.Source, alarmItem.Description); } else { EV.PostWarningLog(alarmItem.Source, alarmItem.Description); } } //EV.PostAlarmLog(Module, obj.Description); } private bool FsmOnError(object[] param) { IsOnline = false; if (FsmState == (int)STATE.Error) { return false; } if (FsmState == (int)STATE.Picking) { _pickRoutine.Abort(); } if (FsmState == (int)STATE.Placing) { _placeRoutine.Abort(); } if (FsmState == (int)STATE.RobotGoto) { _gotoRoutine.Abort(); } if (FsmState == (int)STATE.Init) return false; if (FsmState == (int)STATE.ServoPressure) { _servoTMRoutine.Abort(); } return true; } private bool FsmReset(object[] param) { if (FsmState == (int)STATE.Error) { EV.ClearAlarmEvent(); } if (!_isInit) { PostMsg(MSG.ToInit); return false; } RobotDevice.RobotReset(); return true; } private bool FsmExitError(object[] param) { return true; } private bool FsmEnterError(object[] param) { if (OnEnterError != null) OnEnterError(Module); return true; } private bool FsmOnConnected(object[] param) { //SignalTowerDevice.ResetData(); //LP1Device.ResetData(); //LP2Device.ResetData(); //LP3Device.ResetData(); //LP4Device.ResetData(); //EfemDevice.ResetData(); return true; } private bool FsmOnDisconnected(object[] param) { return true; } private bool FsmResetConnect(object[] param) { //if (!EfemDevice.Connection.IsConnected) //{ // EfemDevice.Connect(); // return false; //} //if (!EfemDevice.EmoAlarm.IsAcknowledged) //{ // EfemDevice.ClearError(); // return false; //} return true; } private bool FsmStartHome(object[] param) { Result ret = StartRoutine(_homeTMRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; _isInit = false; return ret == Result.RUN; } private bool FsmMonitorHomeTask(object[] param) { Result ret = MonitorRoutine(); if (ret == Result.FAIL) { PostMsg(MSG.Error); return false; } if (ret == Result.DONE) { _isInit = true; OP.DoOperation($"{Module}.ResetTask"); return true; } return false; } private bool FsmAbortTask(object[] param) { AbortRoutine(); RobotDevice.RobotReset(); return true; } private bool FsmExitIdle(object[] param) { return true; } private bool FsmEnterIdle(object[] param) { return true; } private bool FsmToInit(object[] param) { RobotDevice.RobotReset(); return true; } private bool FsmStartRobotHome(object[] param) { Result ret = StartRoutine(_homeRobotRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; _isStartTMRobotHome = true; IsTMRobotHomed = false; return ret == Result.RUN; } private bool FsmMonitorTask(object[] param) { Result ret = MonitorRoutine(); if (ret == Result.FAIL) { PostMsg(MSG.Error); return false; } if (_isStartTMRobotHome) { _isStartTMRobotHome = false; IsTMRobotHomed = true; OP.DoOperation($"{Module}.ResetTask"); } return ret == Result.DONE; } private bool FsmStartSetOffline(object[] param) { IsOnline = false; return true; } private bool FsmStartSetOnline(object[] param) { //需检查是否完成TM Purge if(!_tmIoInterLock.DoTmCyclePurgeRoutineSuccessed) { EV.PostWarningLog("TM", "TM Purge is not complete,cannot be online"); return true; } IsOnline = true; return true; } private bool FsmStartRobotPick(object[] param) { _pickRoutine.Init(ModuleHelper.Converter((string)param[0]), (int)param[1], (int)param[2]); Result ret = StartRoutine(_pickRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartRobotPlace(object[] param) { _placeRoutine.Init(ModuleHelper.Converter((string)param[0]), (int)param[1], (int)param[2]); Result ret = StartRoutine(_placeRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartRobotGoto(object[] param) { _gotoRoutine.Init(ModuleHelper.Converter((string)param[0]), (int)param[1], (int)param[2], (string)param[3], (string)param[4]); Result ret = StartRoutine(_gotoRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartRobotExtend(object[] param) { _extendRoutine.Init(ModuleHelper.Converter((string)param[0]), (int)param[1], (int)param[2]); Result ret = StartRoutine(_extendRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartRobotRetract(object[] param) { _retractRoutine.Init(ModuleHelper.Converter((string)param[0]), (int)param[1], (int)param[2]); Result ret = StartRoutine(_retractRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartPrepareTransfer(object[] param) { QueueRoutine.Clear(); //if (SC.GetValue("TM.IsTurboPumpEnabled")) //{ // _turboPumpRoutine.Init(); // QueueRoutine.Enqueue(_turboPumpRoutine); //} //else //{ // _dryPumpRoutine.Init(); // QueueRoutine.Enqueue(_dryPumpRoutine); //} //_slitValveRoutine.Init((string)param[0], true); //QueueRoutine.Enqueue(_slitValveRoutine); Result ret = StartRoutine(); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartPostTransfer(object[] param) { _slitValveRoutine.Init((string)param[0], false); Result ret = StartRoutine(_slitValveRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartPump(object[] param) { Result ret; //if (SC.GetValue("TM.IsTurboPumpEnabled")) //{ // _turboPumpRoutine.Init(); // ret = StartRoutine(_turboPumpRoutine); //} //else //{ _dryPumpRoutine.Init(); ret = StartRoutine(_dryPumpRoutine); //} if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartVent(object[] param) { Result ret = StartRoutine(_ventRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartPurge(object[] param) { Result ret = StartRoutine(_purgeRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartServoTM(object[] param) { Result ret = StartRoutine(_servoTMRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartLeakCheck(object[] param) { if (param != null && param.Length >= 2) { _leakCheckRoutine.Init((int)param[0], (int)param[1]); } else { _leakCheckRoutine.Init(); } Result ret = StartRoutine(_leakCheckRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartOpenSlitValve(object[] param) { _slitValveRoutine.Init((string)param[0], true); Result ret = StartRoutine(_slitValveRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartCloseSlitValve(object[] param) { _slitValveRoutine.Init((string)param[0], false); Result ret = StartRoutine(_slitValveRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } public override bool Home(out string reason) { CheckToPostMessage((int)MSG.Home); reason = string.Empty; return true; } public override bool Pick(ModuleName target, Hand blade, int targetSlot, out string reason) { reason = string.Empty; if (CheckToPostMessage((int)MSG.RobotPick, target.ToString(), targetSlot, blade)) return true; return false; } public override bool Place(ModuleName target, Hand blade, int targetSlot, out string reason) { reason = string.Empty; if (CheckToPostMessage((int)MSG.RobotPlace, target.ToString(), targetSlot, blade)) return true; return false; } public override bool PickAndPlace(ModuleName pickTarget, Hand pickHand, int pickSlot, ModuleName placeTarget, Hand placeHand, int placeSlot, out string reason) { CheckToPostMessage((int)MSG.RobotPickAndPlace, pickTarget.ToString(), pickHand, pickSlot, placeHand, placeSlot); reason = string.Empty; return true; } public override bool Goto(ModuleName target, Hand blade, int targetSlot, out string reason) { CheckToPostMessage((int)MSG.RobotGoto, target.ToString(), targetSlot, blade); reason = string.Empty; return true; } private void TMDevice_OnDeviceAlarmStateChanged(string module, AlarmEventItem alarmItem) { if (IsInit) return; if (!alarmItem.IsAcknowledged) { if (alarmItem.Level == EventLevel.Warning) { EV.PostWarningLog(Module, alarmItem.Description); } else { EV.PostAlarmLog(Module, alarmItem.Description); } //if (alarmItem.EventEnum == TMDevice.IsMaintain.EventEnum //|| alarmItem.EventEnum == TMDevice.EmoAlarm.EventEnum //|| alarmItem.EventEnum == TMDevice.DoorOpen.EventEnum) //{ // _isInit = false; // PostMsg(MSG.Error); //} //else if (alarmItem.Level == EventLevel.Alarm) { PostMsg(MSG.Error); } } else { if (IsError) CheckToPostMessage((int)MSG.Reset); } } private bool PutOnline() { if (IsBypassInterlock || IsBypassEnableTable) { EV.PostWarningLog(Module, $"Interlock is bypassed"); return false; } //需检查是否完成TM Purge if (!_tmIoInterLock.DoTmCyclePurgeRoutineSuccessed) { EV.PostWarningLog("TM", "TM Purge is not complete,cannot be online"); return true; } IsOnline = true; return true; } private bool PutOffline() { IsOnline = false; //NotifyModuleOfflineCancellation?.Dispose(); //NotifyModuleOfflineCancellation = new CancellationTokenSource(); //NotifyModuleOfflineTask(5 * 60 * 1000);//5min return true; } public void InvokeOffline() { PutOffline(); } public void InvokeOnline() { PutOnline(); } private CancellationTokenSource NotifyModuleOfflineCancellation = new CancellationTokenSource(); private Task NotifyModuleOfflineTask(int delayTime) { var t1 = Task.Run(async () => { await Task.Delay(delayTime, NotifyModuleOfflineCancellation.Token).ContinueWith(x => EV.PostWarningLog(Module, $"{Module} is still in offline"), NotifyModuleOfflineCancellation.Token); }); return t1; } public int InvokeError() { if (CheckToPostMessage((int)MSG.Error)) return (int)MSG.Error; return (int)FSM_MSG.NONE; } } }