using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Device.Unit; using Aitex.Core.RT.Event; using Aitex.Core.RT.Fsm; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using Aitex.Core.Utilities; using Aitex.Sorter.Common; using MECF.Framework.Common.Alarms; using MECF.Framework.Common.Device.Bases; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Schedulers; using MECF.Framework.Common.SubstrateTrackings; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FurnaceRT.Equipments.FIMSs { public partial class FIMSModule : FIMSModuleBase { public enum STATE { NotInstall, NotConnected, Idle, Error, Init, Homing, Unloading, Loading, Cycle, InTransfer, } public enum MSG { Home, Disconnected, Connected, Reset, Abort, Error, InTransfer, Cycle, TransferComplete, Load, Unload, LoadRetry, UnloadRetry, } 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 false; } } public bool IsFoupExist => FIMSDevice != null ? FIMSDevice.IsFoupExist : false; public bool IsLoading { get { return FsmState == (int)STATE.Loading; } } private bool _isOnline; public override bool IsOnline { get { return _isOnline; } set { _isOnline = value; SC.SetItemValue($"FIMS.{Name}.IsOnline", value); } } #region fields private FIMSHomeRoutine _homeRoutine; private FIMSLoadRoutine _loadRoutine; private FIMSUnloadRoutine _unloadRoutine; private FIMSCycleTest _moveCycleTest; private List _mappingData; #endregion public FIMSModule(ModuleName module) : base(SC.GetValue("System.CassetteSlotCount")) { Name = module.ToString(); Module = module.ToString(); IsOnline = SC.GetValue($"FIMS.{Name}.IsOnline"); } public override bool Initialize() { InitRoutine(); InitDevice(); InitFsm(); InitOp(); InitData(); InitAlarmEvent(); Singleton.Instance.OnAlarmEvent += Instance_OnAlarmEvent; return base.Initialize(); } private void Instance_OnAlarmEvent(EventItem item) { if (item != null && item.Level == EventLevel.Alarm && (item.Source == Name || item.Source == Module)) { DEVICE.GetDevice("System.SignalTower")?.Reset(); LOG.Write($"{item.Source} {item.EventEnum} {item.Description}\n"); PostMsg(MSG.Error); } } private void InitRoutine() { _homeRoutine = new FIMSHomeRoutine(this); _loadRoutine = new FIMSLoadRoutine(this); _unloadRoutine = new FIMSUnloadRoutine(this); _moveCycleTest = new FIMSCycleTest(this); } private void InitData() { DATA.Subscribe($"{Module}.MappingData", () => new List() { new AITWaterMappingData(){Slot = 1,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 2,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 3,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 4,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 5,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 6,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 7,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 8,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 9,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 10,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 11,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 12,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 13,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 14,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 15,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 16,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 17,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 18,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 19,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 20,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 21,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 22,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 23,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 24,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, new AITWaterMappingData(){Slot = 25,Detect=2500, Base=2500,Diff = 0,Thickness = 10}, }); DATA.Subscribe($"{Module}.SlotNo1Distance", () => 100.0f); DATA.Subscribe($"{Module}.SlotPitchDistance", () => 100f); DATA.Subscribe($"{Module}.ThicknessReferenceValue", () => 5f); DATA.Subscribe($"{Module}.ThicknessPermissions", () => 8f); DATA.Subscribe($"{Module}.MappingResult", () => "Normal Complete"); DATA.Subscribe($"{Module}.Status", () => StringFsmStatus); DATA.Subscribe($"{Module}.IsOnline", () => IsOnline); DATA.Subscribe($"{Module}.IsError", () => IsError); DATA.Subscribe($"{Module}.FIMSCycledCount", () => _moveCycleTest.LoopCounter); //DATA.Subscribe(Module, "CassettePresent", () => _diStationCassettePresent.Value); //DATA.Subscribe($"{Module}.StageValveState", () => StageValveState.ToString()); } private void InitOp() { OP.Subscribe($"{Module}.Abort", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Abort)); OP.Subscribe($"{Module}.Home", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Home)); OP.Subscribe($"{Module}.Load", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Load, args)); OP.Subscribe($"{Module}.Unload", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Unload, args)); OP.Subscribe($"{Module}.Reset", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Reset)); OP.Subscribe($"{Module}.Cycle", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Cycle)); OP.Subscribe($"{Module}.SetOnline", (string cmd, object[] args) => { IsOnline = true; return true; }); OP.Subscribe($"{Module}.SetOffline", (string cmd, object[] args) => { IsOnline = false; return true; }); OP.Subscribe($"{Module}.AlarmAction", (string cmd, object[] args) => { Enum.TryParse(args[0].ToString(), out AlarmAction alarmAction); string eventName = null; if (args.Length > 1) eventName = args[1].ToString(); if (eventName != null) { EV.ClearAlarmEvent(eventName); var item = _triggeredAlarmList.FirstOrDefault(x => x.EventEnum == eventName); if (item != null) { item.Reset(); _triggeredAlarmList.Remove(item); } if (item != null) { switch (alarmAction) { case AlarmAction.Retry: { CheckToPostMessage((int)item.RetryMessage, item.RetryMessageParas); } break; case AlarmAction.Abort: { CheckToPostMessage((int)MSG.Abort); } break; case AlarmAction.Clear: { int alarmCount = 0; var alarms = EV.GetAlarmEvent(); foreach (var alarm in alarms) { if (alarm.Level == EventLevel.Alarm && alarm.Source == Name) alarmCount++; } if (alarmCount == 0) CheckToPostMessage((int)MSG.Reset); } break; case AlarmAction.Continue: { int alarmCount = 0; var alarms = EV.GetAlarmEvent(); foreach (var alarm in alarms) { if (alarm.Level == EventLevel.Alarm && alarm.Source == Name) alarmCount++; } if (alarmCount == 0) CheckToPostMessage((int)MSG.Reset); } break; } } } return true; }); } private void InitFsm() { EnumLoop.ForEach((item) => { MapState((int)item, item.ToString()); }); EnumLoop.ForEach((item) => { MapMessage((int)item, item.ToString()); }); EnableFsm(100, STATE.Init); 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); Transition(STATE.Idle, MSG.Disconnected, null, STATE.NotConnected); Transition(STATE.Idle, MSG.InTransfer, null, STATE.InTransfer); Transition(STATE.InTransfer, MSG.TransferComplete, null, STATE.Idle); Transition(STATE.InTransfer, MSG.Abort, null, STATE.Idle); Transition(STATE.NotConnected, MSG.Connected, null, STATE.Idle); //Error AnyStateTransition(MSG.Error, FsmOnError, STATE.Error); Transition(STATE.Error, MSG.Reset, FsmReset, STATE.Idle); Transition(STATE.Init, MSG.Reset, FsmReset, STATE.Init); Transition(STATE.Idle, MSG.Reset, FsmReset, STATE.Idle); //load Transition(STATE.Error, MSG.LoadRetry, FsmStartLoad, STATE.Loading); Transition(STATE.Idle, MSG.Load, FsmStartLoad, STATE.Loading); Transition(STATE.Loading, FSM_MSG.TIMER, FsmMonitorLoadTask, STATE.Idle); Transition(STATE.Loading, MSG.Abort, FsmAbortTask, STATE.Idle); //unload Transition(STATE.Error, MSG.UnloadRetry, FsmStartUnload, STATE.Unloading); Transition(STATE.Idle, MSG.Unload, FsmStartUnload, STATE.Unloading); Transition(STATE.Unloading, FSM_MSG.TIMER, FsmMonitorUnloadTask, STATE.Idle); Transition(STATE.Unloading, MSG.Abort, FsmAbortTask, STATE.Idle); Transition(STATE.Idle, MSG.Cycle, FsmStartMoveTest, STATE.Cycle); Transition(STATE.Cycle, FSM_MSG.TIMER, FsmMonitorTask, STATE.Idle); Transition(STATE.Cycle, MSG.Abort, FsmAbortTask, STATE.Idle); } #region Service Functions private bool FsmStartHome(object[] param) { Result ret = StartRoutine(_homeRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmAbortTask(object[] param) { return true; } private bool FsmMonitorHomeTask(object[] param) { Result ret = MonitorRoutine(); if (ret == Result.FAIL) { PostMsg(MSG.Error); return false; } if (ret == Result.DONE) { return true; } return false; } private bool FsmStartMoveTest(object[] param) { Result ret = StartRoutine(_moveCycleTest); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartLoad(object[] param) { bool isNeedN2Purge = false; if(param.Length > 0) { bool.TryParse(param[0].ToString(), out isNeedN2Purge); } _loadRoutine.Init(isNeedN2Purge); QueueRoutine.Clear(); QueueRoutine.Enqueue(_loadRoutine); Result ret = QueueRoutine.Peek().Start(); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartUnload(object[] param) { bool isNeedN2Purge = false; if (param.Length > 0) { bool.TryParse(param[0].ToString(), out isNeedN2Purge); } _unloadRoutine.Init(isNeedN2Purge); QueueRoutine.Clear(); Result ret = StartRoutine(_unloadRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmMonitorLoadTask(object[] param) { Result ret = MonitorRoutine(); if (ret == Result.FAIL) { PostMsg(MSG.Error); return false; } if (ret == Result.DONE) IsOnline = true; return ret == Result.DONE; } private bool FsmMonitorTask(object[] param) { Result ret = MonitorRoutine(); if (ret == Result.FAIL) { PostMsg(MSG.Error); return false; } return ret == Result.DONE; } private bool FsmMonitorUnloadTask(object[] param) { Result ret = MonitorRoutine(); if (ret == Result.FAIL) { PostMsg(MSG.Error); return false; } return ret == Result.DONE; } public override bool Home(out string reason) { CheckToPostMessage((int)MSG.Home); reason = string.Empty; return true; } private bool FsmOnError(object[] param) { if (FsmState == (int)STATE.Error) { return false; } if (FsmState != (int)STATE.Init && FsmState != (int)STATE.Idle) AbortRoutine(); return true; } public override void Reset() { if (IsError) { CheckToPostMessage((int)MSG.Reset); } } private bool FsmReset(object[] param) { FIMSDevice.SetAlarmReset(); return true; } public override bool PrepareTransfer(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType, out string reason) { reason = string.Empty; return true; } public override bool TransferHandoff(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType, out string reason) { reason = string.Empty; return true; } public override bool PostTransfer(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType, out string reason) { reason = string.Empty; return true; } public override bool CheckReadyForTransfer(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType, out string reason) { reason = string.Empty; if (!IsReady) { reason = $"{Module} status={StringFsmStatus} is busy"; return false; } if (robot == ModuleName.WaferRobot) { if (!FIMSDevice.IsLoadCompleted) { reason = $"{Module} is not loaded"; return false; } if (!IsDoorOpen) { reason = $"{Module} door is not open"; } } if (robot == ModuleName.CarrierRobot) { if (!FIMSDevice.IsUnloadCompleted) { reason = $"{Module} is not unloaded"; return false; } if (transferType == EnumTransferType.Pick) { if (!CarrierManager.Instance.CheckHasCarrier(Module, 0)) { reason = $"{Module} carrier not present"; return false; } } if (transferType == EnumTransferType.Place) { if (!CarrierManager.Instance.CheckNoCarrier(Module, 0)) { reason = $"{Module} carrier present"; return false; } } } return true; } public override void NoteTransferStart(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType) { CheckToPostMessage(MSG.InTransfer); } public override void NoteTransferStop(ModuleName robot, Hand blade, int targetSlot, EnumTransferType transferType) { if (FsmState == (int)STATE.InTransfer) CheckToPostMessage(MSG.TransferComplete); } public void InvokeLoad(bool isNeedN2Purge) { CheckToPostMessage((int)MSG.Load, isNeedN2Purge); } public void InvokeUnload(bool isNeedN2Purge) { CheckToPostMessage((int)MSG.Unload, isNeedN2Purge); } #endregion } }