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.OperationCenter; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Utilities; using Aitex.Sorter.Common; using MECF.Framework.Common.Alarms; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Event; 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; using FurnaceRT.Equipments.Systems; using Aitex.Core.Util; using MECF.Framework.Common.Device.Bases; using Aitex.Core.RT.Log; namespace FurnaceRT.Equipments.LPs { public partial class LoadPortModule : LoadPortModuleBase { public enum STATE { NotInstall, NotConnected, Init, Idle, Homing, Unloading, Loading, Error, InTransfer, } public enum MSG { Home, Disconnected, Connected, Reset, Abort, Error, Load, AutoLoad, Unload, AutoUnload, AutoLoadRetry, LoadRetry, UnloadRetry, AutoUnloadRetry, InTransfer, TransferComplete, ToInit, } 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 event Action OnEnterError; public string CurrentLotId { get; set; } public List WaitLotId { get; set; } //public bool IsLoaded => SMIFDevice.IsLoaded; //public bool IsUnloaded => SMIFDevice.IsUnloaded; //public bool IsExtend => SMIFDevice.IsExtend; //public bool IsRetract => SMIFDevice.IsRetract; #region fields private LoadPortLoad _loadRoutine; private LoadPortAutoLoad _autoLoadRoutine; private LoadPortUnload _unloadRoutine; private LoadPortAutoUnload _autoUnloadRoutine; private LoadPortHome _homeRoutine; #endregion public LoadPortModule(ModuleName module) : base(SC.GetValue("System.CassetteSlotCount")) { Name = module.ToString(); Module = module.ToString(); IsOnline = true; } 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() { _loadRoutine = new LoadPortLoad(this); _autoLoadRoutine = new LoadPortAutoLoad(this); _unloadRoutine = new LoadPortUnload(this); _autoUnloadRoutine = new LoadPortAutoUnload(this); _homeRoutine = new LoadPortHome(this); } private void InitData() { DATA.Subscribe($"{Module}.Status", () => StringFsmStatus); DATA.Subscribe($"{Module}.IsOnline", () => IsOnline); DATA.Subscribe($"{Module}.IsError", () => IsError); DATA.Subscribe($"{Name}.CurrentLotId", () => CurrentLotId); DATA.Subscribe($"{Name}.WaitLotId", () => WaitLotId); DATA.Subscribe($"{Name}.CarrierId", () => CarrierId); } private void InitOp() { OP.Subscribe($"{Module}.Home", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Home)); OP.Subscribe($"{Module}.Abort", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Abort)); OP.Subscribe($"{Module}.Load", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Load)); OP.Subscribe($"{Module}.Unload", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Unload)); OP.Subscribe($"{Module}.Reset", (string cmd, object[] args) => CheckToPostMessage((int)MSG.Reset)); OP.Subscribe($"{Module}.ReadCarrierId", (string cmd, object[] args) => ReadCarrierId(args)); 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, IsInstalled ? STATE.Idle : STATE.NotInstall); //init Transition(STATE.Init, MSG.Home, FsmStartHome, STATE.Homing); Transition(STATE.Idle, MSG.Abort, null, STATE.Idle); Transition(STATE.Idle, MSG.Reset, null, STATE.Idle); Transition(STATE.Init, MSG.Reset, null, STATE.Init); Transition(STATE.Error, MSG.Abort, null, STATE.Error); AnyStateTransition(MSG.ToInit, FsmToInit, STATE.Init); 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.InTransfer, null, STATE.InTransfer); Transition(STATE.InTransfer, MSG.TransferComplete, null, STATE.Idle); Transition(STATE.InTransfer, MSG.Abort, null, STATE.Idle); Transition(STATE.Idle, MSG.Abort, null, STATE.Idle); Transition(STATE.Idle, MSG.Reset, null, STATE.Idle); Transition(STATE.Error, MSG.Abort, null, STATE.Error); //Error AnyStateTransition(MSG.Error, FsmOnError, STATE.Error); Transition(STATE.Error, MSG.Reset, FsmReset, STATE.Idle); EnterExitTransition(STATE.Error, FsmEnterError, FSM_MSG.NONE, FsmExitError); //load Transition(STATE.Error, MSG.LoadRetry, FsmStartLoad, STATE.Loading); Transition(STATE.Error, MSG.AutoLoadRetry, FsmStartAutoLoad, STATE.Loading); Transition(STATE.Idle, MSG.Load, FsmStartLoad, STATE.Loading); Transition(STATE.Idle, MSG.AutoLoad, FsmStartAutoLoad, 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.Error, MSG.AutoUnloadRetry, FsmStartAutoUnload, STATE.Unloading); Transition(STATE.Idle, MSG.Unload, FsmStartUnload, STATE.Unloading); Transition(STATE.Idle, MSG.AutoUnload, FsmStartAutoUnload, STATE.Unloading); Transition(STATE.Unloading, FSM_MSG.TIMER, FsmMonitorUnloadTask, STATE.Idle); Transition(STATE.Unloading, MSG.Abort, FsmAbortTask, STATE.Idle); } #region Service Functions public override bool Home(out string reason) { if (!CheckToPostMessage((int)MSG.Home)) { reason = $"Can not home in {StringFsmStatus} status"; return false; } reason = string.Empty; return true; } public override void Reset() { _triggeredAlarmList.ForEach(x => x.Reset()); _triggeredAlarmList.Clear(); if (IsError) { CheckToPostMessage((int)MSG.Reset); } } private bool FsmReset(object[] param) { 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 (transferType == EnumTransferType.Place) { if (!LPDevice.IsFoupPresent || (SC.GetValue("System.IsSimulatorMode") && CarrierManager.Instance.CheckNoCarrier(Module, 0))) return true; reason = $"foup present"; return false; } if (transferType == EnumTransferType.Pick) { if (LPDevice.IsFoupPresent) return true; reason = $"foup not present"; return false; } if (!IsReleased) { reason = $"{Module} is not release"; return false; } return false; } 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); } 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 FsmMonitorUnloadTask(object[] param) { Result ret = MonitorRoutine(); if (ret == Result.FAIL) { PostMsg(MSG.Error); return false; } return ret == Result.DONE; } private bool FsmStartLoad(object[] param) { QueueRoutine.Clear(); _loadRoutine.Init(param.Length > 0 ? (bool)param[0] : false); QueueRoutine.Enqueue(_loadRoutine); Result ret = QueueRoutine.Peek().Start(); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartAutoLoad(object[] param) { QueueRoutine.Clear(); _autoLoadRoutine.Init(param.Length > 0 ? (bool)param[0] : false); QueueRoutine.Enqueue(_autoLoadRoutine); Result ret = QueueRoutine.Peek().Start(); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartUnload(object[] param) { QueueRoutine.Clear(); _loadRoutine.Init(param.Length > 0 ? (bool)param[0] : false); Result ret = StartRoutine(_unloadRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartAutoUnload(object[] param) { QueueRoutine.Clear(); _autoUnloadRoutine.Init(param.Length > 0 ? (bool)param[0] : false); Result ret = StartRoutine(_autoUnloadRoutine); if (ret == Result.FAIL || ret == Result.DONE) return false; return ret == Result.RUN; } private bool FsmStartHome(object[] param) { Result ret = StartRoutine(_homeRoutine); if (ret == Result.FAIL || ret == Result.DONE) return 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) { return true; } return false; } private bool FsmExitError(object[] param) { return true; } private bool FsmEnterError(object[] param) { if (OnEnterError != null) OnEnterError(Module); return true; } private bool FsmAbortTask(object[] param) { AbortRoutine(); return true; } private bool FsmToInit(object[] param) { return true; } private bool FsmOnError(object[] param) { if (FsmState == (int)STATE.Error) { return false; } if (FsmState != (int)STATE.Init && FsmState != (int)STATE.Idle) AbortRoutine(); //AbortRoutine(); //if (FsmState == (int)STATE.Init) // return false; return true; } public void InvokeLoad() { CheckToPostMessage((int)MSG.Load); } public void InvokeUnload() { CheckToPostMessage((int)MSG.Unload); } #endregion } }