using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Fsm; using Aitex.Core.RT.Log; using Aitex.Core.Util; using Aitex.Core.Utilities; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.WaferHolder; using System; using MECF.Framework.Common.ToolLayout; using MECF.Framework.Common.Persistent.Reservoirs; using Aitex.Core.RT.OperationCenter; using MECF.Framework.Common.RecipeCenter; using Aitex.Core.RT.RecipeCenter; using MECF.Framework.Common.SubstrateTrackings; using Aitex.Core.RT.Device; using MECF.Framework.Common.Routine; using MECF.Framework.Common.ProcessCell; using Aitex.Core.RT.SCCore; using MECF.Framework.Common.Alarm; using CyberX8_Core; using CyberX8_RT.Devices.Metal; using CyberX8_RT.Devices.Reservoir; using CyberX8_RT.Modules.Metal; using CyberX8_RT.Modules.Reservoir; using CyberX8_RT.Modules; using CyberX8_RT.Modules.EFEM; using static Mono.Security.X509.X520; namespace CyberX8_RT.Modules.Metal { public class MetalEntity : Entity, IEntity, IModuleEntity { #region 常量 private const string STRATUS = "Stratus"; private const string AUTO = "Auto"; private const string MANUAL = "Manual"; private const string DISABLED = "Disabled"; private const string ENGINEERING = "Engineering"; private const string PRODUCTION = "Production"; #endregion #region 内部变量 /// /// 已经完成的Cycle次数 /// private int _achievedCycle = 0; /// /// Metal项 /// private MetalItem _metalItem; /// /// 持久化对象 /// private MetalPersistentValue _persistentValue; /// /// c&m Initialize routine /// private CompactEmbranceInitializeRoutine _compactEmbranceInitializeRoutine; /// /// C&M Runrecipe routine /// private CompactEmbranceRunRecipeRoutine _compactEmbranceRunRecipeRoutine; /// /// S&H Initialize Routine /// private StandardHotInitializeRoutine _standardHotInitializeRoutine; /// /// S&H RunRecipe Routine /// private StandardHotRunRecipeRoutine _standardHotRunRecipeRoutine; /// /// Current short test routine /// private CurrentShortTestRoutine _currentShortTestRoutine; /// /// 当前Recipe /// private DepRecipe _currentRecipe = null; /// /// recipe时间 /// private int _recipeTime; /// /// 循环次数 /// private int _cycle = 0; /// /// 运行Recipe面 /// private string _recipeSide = ""; /// /// 当前RunRecipe Routine /// private RoutineBase _currentRunRecipeRoutine; /// /// Runrecipe已经运行的时间 /// private int _runrecipeElapsedTime = 0; /// /// run recipe start time /// private DateTime _runRecipeStartTime; /// /// run recipe complete time /// private DateTime _runRecipeCompleteTime; /// /// 所在reservoir /// private StandardHotReservoirDevice _reservoirDevice; /// /// 所在reservoir名字 /// private string _reservoirName; /// /// 当前完成recipe次数 /// private int _currentCycleTimes; #endregion #region 属性 /// /// 模块名称 /// public ModuleName Module { get; private set; } /// /// 初始化状态 /// public bool IsInit { get { return fsm.State == (int)MetalState.Init; } } /// /// 空闲状态 /// public bool IsIdle { get { return fsm.State == (int)MetalState.Idle; } } /// /// 是否发生错误 /// public bool IsError { get { return fsm.State == (int)MetalState.Error; } } /// /// 是否正在作业 /// public bool IsBusy { get { return fsm.State > (int)MetalState.Idle; } } /// /// 是否初始化完成 /// public bool IsInitialized { get { return fsm.State >= (int)MetalState.Initialized; } } /// /// 是否禁用 /// public bool IsDisable { get { return _persistentValue == null || _persistentValue.OperatingMode == DISABLED; } } /// /// 自动模式 /// public bool IsAuto { get { return _persistentValue != null && _persistentValue.OperatingMode == AUTO; } } /// /// 自动模式 /// public bool IsManual { get { return _persistentValue != null && _persistentValue.OperatingMode == MANUAL; } } /// /// 是否为工程模式 /// public bool IsEngineering { get { return _persistentValue != null && _persistentValue.RecipeOperatingMode == ENGINEERING; } } /// /// 是否为产品模式 /// public bool IsProduction { get { return _persistentValue != null && _persistentValue.RecipeOperatingMode == PRODUCTION; } } /// /// WaferHolder信息 /// public WaferHolderInfo WaferHolderInfo { get { return WaferHolderManager.Instance.GetWaferHolder(Module.ToString()); } } /// /// 已完成的RunRecipeCycle次数 /// public int AchievedCycle { get { return _achievedCycle; } } /// /// 当前状态机状态 /// public int State { get { return fsm.State; } } /// /// 当前Metal设置的WaferSize /// public int MetalWaferSize { get { return _persistentValue.MetalWaferSize; } } /// /// recipe时长 /// public int RecipeTime { get { return _recipeTime; } } /// /// 剩余时间 /// public override int TimeToReady { get { if (IsIdle) { return 0; } switch (fsm.State) { case (int)MetalState.RunReciping: return Math.Max(_recipeTime - fsm.ElapsedTime / 1000, 0); default: return 0; } } } /// /// 用量 /// public MetalUsage MetalUsage { get { return MetalUsageManager.Instance.GetMetalUsage(Module.ToString()); } } #endregion /// /// 构造函数 /// /// public MetalEntity(ModuleName moduleName) { this.Module = moduleName; WaferManager.Instance.SubscribeLocation(Module, 2); InitialFsm(); } /// /// 初始化 /// /// protected override bool Init() { InitializeDATA(); InitializeParameter(); InitializeRoutine(); InitializeOperation(); return true; } /// /// 初始化参数 /// private void InitializeParameter() { _persistentValue = MetalPersistentManager.Instance.GetMetalPersistentValue(Module.ToString()); if (_persistentValue == null) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Persistent Value Object is not exist"); } _metalItem = MetalItemManager.Instance.GetMetalItem(Module.ToString()); _reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString()); _reservoirDevice = DEVICE.GetDevice($"{_reservoirName}"); } /// /// 初始化Routine /// private void InitializeRoutine() { _compactEmbranceInitializeRoutine = new CompactEmbranceInitializeRoutine(Module.ToString()); _standardHotInitializeRoutine = new StandardHotInitializeRoutine(Module.ToString()); _compactEmbranceRunRecipeRoutine = new CompactEmbranceRunRecipeRoutine(Module.ToString()); _standardHotRunRecipeRoutine = new StandardHotRunRecipeRoutine(Module.ToString()); _currentShortTestRoutine = new CurrentShortTestRoutine(Module.ToString()); } /// /// 初始化操作 /// private void InitializeOperation() { OP.Subscribe($"{Module}.InitializeAll", (cmd, args) => { return CheckToPostMessage(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Initialize); }); OP.Subscribe($"{Module}.CycleManualProcessRecipe", (cmd, args) => { DepRecipe recipe = RecipeFileManager.Instance.LoadGenericityRecipe(args[0].ToString()); if (recipe == null) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{args[0]} recipe is null"); return false; } object[] objects = new object[args.Length]; objects[0] = recipe; for (int i = 1; i < args.Length; i++) { objects[i] = args[i]; } return CheckToPostMessage(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.RunRecipe, objects); }); OP.Subscribe($"{Module}.CurrentShortTest", (cmd, args) => { return CheckToPostMessage(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.CurrentShortTest); }); OP.Subscribe($"{Module}.UpdateMetalUsage", UpdateMetalUsageAction); OP.Subscribe($"{Module}.Abort", (cmd, args) => { return CheckToPostMessage(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Abort); }); } /// /// EnterInit /// public void EnterInit() { if ((MetalState)fsm.State != MetalState.Idle) return; else { CheckToPostMessage(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Init); } } /// 初始化状态机 /// private void InitialFsm() { fsm = new StateMachine(Module.ToString(), (int)MetalState.Init, 20); fsm.EnableRepeatedMsg(true); AnyStateTransition(MetalMsg.Error, EnterError, MetalState.Error); //Initialize AnyStateTransition(MetalMsg.Initialize, InitializeAll, MetalState.Initializing); Transition(MetalState.Initializing, FSM_MSG.TIMER, InitializeAllMonitor, MetalState.Initialized); //直接进入Idle Transition(MetalState.Initialized, FSM_MSG.TIMER, NullFunc, MetalState.Idle); //RunRecipe Transition(MetalState.Idle, MetalMsg.RunRecipe, RunRecipe, MetalState.RunReciping); Transition(MetalState.WaitForRunRecipe, MetalMsg.RunRecipe, RunRecipe, MetalState.RunReciping); Transition(MetalState.RunReciping, FSM_MSG.TIMER, RunRecipeMonitor, MetalState.Idle); Transition(MetalState.RunReciping, MetalMsg.Abort, AbortRecipe, MetalState.Abort); //Current Short Test Transition(MetalState.Idle, MetalMsg.CurrentShortTest, CurrentShortTest, MetalState.CurrentShortTesting); Transition(MetalState.CurrentShortTesting, FSM_MSG.TIMER, CurrentShortTestMonitor, MetalState.WaitCloseFlow); Transition(MetalState.WaitCloseFlow, MetalMsg.CloseFlowValve, CloseFlowValve, MetalState.WaitOpenFlow); Transition(MetalState.WaitOpenFlow, MetalMsg.OpenFlowValve, OpenFlowValve, MetalState.WaitForRunRecipe); //Enter Init Transition(MetalState.Idle, MetalMsg.Init, NullFunc, MetalState.Init); EnumLoop.ForEach((item) => { fsm.MapState((int)item, item.ToString()); }); EnumLoop.ForEach((item) => { fsm.MapMessage((int)item, item.ToString()); }); } /// /// 初始化DATA /// private void InitializeDATA() { InitializeSVID(); DATA.Subscribe($"{Module}.FsmState", () => ((MetalState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.WaferHolder", () => WaferHolderInfo, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AchievedCycle", () => AchievedCycle, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsInit", () => IsInit, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsIdle", () => IsIdle, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsError", () => IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsBusy", () => IsBusy, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.IsDisable", () => IsDisable, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CurrentRecipe", () => _currentRecipe != null ? _currentRecipe.Ppid : "", SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.MetalUsage", () => MetalUsage, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.SubordinateReservoirName", () => _reservoirName, SubscriptionAttribute.FLAG.IgnoreSaveDB); } /// /// 初始化SVID /// private void InitializeSVID() { DATA.Subscribe($"{Module}.State", () => ((MetalState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.LotID", () => WaferHolderInfo?.LotId , SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.WSID", () => WaferHolderInfo?.Id, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.LSAID", () => WaferHolderInfo?.CrsAId, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.LSBID", () => WaferHolderInfo?.CrsBId, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ModuleRecipe", () => _currentRecipe?.Ppid, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.SequenceRecipe", () =>WaferHolderInfo?.SequenceId, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.WaferAID", () => WaferHolderInfo?.WaferAId, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.WaferBID", () => WaferHolderInfo?.WaferBId, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.TotalTime", () => _recipeTime, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.TimeRemain", () => _recipeTime != 0 && _currentRunRecipeRoutine != null ? (_recipeTime - Math.Round((double)_currentRunRecipeRoutine.ElapsedMilliseconds / 1000, 0)) : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.Task", () => WaferHolderInfo?.CurrentControlJobId, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.OperatingMode", () => _persistentValue != null ? _persistentValue.OperatingMode : "None", SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.TotalUsage", () => MetalUsage != null ? MetalUsage.TotalUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.TotalUsage.WarningLimit", () => SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.TotalUsage.FaultLimit", () => SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeAUsage", () => MetalUsage != null ? MetalUsage.AnodeAUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeAUsage.WarningLimit", () => SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeAUsage.FaultLimit", () => SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeBUsage", () => MetalUsage != null ? MetalUsage.AnodeBUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeBUsage.WarningLimit", () => SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeBUsage.FaultLimit", () => SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.MembranceAUsage", () => MetalUsage != null ? MetalUsage.MembranceAUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.MembranceAUsage.WarningLimit", () => SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.MembranceAUsage.FaultLimit", () => SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.MembranceBUsage", () => MetalUsage != null ? MetalUsage.MembranceBUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.MembranceBUsage.WarningLimit", () => SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.MembranceBUsage.FaultLimit", () => SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.TotalWafers", () => MetalUsage != null ? MetalUsage.TotalWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.TotalWafers.WarningLimit", () => SC.GetValue($"Metal.{Module}.MetalTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.TotalWafers.FaultLimit", () => SC.GetValue($"Metal.{Module}.MetalTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeAWafers", () => MetalUsage != null ? MetalUsage.AnodeAWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeAWafers.WarningLimit", () => SC.GetValue($"Metal.{Module}.AnodeATotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeAWafers.FaultLimit", () => SC.GetValue($"Metal.{Module}.AnodeATotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeBWafers", () => MetalUsage != null ? MetalUsage.AnodeBWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeBWafers.WarningLimit", () => SC.GetValue($"Metal.{Module}.AnodeBTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.AnodeBWafers.FaultLimit", () => SC.GetValue($"Metal.{Module}.AnodeBTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB); } /// /// 进入错误状态 /// /// /// private bool EnterError(object[] args) { if (State == (int)MetalState.RunReciping) { if (_metalItem.SubType == STRATUS) { _standardHotRunRecipeRoutine.Abort(); } else { _compactEmbranceRunRecipeRoutine.Abort(); } } return true; } /// /// UpdateMetalUsageAction /// /// /// /// private bool UpdateMetalUsageAction(string cmd, object[] args) { if (args.Length > 2) { MetalUsageManager.Instance.UpdateMetalUsageByManualOperation(args[0].ToString(), args[1].ToString(), args[2].ToString()); LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"New {args[1].ToString()} value {args[2].ToString()} was input"); } return true; } #region Initialize All /// /// 初始化 /// /// /// private bool InitializeAll(object[] param) { if (fsm.State == (int)MetalState.Initializing) { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), "state is Initializing,cannot do initialize"); return false; } if (!CheckReservoirInitialized()) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not initialized"); return false; } if (!MetalUsageMointor(Module.ToString())) { return false; } if ("Auto".Equals(_persistentValue.OperatingMode)) { if (!CheckReservoirIsAuto()) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not in Auto OperationMode"); return false; } } if (_metalItem.SubType == STRATUS) { return _standardHotInitializeRoutine.Start(_persistentValue) == RState.Running; } else { return _compactEmbranceInitializeRoutine.Start(_persistentValue) == RState.Running; } } /// /// 检验Reservoir是否Initialized /// /// private bool CheckReservoirInitialized() { string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString()); ReservoirEntity reservoirEntity = Singleton.Instance.GetModule(reservoir); if (reservoirEntity != null) { return reservoirEntity.IsInitialized; } return false; } /// /// 检验Reservoir是否Auto /// /// private bool CheckReservoirIsAuto() { string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString()); ReservoirsPersistentValue reservoirsPersistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(reservoir); if ("Auto".Equals(reservoirsPersistentValue.OperatingMode)) { return true; } return false; } /// /// 初始化监控 /// /// /// private bool InitializeAllMonitor(object[] param) { RState rsstate = RState.Running; if (_metalItem.SubType == STRATUS) { rsstate = _standardHotInitializeRoutine.Monitor(); } else { rsstate = _compactEmbranceInitializeRoutine.Monitor(); } if (rsstate == RState.End) { return true; } else if (rsstate == RState.Failed || rsstate == RState.Timeout) { PostMsg(MetalMsg.Error); return false; } return false; } #endregion #region RunRecipe /// /// Run Recipe /// /// /// private bool RunRecipe(object[] param) { MetalUsageMointor(); //Metal run recipe前检查PMCounter消耗 string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString()); if (_metalItem.SubType == STRATUS) { StandardHotReservoirDevice resDevice = DEVICE.GetDevice(reservoirName); resDevice.ReservoirUsageMonitor(); } DepRecipe recipe = param[0] as DepRecipe; _recipeSide = param[1].ToString(); _cycle = (int)param[2]; _runrecipeElapsedTime = 0; bool result = false; if (_metalItem.SubType == STRATUS) { _currentRunRecipeRoutine = _standardHotRunRecipeRoutine; result = _standardHotRunRecipeRoutine.Start(recipe, _recipeSide,_cycle) == RState.Running; } else { _currentRunRecipeRoutine = _compactEmbranceRunRecipeRoutine; result = _compactEmbranceRunRecipeRoutine.Start(recipe, _recipeSide, _cycle) == RState.Running; } if (result) { if (WaferHolderInfo != null) { WaferHolderInfo.MetalModuleName = Module; } _recipeTime = (recipe.CalculateRecipeTotalTime())*_cycle; _currentRecipe = recipe; if (WaferHolderInfo != null && WaferHolderInfo.SchedulerModules != null && WaferHolderInfo.SchedulerModules.Count != 0) { LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"{WaferHolderInfo?.Id} {string.Join(",", WaferHolderInfo.SchedulerModules)}"); } _runRecipeStartTime = DateTime.Now; if (WaferHolderInfo != null && _currentRecipe != null) { FaModuleNotifier.Instance.NotifyWaferShuttleRecipeStart(WaferHolderInfo, _currentRecipe.Ppid); } } return result; } /// /// RunRecipe监控 /// /// /// private bool RunRecipeMonitor(object[] param) { RState rsstate = RState.Running; if (_metalItem.SubType == STRATUS) { rsstate = _standardHotRunRecipeRoutine.Monitor(); if (rsstate == RState.Running) { StandardHotMetalDevice _standardHotMetalDevice = DEVICE.GetDevice(Module.ToString()); if (_standardHotMetalDevice.MetalDeviceData.CellFlow <= 0) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir metal cell flow is 0"); rsstate = RState.Failed; } } _achievedCycle = _standardHotRunRecipeRoutine.GetCurrentCycle(); } else { rsstate = _compactEmbranceRunRecipeRoutine.Monitor(); if (rsstate == RState.Running) { CompactMembranMetalDevice _compactMembranMetalDevice = DEVICE.GetDevice(Module.ToString()); if (_compactMembranMetalDevice.MetalDeviceData.CellFlow <= 0) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir metal cell flow is 0"); rsstate = RState.Failed; } if (_compactMembranMetalDevice.ANACellFlow.CounterValue <= 0) //检查hold flow { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir AnodeA flow is 0"); rsstate = RState.Failed; } if (_compactMembranMetalDevice.ANBCellFlow.CounterValue <= 0) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir AnodeB flow is 0"); rsstate = RState.Failed; } } } if (Singleton.Instance.IsAutoRunning && _runrecipeElapsedTime != TimeToReady) { _runrecipeElapsedTime = TimeToReady; LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"{WaferHolderInfo?.Id} {Module} RunRecipe TimeToReady {TimeToReady}s."); } if (rsstate == RState.End) { _recipeTime = 0; if (WaferHolderInfo != null) { double anodeAUsage = GetAnodeAUsage(); double anodeBUsage = GetAnodeBUsage(); MetalUsageManager.Instance.UpdateMetalUsage(Module.ToString(), _recipeSide, anodeAUsage, anodeBUsage); MetalUsageMointor(); //检查PMCounter消耗 //CMM Usage string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString()); if (_metalItem.SubType == STRATUS) { StandardHotReservoirDevice resDevice = DEVICE.GetDevice(reservoirName); resDevice.ReservoirUsageMonitor(); resDevice.SetExportCMMUsage(); } WaferHolderInfo.LastMetalRecipeCompleteTime = DateTime.Now; } _runrecipeElapsedTime = 0; //记录LotTrack _runRecipeCompleteTime = DateTime.Now; int timeLength = (int)(_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds; if (_metalItem.SubType == STRATUS) { _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2"); MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _standardHotRunRecipeRoutine.MetalLotTrackDatas, _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType); } else { _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2"); MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas, _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType); } if (WaferHolderInfo != null && _currentRecipe != null) { FaModuleNotifier.Instance.NotifyWaferShuttleRecipeEnd(WaferHolderInfo, _currentRecipe.Ppid, timeLength); } return true; } else if (rsstate == RState.Failed || rsstate == RState.Timeout) { _recipeTime = 0; if (WaferHolderInfo != null) { double anodeAUsage = GetAnodeAUsage(); double anodeBUsage = GetAnodeBUsage(); MetalUsageManager.Instance.UpdateMetalUsage(Module.ToString(), _recipeSide, anodeAUsage, anodeBUsage); MetalUsageMointor(); //失败了也要检查PMCounter消耗 //CMMUsage string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString()); if (_metalItem.SubType == STRATUS) { StandardHotReservoirDevice resDevice = DEVICE.GetDevice(reservoirName); resDevice.ReservoirUsageMonitor(); resDevice.SetExportCMMUsage(); } } _runrecipeElapsedTime = 0; if (WaferHolderInfo != null && _currentRecipe != null) { WaferHolderInfo.LastMetalRecipeCompleteTime = DateTime.Now; } PostMsg(MetalMsg.Error); //记录LotTrack _runRecipeCompleteTime = DateTime.Now; if (_metalItem.SubType == STRATUS) { _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2"); MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _standardHotRunRecipeRoutine.MetalLotTrackDatas, _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType); } else { _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2"); MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas, _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType); } if (WaferHolderInfo != null && _currentRecipe != null) { FaModuleNotifier.Instance.NotifyWaferShuttleRecipeFailed(WaferHolderInfo, _currentRecipe.Ppid); } return false; } return false; } /// /// 监控 PM Counter Metal用量 /// private void MetalUsageMointor() { MetalUsage metalUsage = MetalUsageManager.Instance.GetMetalUsage(Module.ToString()); if (metalUsage != null) { //TotalAUsage if (metalUsage.TotalUsage > SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursFaultLimit") != 0) { if (metalUsage.TotalUsage > SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.TotalUsage", $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.TotalUsage", $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}"); } } //AnodeAUsage if (metalUsage.AnodeAUsage > SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit") != 0) { if (metalUsage.AnodeAUsage > SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeAUsage", $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeAUsage", $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}"); } } //AnodeBUsage if (metalUsage.AnodeBUsage > SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit") != 0) { if (metalUsage.AnodeBUsage > SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeBUsage", $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeBUsage", $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}"); } } //MembraneAUsage if (metalUsage.MembranceAUsage > SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit") != 0) { if (metalUsage.MembranceAUsage > SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.MembraneAUsage", $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.MembraneAUsage", $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}"); } } //MembraneBUsage if (metalUsage.MembranceBUsage > SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit") != 0) { if (metalUsage.MembranceBUsage > SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.MembraneBUsage", $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.MembraneBUsage", $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}"); } } //TotalWafer if (metalUsage.TotalWafers > SC.GetValue($"Metal.{Module}.MetalTotalWafersWarningLimit") && SC.GetValue($"Metal.{Module}.MetalTotalWafersWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.MetalTotalWafersFaultLimit") != 0) { if (metalUsage.TotalWafers > SC.GetValue($"Metal.{Module}.MetalTotalWafersFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue($"Metal.{Module}.MetalTotalWafersFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.TotalWafers", $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue($"Metal.{Module}.MetalTotalWafersFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue($"Metal.{Module}.MetalTotalWafersWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.TotalWafers", $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue($"Metal.{Module}.MetalTotalWafersWarningLimit")}"); } } //AnodeAWafer if (metalUsage.AnodeAWafers > SC.GetValue($"Metal.{Module}.AnodeATotalWafersWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeATotalWafersWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeATotalWafersFaultLimit") != 0) { if (metalUsage.AnodeAWafers > SC.GetValue($"Metal.{Module}.AnodeATotalWafersFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalWafersFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeAWafers", $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalWafersFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalWafersWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeAWafers", $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalWafersWarningLimit")}"); } } //AnodeBWafer if (metalUsage.AnodeBWafers > SC.GetValue($"Metal.{Module}.AnodeBTotalWafersWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeBTotalWafersWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeBTotalWafersFaultLimit") != 0) { if (metalUsage.AnodeBWafers > SC.GetValue($"Metal.{Module}.AnodeBTotalWafersFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeBWafers", $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeBWafers", $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}"); } } //AnodeAbathUsage if (metalUsage.AnodeABathUsage > SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit") != 0) { if (metalUsage.AnodeABathUsage > SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeABathUsage", $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeABathUsage", $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}"); } } //AnodeBbathUsage if (metalUsage.AnodeBBathUsage > SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit") != 0) { if (metalUsage.AnodeBBathUsage > SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}"); PostMsg(MetalMsg.Error); AlarmListManager.Instance.AddDataError(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeBBathUsage", $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}"); AlarmListManager.Instance.AddWarn(Module.ToString(), $"{Module.ToString()}.metalUsage.AnodeBBathUsage", $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}"); } } } } /// /// 获取A面使用的电量 /// /// private double GetAnodeAUsage() { if (_metalItem.SubType == STRATUS) { return Math.Round(_standardHotRunRecipeRoutine.AnodeAUsage, 3); } else { return Math.Round(_compactEmbranceRunRecipeRoutine.AnodeAUsage, 3); } } /// /// 获取B面使用的电量 /// /// private double GetAnodeBUsage() { if (_metalItem.SubType == STRATUS) { return Math.Round(_standardHotRunRecipeRoutine.AnodeBUsage, 3); } else { return Math.Round(_compactEmbranceRunRecipeRoutine.AnodeBUsage, 3); } } /// /// Abort Recipe /// /// /// public bool AbortRecipe(object[] param) { _runRecipeCompleteTime = DateTime.Now; if (_metalItem.SubType == STRATUS) { _standardHotRunRecipeRoutine.Abort(); _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2"); MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _standardHotRunRecipeRoutine.MetalLotTrackDatas, _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType); } else { _compactEmbranceRunRecipeRoutine.Abort(); _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2"); MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas, _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType); } return true; } #endregion #region Current Short Test /// /// Current Short Test /// /// /// private bool CurrentShortTest(object[] param) { return _currentShortTestRoutine.Start() == RState.Running; } /// /// Current Short test监控 /// /// /// private bool CurrentShortTestMonitor(object[] param) { RState rsstate = _currentShortTestRoutine.Monitor(); if (rsstate == RState.End) { return true; } else if (rsstate == RState.Failed || rsstate == RState.Timeout) { PostMsg(MetalMsg.Error); return false; } return false; } #endregion #region Close Flow Valve /// /// 关闭Flow Valve /// /// /// private bool CloseFlowValve(object[] param) { if (_metalItem.SubType == STRATUS) { StandardHotMetalDevice device = DEVICE.GetDevice(Module.ToString()); if (device != null) { return device.SwitchToBypass("", null); } return false; } else { CompactMembranMetalDevice device = DEVICE.GetDevice(Module.ToString()); if (device != null) { string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString()); CompactMembranReservoirDevice reservoirDevice = DEVICE.GetDevice(reservoir); if (reservoirDevice != null) { bool result = reservoirDevice.CAByPassOn("", null); if (result) { return device.CellFlowValveOff("", null); } } } return false; } } #endregion #region Open Flow Valve /// /// 打开Flow Valve /// /// /// private bool OpenFlowValve(object[] param) { if (_metalItem.SubType == STRATUS) { StandardHotMetalDevice device = DEVICE.GetDevice(Module.ToString()); if (device != null) { bool result = device.SwitchToFlow("", null); if (result) { return device.OpenPump("", null); } } return false; } else { CompactMembranMetalDevice device = DEVICE.GetDevice(Module.ToString()); if (device != null) { string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString()); CompactMembranReservoirDevice reservoirDevice = DEVICE.GetDevice(reservoir); if (reservoirDevice != null) { bool result = reservoirDevice.CAByPassOff("", null); if (result) { return device.CellFlowValveOn("", null); } } } return false; } } #endregion public bool Check(int msg, out string reason, params object[] args) { reason = ""; return true; } public bool CheckAcked(int msg) { return true; } public int Invoke(string function, params object[] args) { switch (function) { case "HomeAll": if (IsIdle) { return (int)FSM_MSG.NONE; } if (CheckToPostMessage(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Initialize)) { return (int)MetalMsg.Initialize; } else { return (int)FSM_MSG.NONE; } } return (int)FSM_MSG.NONE; } /// /// 监控 PM Counter Metal用量 /// private bool MetalUsageMointor(string Module) { MetalUsage metalUsage = MetalUsageManager.Instance.GetMetalUsage(Module); if (metalUsage != null) { //TotalAUsage if (metalUsage.TotalUsage > SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursFaultLimit") != 0) { if (metalUsage.TotalUsage > SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}"); return false; } else { LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}"); } } //AnodeAUsage if (metalUsage.AnodeAUsage > SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit") != 0) { if (metalUsage.AnodeAUsage > SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}"); return false; } else { LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}"); } } //AnodeBUsage if (metalUsage.AnodeBUsage > SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit") != 0) { if (metalUsage.AnodeBUsage > SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}"); return false; } else { LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}"); } } //MembraneAUsage if (metalUsage.MembranceAUsage > SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit") != 0) { if (metalUsage.MembranceAUsage > SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}"); return false; } else { LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}"); } } //MembraneBUsage if (metalUsage.MembranceBUsage > SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") && SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit") != 0) { if (metalUsage.MembranceBUsage > SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}"); } else { LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}"); } } //TotalWafer if (metalUsage.TotalWafers > SC.GetValue($"Metal.{Module}.MetalTotalWafersWarningLimit") && SC.GetValue($"Metal.{Module}.MetalTotalWafersWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.MetalTotalWafersFaultLimit") != 0) { if (metalUsage.TotalWafers > SC.GetValue($"Metal.{Module}.MetalTotalWafersFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue($"Metal.{Module}.MetalTotalWafersFaultLimit")}"); return false; } else { LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue($"Metal.{Module}.MetalTotalWafersWarningLimit")}"); } } //AnodeAWafer if (metalUsage.AnodeAWafers > SC.GetValue($"Metal.{Module}.AnodeATotalWafersWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeATotalWafersWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeATotalWafersFaultLimit") != 0) { if (metalUsage.AnodeAWafers > SC.GetValue($"Metal.{Module}.AnodeATotalWafersFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalWafersFaultLimit")}"); return false; } else { LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeATotalWafersWarningLimit")}"); } } //AnodeBWafer if (metalUsage.AnodeBWafers > SC.GetValue($"Metal.{Module}.AnodeBTotalWafersWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeBTotalWafersWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeBTotalWafersFaultLimit") != 0) { if (metalUsage.AnodeBWafers > SC.GetValue($"Metal.{Module}.AnodeBTotalWafersFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}"); return false; } else { LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}"); } } //AnodeAbathUsage if (metalUsage.AnodeABathUsage > SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit") != 0) { if (metalUsage.AnodeABathUsage > SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}"); return false; } else { LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}"); } } //AnodeBbathUsage if (metalUsage.AnodeBBathUsage > SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") && SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") != 0 && SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit") != 0) { if (metalUsage.AnodeBBathUsage > SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}"); return false; } else { LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}"); } } } return true; } } public enum MetalMsg { NONE, Error, ResumeError, Initialize, Manual, Auto, CurrentShortTest, CloseFlowValve, OpenFlowValve, RunRecipe, Abort, Init } }