using Aitex.Core.Common; using Aitex.Core.RT.Event; 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 MECF.Framework.Common.DBCore; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Alarms; using MECF.Framework.Common.Event; using MECF.Framework.Common.SubstrateTrackings; using System; using System.Collections.Generic; using FurnaceRT.Equipments.PMs.Routines; using System.Diagnostics; namespace FurnaceRT.Equipments.PMs.RecipeExecutions { public enum RecipeContinueMode { None, WaferReturnAndJobStop, RecipeCompleted, StepContinue, StepRestart, RecipeRestart, NextStep, } public class Process : PMBaseRoutine { enum RecipeRunningState { Error, RecipeCompleted, ExecStep, TimeWait, ConditionWait, StepCompleted, Paused, } enum RecipeAlaramAction { None, JumpAbortRecipe, JumpStep, JumpStepCancelCallLoop, Abort, Hold, IgnoreAlaram, } private object _recipeLocker = new object(); private RecipeRunningState _state = RecipeRunningState.ExecStep; private RecipeRunningState _pausedState = RecipeRunningState.ExecStep; private double _curStepElpasedTimeBeforePaused; private double _holdTimeElpasedTime; private double _waferTimeElpasedTimeBeforPaused; private double _totalElpasedTime; public RecipeContinueMode ContinueAction { get; set; } public DateTime _recipeStartTime { get; private set; } public string CurrentRecipeContent { get; private set; } private int _currentStepNumber; private int _currentSubRecipeStepNumber; private bool _loopEnd; public int CurStepTotalLoopCount { get; private set; } public int CurSubRecipeStepTotalLoopCount { get; private set; } public double CurStepTotalTime { get { if (PMModule.RecipeRunningInfo.RecipeStepList == null || PMModule.RecipeRunningInfo.RecipeStepList.Count == 0 || _state == RecipeRunningState.RecipeCompleted || _state == RecipeRunningState.Error) return 0; return PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime * 1000; } } public int CurrentLoopCount { get; private set; } public int CurrentAbortRecipeLoopCount { get; private set; } public int CurrentSubRecipeLoopCount { get; private set; } public bool IsExecuteAbort { get; private set; } public bool IsSubReciep { get; private set; } public int AlarmConditionJumpStep { get; set; } = -1; private DeviceTimer _stepTimer = new DeviceTimer(); private DeviceTimer _holdTimer = new DeviceTimer(); private RecipeFACallback _faCallback; private RecipeDBCallback _dbCallback; private Fdc _fdc; private ModuleName _doModule = ModuleName.PM1; private bool IsJumpStepCancelCallLoop; private int _jumpStepNumber; private int _showStepNo; private int _subRecipeStartStepNumber; private RecipeAlaramAction _alarmAction = RecipeAlaramAction.None; public List _alarmNames { private set; get; } private R_TRIG _trigHeaterBottomToleranceAlarm = new R_TRIG(); private R_TRIG _trigHeaterBottomToleranceWarning = new R_TRIG(); private R_TRIG _trigHeaterCenterBottomToleranceAlarm = new R_TRIG(); private R_TRIG _trigHeaterCenterBottomToleranceWarning = new R_TRIG(); private R_TRIG _trigHeaterCenterToleranceAlarm = new R_TRIG(); private R_TRIG _trigHeaterCenterToleranceWarning = new R_TRIG(); private R_TRIG _trigHeaterCenterTopToleranceAlarm = new R_TRIG(); private R_TRIG _trigHeaterCenterTopToleranceWarning = new R_TRIG(); private R_TRIG _trigHeaterTopToleranceAlarm = new R_TRIG(); private R_TRIG _trigHeaterTopToleranceWarning = new R_TRIG(); private R_TRIG _trigPressureToleranceAlarm = new R_TRIG(); private R_TRIG _trigPressureToleranceWarning = new R_TRIG(); private R_TRIG _trigInputSignalTimeOutAlarm = new R_TRIG(); private R_TRIG _trigTemperatureConvergenceTimeOutAlarm = new R_TRIG(); private R_TRIG _trigReachTempTimeOutAlarm = new R_TRIG(); private R_TRIG _trigPressureConvergenceTimeOutAlarm = new R_TRIG(); private R_TRIG _trigReachPressureTimeOutAlarm = new R_TRIG(); private R_TRIG _trigAutoProfileTimeOutAlarm = new R_TRIG(); private Dictionary _trigMfcToleranceAlarms; private Dictionary _trigMfcToleranceWarnings; private R_TRIG _trigBoatMoveToLoadPositionTimeout = new R_TRIG(); private R_TRIG _trigHeaterProfileFinish = new R_TRIG(); private R_TRIG _trigLeakCheckFinish = new R_TRIG(); private R_TRIG _trigBoatWaitCondition = new R_TRIG(); private R_TRIG _trigAPCWaitCondition = new R_TRIG(); private R_TRIG _trigAUXWaitCondition = new R_TRIG(); private R_TRIG _trigHeaterWaitCondition = new R_TRIG(); private R_TRIG _trigMFCWaitCondition = new R_TRIG(); private string _infoHeaterProfileFinish = ""; private string _infoAUXWaitCondition = ""; private string _infoHeaterWaitCondition = ""; private string _infoMFCWaitCondition = ""; private Dictionary> _callSubSteps = new Dictionary>(); private bool _isJumpStep = false; public Process(ModuleName module, PMModule pm) : base(module, pm) { Module = module.ToString(); Name = "Process"; _trigMfcToleranceAlarms = new Dictionary() { {"MFC61", new R_TRIG() }, {"MFC13", new R_TRIG() }, {"MFC14", new R_TRIG() }, {"MFC15", new R_TRIG() }, {"MFC16", new R_TRIG() }, {"MFC24", new R_TRIG() }, {"MFC25", new R_TRIG() }, {"MFC26", new R_TRIG() }, {"MFC34", new R_TRIG() }, {"MFC35", new R_TRIG() }, {"MFC36", new R_TRIG() }, {"MFC90", new R_TRIG() }, {"MFC91", new R_TRIG() }, {"MFC84", new R_TRIG() }, }; _trigMfcToleranceWarnings = new Dictionary() { {"MFC61", new R_TRIG() }, {"MFC13", new R_TRIG() }, {"MFC14", new R_TRIG() }, {"MFC15", new R_TRIG() }, {"MFC16", new R_TRIG() }, {"MFC24", new R_TRIG() }, {"MFC25", new R_TRIG() }, {"MFC26", new R_TRIG() }, {"MFC34", new R_TRIG() }, {"MFC35", new R_TRIG() }, {"MFC36", new R_TRIG() }, {"MFC90", new R_TRIG() }, {"MFC91", new R_TRIG() }, {"MFC84", new R_TRIG() }, }; _faCallback = new RecipeFACallback(); _dbCallback = new RecipeDBCallback(); _fdc = new Fdc(Module); } public override Result Start(params object[] param) { CurStepTotalLoopCount = 0; _currentSubRecipeStepNumber = CurSubRecipeStepTotalLoopCount = 0; if (AlarmConditionJumpStep > 0) _currentStepNumber = AlarmConditionJumpStep; else _currentStepNumber = PMModule.IsJobProcess ? 1 : 0; // 如果是从Job Process开始,从1开始,跳过standby step AlarmConditionJumpStep = -1; PMModule.RecipeRunningInfo.InnerId = Guid.NewGuid(); PMModule.RecipeRunningInfo.BeginTime = DateTime.Now; PMModule.RecipeRunningInfo.TotalTime = CalcRecipeTime(); if (PMModule.RecipeRunningInfo.TotalTime < 0) return Result.FAIL; IsSubReciep = false; IsExecuteAbort = false; IsJumpStepCancelCallLoop = false; PMModule.IsPaused = false; PMModule.IsHeaterProfile = false; PMModule.IsHeaterProfileSuccess = false; PMModule.IsMainRecipeComplete = false; _loopEnd = false; _isJumpStep = false; _curStepElpasedTimeBeforePaused = 0; _waferTimeElpasedTimeBeforPaused = 0; _totalElpasedTime = 0; _holdTimeElpasedTime = 0; _jumpStepNumber = 0; _showStepNo = 0; _state = RecipeRunningState.ExecStep; _alarmAction = RecipeAlaramAction.None; _alarmNames = new List(); _subRecipeStartStepNumber = 1; _callSubSteps.Clear(); PMModule.InitAlarmCondition(PMModule.RecipeRunningInfo.Head.AlarmCondition); PMModule.InitLeakCheck(PMModule.RecipeRunningInfo.Head.LeakCheck); ResetTrig(); Notify($"Start"); _faCallback.RecipeStart(PMModule.Module, PMModule.RecipeRunningInfo.RecipeName); _dbCallback.RecipeStart(PMModule.Module, 0, PMModule.RecipeRunningInfo.InnerId.ToString(), PMModule.RecipeRunningInfo.RecipeName); _dbCallback.RecipeUpdateStatus(PMModule.RecipeRunningInfo.InnerId.ToString(), "InProcess"); _fdc.Reset(); WaferManager.Instance.UpdateWaferProcessStatus(ModuleHelper.Converter(Module), 0, EnumWaferProcessStatus.InProcess); PMModule.HeaterEnable(true); return Result.RUN; } public override Result Monitor() { if (!PMModule.CheckEnableRunProcess(out string reason)) { PMModule.CheckEnableRunProcessAlarm.Set(reason); return Result.FAIL; } //MonitorRecipeAlaramAction(); //if (IsExecuteAbort) // return Result.DONE; MonitorRecipePause(); CheckTolerance(); List curSteps; if ((IsSubReciep || PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsCallSubStep) && !_isJumpStep) { curSteps = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps; if (!_callSubSteps.ContainsKey(_currentStepNumber)) _callSubSteps.Add(_currentStepNumber, Tuple.Create(false, 0)); if (PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsCallSubStep) _callSubSteps[_currentStepNumber] = Tuple.Create(true, PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeLoopCount); if (!IsSubReciep) { PMModule.RecipeRunningInfo.SubRecipeCurrentLoopCount = 1; PMModule.RecipeRunningInfo.SubRecipeLoopCount = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeLoopCount; } PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsCallSubStep = false; IsSubReciep = true; } else { curSteps = PMModule.RecipeRunningInfo.RecipeStepList; PMModule.RecipeRunningInfo.SubRecipeLoopCount = 0; } lock (_recipeLocker) { try { switch (_state) { case RecipeRunningState.ExecStep: { PMModule.IsWait = false; _loopEnd = false; if (!_holdTimer.IsIdle()) { _holdTimeElpasedTime += _holdTimer.GetElapseTime(); _holdTimer.Stop(); } PMModule.ResetToleranceChecker(); _curStepElpasedTimeBeforePaused = 0; ContinueAction = RecipeContinueMode.None; if (IsSubReciep) { if (curSteps[_currentSubRecipeStepNumber].IsLoopStartStep) { CurrentSubRecipeLoopCount++; PMModule.RecipeRunningInfo.IsLooping = true; PMModule.RecipeRunningInfo.LoopCountCurrent = CurrentSubRecipeLoopCount - 1;//即使不循环,本身也有一次。本身的一次不算,所以减1 PMModule.RecipeRunningInfo.LoopCountSet = curSteps[_currentSubRecipeStepNumber].LoopCount - 1;//即使不循环,本身也有一次。本身的一次不算,所以减1 } if (curSteps[_currentSubRecipeStepNumber].IsJumpStep) { _currentSubRecipeStepNumber = curSteps[_currentSubRecipeStepNumber].JumpStepNo; } RecipeExec("Sub recipe", curSteps, _currentSubRecipeStepNumber, _curStepElpasedTimeBeforePaused, _currentSubRecipeStepNumber + 1); } else { if (curSteps[_currentStepNumber].IsLoopStartStep) { CurrentLoopCount++; PMModule.RecipeRunningInfo.IsLooping = true; PMModule.RecipeRunningInfo.LoopCountCurrent = CurrentLoopCount - 1;//即使不循环,本身也有一次。本身的一次不算,所以减1 PMModule.RecipeRunningInfo.LoopCountSet = curSteps[_currentStepNumber].LoopCount - 1;//即使不循环,本身也有一次。本身的一次不算,所以减1 } if (curSteps[_currentStepNumber].IsJumpStep) { curSteps[_currentStepNumber].IsJumpStep = false;//只执行一次 _currentStepNumber = curSteps[_currentStepNumber].JumpStepNo; } RecipeExec("Main recipe", curSteps, _currentStepNumber, _curStepElpasedTimeBeforePaused); } } break; case RecipeRunningState.TimeWait: //if (PMModule.IsPaused) //{ // _state = RecipeRunningState.Paused; // break; //} var leakCheck = PMModule.CheckLeakCheckFinish(); _trigLeakCheckFinish.CLK = !leakCheck; if (_trigLeakCheckFinish.Q) LOG.Write($"Wait condition:leak check"); if (_stepTimer.IsTimeout()) { var heaterProfile = PMModule.CheckHeaterProfileFinish(out reason); _trigHeaterProfileFinish.CLK = !heaterProfile || _infoHeaterProfileFinish != reason; if (_trigHeaterProfileFinish.Q) LOG.Write($"Wait condition:heater profile--{reason}"); _infoHeaterProfileFinish = reason; var boatWaitCondition = PMModule.CheckBoatWaitCondition(out reason); _trigBoatWaitCondition.CLK = !boatWaitCondition; if (_trigBoatWaitCondition.Q) LOG.Write($"Wait condition:boat--{reason}"); var apcWaitCondition = PMModule.CheckAPCWaitCondition(out reason); _trigAPCWaitCondition.CLK = !apcWaitCondition; if (_trigAPCWaitCondition.Q) LOG.Write($"Wait condition:APC--{reason}"); var auxWaitCondition = PMModule.CheckAUXWaitCondition(out reason); _trigAUXWaitCondition.CLK = !auxWaitCondition || _infoAUXWaitCondition != reason; if (_trigAUXWaitCondition.Q) LOG.Write($"Wait condition:heater profile--{reason}"); _infoAUXWaitCondition = reason; var heaterWaitCondition = PMModule.CheckHeaterWaitCondition(out reason); _trigHeaterWaitCondition.CLK = !heaterWaitCondition || _infoHeaterWaitCondition != reason; if (_trigHeaterWaitCondition.Q) LOG.Write($"Wait condition:heater--{reason}"); _infoHeaterWaitCondition = reason; var mfcWaitCondition = PMModule.CheckMFCWaitCondition(out reason); _trigMFCWaitCondition.CLK = !mfcWaitCondition || _infoMFCWaitCondition != reason; if (_trigMFCWaitCondition.Q) LOG.Write($"Wait condition:MFC--{reason}"); _infoMFCWaitCondition = reason; if (heaterProfile && leakCheck && boatWaitCondition && apcWaitCondition && auxWaitCondition && heaterWaitCondition && mfcWaitCondition) { _state = RecipeRunningState.StepCompleted; } else { PMModule.IsWait = true; } } else { PMModule.CheckHeaterProfileFinish(out reason); PMModule.CheckBoatWaitCondition(out reason); PMModule.CheckAPCWaitCondition(out reason); PMModule.CheckAUXWaitCondition(out reason); PMModule.CheckHeaterWaitCondition(out reason); PMModule.CheckMFCWaitCondition(out reason); } break; case RecipeRunningState.ConditionWait: { if (!PMModule.CheckBoatState() && !PMModule.IsBoatMoveToLoadPosition) break; var heaterProfile = PMModule.CheckHeaterProfileFinish(out reason); _trigHeaterProfileFinish.CLK = !heaterProfile || _infoHeaterProfileFinish != reason; if (_trigHeaterProfileFinish.Q) LOG.Write($"Wait condition:heater profile--{reason}"); _infoHeaterProfileFinish = reason; leakCheck = PMModule.CheckLeakCheckFinish(); _trigLeakCheckFinish.CLK = !leakCheck; if (_trigLeakCheckFinish.Q) LOG.Write($"Wait condition:leak check"); var boatWaitCondition = PMModule.CheckBoatWaitCondition(out reason); _trigBoatWaitCondition.CLK = !boatWaitCondition; if (_trigBoatWaitCondition.Q) LOG.Write($"Wait condition:boat--{reason}"); var apcWaitCondition = PMModule.CheckAPCWaitCondition(out reason); _trigAPCWaitCondition.CLK = !apcWaitCondition; if (_trigAPCWaitCondition.Q) LOG.Write($"Wait condition:APC--{reason}"); var auxWaitCondition = PMModule.CheckAUXWaitCondition(out reason); _trigAUXWaitCondition.CLK = !auxWaitCondition || _infoAUXWaitCondition != reason; if (_trigAUXWaitCondition.Q) LOG.Write($"Wait condition:heater profile--{reason}"); _infoAUXWaitCondition = reason; var heaterWaitCondition = PMModule.CheckHeaterWaitCondition(out reason); _trigHeaterWaitCondition.CLK = !heaterWaitCondition || _infoHeaterWaitCondition != reason; if (_trigHeaterWaitCondition.Q) LOG.Write($"Wait condition:heater--{reason}"); _infoHeaterWaitCondition = reason; var mfcWaitCondition = PMModule.CheckMFCWaitCondition(out reason); _trigMFCWaitCondition.CLK = !mfcWaitCondition || _infoMFCWaitCondition != reason; if (_trigMFCWaitCondition.Q) LOG.Write($"Wait condition:MFC--{reason}"); _infoMFCWaitCondition = reason; if (heaterProfile && leakCheck && boatWaitCondition && apcWaitCondition && auxWaitCondition && heaterWaitCondition && mfcWaitCondition) { _state = RecipeRunningState.StepCompleted; } if (_stepTimer.IsTimeout()) { if (PMModule.IsBoatMoveToLoadPosition) { _trigBoatMoveToLoadPositionTimeout.CLK = !boatWaitCondition; if (_trigBoatMoveToLoadPositionTimeout.Q) PMModule.BoatMoveToLoadPositionTimeoutWarning.Set(); } //_trigInputSignalTimeOutAlarm.CLK = !PMModule.CheckExternalSensorCondition(); //if (_trigInputSignalTimeOutAlarm.Q) // PMModule.InputSignalTimeOutAlarm.Set(); //_trigTemperatureConvergenceTimeOutAlarm.CLK = !PMModule.CheckTempStabilizeCondition(); //if (_trigTemperatureConvergenceTimeOutAlarm.Q) // PMModule.TemperatureConvergenceTimeOutAlarm.Set(); //_trigReachTempTimeOutAlarm.CLK = !PMModule.CheckReachTempCondition(); //if (_trigReachTempTimeOutAlarm.Q) // PMModule.TemperatureConvergenceTimeOutAlarm.Set("Reach temp condition timeout"); //_trigPressureConvergenceTimeOutAlarm.CLK = !PMModule.CheckPressureStablilizeCondition(); //if (_trigPressureConvergenceTimeOutAlarm.Q) // PMModule.PressureConvergenceTimeOutAlarm.Set(); //_trigReachPressureTimeOutAlarm.CLK = !PMModule.CheckReachPressureCondition(); //if (_trigReachPressureTimeOutAlarm.Q) // PMModule.PressureConvergenceTimeOutAlarm.Set("Reach pressure condition timeout"); //_trigAutoProfileTimeOutAlarm.CLK = !PMModule.CheckFinishAutoProfileCondition(); //if (_trigAutoProfileTimeOutAlarm.Q) // PMModule.AutoProfileTimeOutAlarm.Set(); //_state = RecipeRunningState.StepCompleted; } else { _trigBoatMoveToLoadPositionTimeout.RST = true; } } break; case RecipeRunningState.Paused: if (!_stepTimer.IsIdle()) { _curStepElpasedTimeBeforePaused += _stepTimer.GetElapseTime(); _stepTimer.Stop(); } if (_holdTimer.IsIdle()) _holdTimer.Start(0); switch (ContinueAction) { case RecipeContinueMode.None: break; case RecipeContinueMode.StepContinue: if (!_holdTimer.IsIdle()) { _holdTimeElpasedTime += _holdTimer.GetElapseTime(); _holdTimer.Stop(); } _state = RecipeRunningState.ExecStep; _stepTimer.Stop(); break; } break; case RecipeRunningState.StepCompleted: { ResetTrig(); //CloseAllValve(); _curStepElpasedTimeBeforePaused = 0; var stepName = ""; var stepTime = (float)_stepTimer.GetElapseTime() / 1000;//sec var thickness = 0.0f; if (IsSubReciep) { stepName = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].StepName; float.TryParse(PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].FilmThickFormula, out thickness); //放在前面,stepnumber后面会被更新 if (!_isJumpStep) { _faCallback.RecipeStepEnd(PMModule.Module, PMModule.RecipeRunningInfo.RecipeName, _currentSubRecipeStepNumber + 1); _dbCallback.RecipeStepEnd(PMModule.RecipeRunningInfo.InnerId.ToString(), _currentSubRecipeStepNumber + 1, _fdc.DataList, SC.GetStringValue("PM1.TempCorrection"), SC.GetStringValue("PM1.Heater.PID")); } _fdc.Stop(); _totalElpasedTime += curSteps[_currentSubRecipeStepNumber].StepTime; _subRecipeStartStepNumber++; if (_loopEnd) { _currentSubRecipeStepNumber++; CurrentSubRecipeLoopCount = 0; PMModule.RecipeRunningInfo.IsLooping = false; PMModule.RecipeRunningInfo.LoopCountCurrent = 0; PMModule.RecipeRunningInfo.LoopCountSet = 0; } else { SubRecipeLoopEndCheck(curSteps); } if (_currentSubRecipeStepNumber >= curSteps.Count) { PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeLoopCount--; if (PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeLoopCount > 0) { IsSubReciep = true; } else { IsSubReciep = false; } _currentSubRecipeStepNumber = 0; CurrentSubRecipeLoopCount = 0; //// sub recipe执行完后,检查下是否在main recipe的loop内 //RecipeLoopEndCheck(); //if (_currentStepNumber >= PMModule.RecipeRunningInfo.RecipeStepList.Count) //{ // _currentStepNumber = PMModule.RecipeRunningInfo.RecipeStepList.Count - 1; // _state = RecipeRunningState.RecipeCompleted; //} } _state = RecipeRunningState.ExecStep; _stepTimer.Stop(); } else { stepName = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepName; float.TryParse(PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].FilmThickFormula, out thickness); //放在前面,stepnumber后面会被更新 if (!_isJumpStep) { _faCallback.RecipeStepEnd(PMModule.Module, PMModule.RecipeRunningInfo.RecipeName, _currentStepNumber); _dbCallback.RecipeStepEnd(PMModule.RecipeRunningInfo.InnerId.ToString(), _currentStepNumber, _fdc.DataList, SC.GetStringValue("PM1.TempCorrection"), SC.GetStringValue("PM1.Heater.PID")); } _fdc.Stop(); if (_currentStepNumber >= 0 && !IsSubReciep) { _totalElpasedTime += PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime; } if (IsSubReciep) IsSubReciep = false; if (_loopEnd) { _currentStepNumber++; CurrentLoopCount = 0; CurrentAbortRecipeLoopCount = 0; CurrentSubRecipeLoopCount = 0; PMModule.RecipeRunningInfo.IsLooping = false; PMModule.RecipeRunningInfo.LoopCountCurrent = 0; PMModule.RecipeRunningInfo.LoopCountSet = 0; } else { RecipeLoopEndCheck(PMModule.RecipeRunningInfo.RecipeStepList); } if (_currentStepNumber >= PMModule.RecipeRunningInfo.RecipeStepList.Count - 1) { for (int i = 0; i < SC.GetValue($"Boat.SlotCount"); i++) { if (!WaferManager.Instance.CheckHasWafer(ModuleHelper.Converter(Module), i)) continue; var wafer = WaferManager.Instance.GetWafer(ModuleHelper.Converter(Module), i); if (wafer.ProcessState == EnumWaferProcessStatus.Completed || wafer.ProcessState == EnumWaferProcessStatus.Idle) continue; WaferManager.Instance.UpdateWaferProcessStatus(ModuleHelper.Converter(Module), i, EnumWaferProcessStatus.Completed); } PMModule.IsMainRecipeComplete = true; } if (_currentStepNumber >= PMModule.RecipeRunningInfo.RecipeStepList.Count) { _currentStepNumber = PMModule.RecipeRunningInfo.RecipeStepList.Count - 1; _state = RecipeRunningState.RecipeCompleted; } else { _state = RecipeRunningState.ExecStep; _stepTimer.Stop(); } } if (!_isJumpStep) { PMModule.UpdateRecipeStepThicknessAndTime(stepName, thickness, stepTime); var wafers = WaferManager.Instance.GetWafers(ModuleHelper.Converter(Module)); for (int i = 0; i < wafers.Length; i++) { if (WaferManager.Instance.CheckNoWafer(ModuleHelper.Converter(Module), i)) continue; var useCount = wafers[i].UseCount; var useTime = wafers[i].UseTime + (float)stepTime; var useThick = wafers[i].UseThick + thickness; WaferManager.Instance.UpdateWaferStatistics(ModuleHelper.Converter(Module), i, useCount, useTime, useThick); } } } _isJumpStep = false; if (PMModule.IsPaused) { _state = RecipeRunningState.Paused; break; } break; case RecipeRunningState.RecipeCompleted: { var wafers = WaferManager.Instance.GetWafers(ModuleHelper.Converter(Module)); for (int i = 0; i < wafers.Length; i++) { if (WaferManager.Instance.CheckNoWafer(ModuleHelper.Converter(Module), i)) continue; var useCount = wafers[i].UseCount + 1; var useTime = wafers[i].UseTime; var useThick = wafers[i].UseThick; WaferManager.Instance.UpdateWaferStatistics(ModuleHelper.Converter(Module), i, useCount, useTime, useThick); } if (PMModule.IsHeaterProfile && !PMModule.IsHeaterProfileSuccess) EV.PostWarningLog(PMModule.Module, "Auto profile failed"); Notify("End"); return Result.DONE; } case RecipeRunningState.Error: { return Result.DONE; } default: break; } } catch (Exception ex) { LOG.Write(ex); return Result.FAIL; } } MonitorRecipeRunInfo(); return Result.RUN; } private void MonitorRecipeRunInfo() { PMModule.IsHolded = _state == RecipeRunningState.Paused; double elapseTime; double totalElapseTime; double holdTotalElapseTime; var step = 0; if (IsSubReciep) { if (PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps != null) { if (_stepTimer.IsIdle()) { elapseTime = (_curStepElpasedTimeBeforePaused / 1000) < 1 ? 0 : _curStepElpasedTimeBeforePaused / 1000; } else { elapseTime = ((_curStepElpasedTimeBeforePaused + _stepTimer.GetElapseTime()) / 1000) < 1 ? 0 : (_curStepElpasedTimeBeforePaused + _stepTimer.GetElapseTime()) / 1000; } if (elapseTime > PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].StepTime) elapseTime = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].StepTime; totalElapseTime = _totalElpasedTime + elapseTime > PMModule.RecipeRunningInfo.TotalTime ? PMModule.RecipeRunningInfo.TotalTime : _totalElpasedTime + elapseTime; if (_holdTimer.IsIdle()) { holdTotalElapseTime = _holdTimeElpasedTime / 1000; } else { holdTotalElapseTime = (_holdTimeElpasedTime + _holdTimer.GetElapseTime()) / 1000; } PMModule.RecipeRunningInfo.StepElapseTime = elapseTime; PMModule.RecipeRunningInfo.TotalElapseTime = totalElapseTime; PMModule.RecipeRunningInfo.HoldTime = holdTotalElapseTime; PMModule.RecipeRunningInfo.StepTime = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].StepTime; PMModule.RecipeRunningInfo.RecipeName = $"Sub/{PMModule.RecipeRunningInfo.Head.SubRecipe}-{PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeTableInfo}-{PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].StepName}"; PMModule.RecipeRunningInfo.ExecRecipeType = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].RecipeType; PMModule.RecipeRunningInfo.SubRecipeCurrentLoopCount = PMModule.RecipeRunningInfo.SubRecipeLoopCount - PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeLoopCount + 1; PMModule.RecipeRunningInfo.SubRecipeName = PMModule.RecipeRunningInfo.Head.SubRecipe; step = _currentSubRecipeStepNumber; if (_state == RecipeRunningState.Paused) { //pause之后,当前step执行完,显示的step要保持hold住的这一步的 step--; if (step < 0) step = 0; } PMModule.RecipeRunningInfo.StepNumber = step + 1; //CurStepNum start from 0 PMModule.RecipeRunningInfo.StepName = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[step].StepName; if (PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[step].IsLoopEndStep) PMModule.RecipeRunningInfo.NextStepName = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps.Count > PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].LoopStartStep ? PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[step].LoopStartStep].StepName : ""; else { if (PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps.Count > step + 1) { PMModule.RecipeRunningInfo.NextStepName = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[step + 1].StepName; } else { if (PMModule.RecipeRunningInfo.SubRecipeCurrentLoopCount < PMModule.RecipeRunningInfo.SubRecipeLoopCount) { //sub 下一个循环 PMModule.RecipeRunningInfo.NextStepName = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[0].StepName; } else { //sub执行结束 if (PMModule.RecipeRunningInfo.RecipeStepList.Count > _currentStepNumber) { PMModule.RecipeRunningInfo.NextStepName = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepName; } } } } if (PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].StepName.ToLower() == "standby") { PMModule.StringProcessFlowState = PMModule.ProcessFlowState.Standby.ToString(); } else { PMModule.StringProcessFlowState = PMModule.ProcessFlowState.Run.ToString(); } } return; } if (_stepTimer.IsIdle()) { elapseTime = (_curStepElpasedTimeBeforePaused / 1000) < 1 ? 0 : _curStepElpasedTimeBeforePaused / 1000; } else { elapseTime = ((_curStepElpasedTimeBeforePaused + _stepTimer.GetElapseTime()) / 1000) < 1 ? 0 : (_curStepElpasedTimeBeforePaused + _stepTimer.GetElapseTime()) / 1000; } if (elapseTime > PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime) elapseTime = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime; totalElapseTime = _totalElpasedTime + elapseTime > PMModule.RecipeRunningInfo.TotalTime ? PMModule.RecipeRunningInfo.TotalTime : _totalElpasedTime + elapseTime; if (_holdTimer.IsIdle()) { holdTotalElapseTime = _holdTimeElpasedTime / 1000; } else { holdTotalElapseTime = (_holdTimeElpasedTime + _holdTimer.GetElapseTime()) / 1000; } PMModule.RecipeRunningInfo.StepElapseTime = elapseTime; PMModule.RecipeRunningInfo.TotalElapseTime = totalElapseTime; PMModule.RecipeRunningInfo.HoldTime = holdTotalElapseTime; PMModule.RecipeRunningInfo.StepTime = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime; PMModule.RecipeRunningInfo.RecipeName = PMModule.RecipeRunningInfo.MainRecipeName; PMModule.RecipeRunningInfo.ExecRecipeType = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeType; if (_state == RecipeRunningState.RecipeCompleted) { PMModule.RecipeRunningInfo.HoldTime = 0; } step = _currentStepNumber; if (_state == RecipeRunningState.Paused) { //pause之后,当前step执行完,显示的step要保持hold住的这一步的 step--; if (step < 0) step = 0; } if (PMModule.RecipeRunningInfo.RecipeStepList[0].StepName.ToLower() == "standby") { PMModule.RecipeRunningInfo.StepNumber = step; //CurStepNum start from 0 } else { PMModule.RecipeRunningInfo.StepNumber = step + 1; //CurStepNum start from 0 } PMModule.RecipeRunningInfo.StepName = PMModule.RecipeRunningInfo.RecipeStepList[_showStepNo].StepName; if (PMModule.RecipeRunningInfo.RecipeStepList[step].IsLoopEndStep) PMModule.RecipeRunningInfo.NextStepName = PMModule.RecipeRunningInfo.RecipeStepList.Count > PMModule.RecipeRunningInfo.RecipeStepList[step].LoopStartStep ? PMModule.RecipeRunningInfo.RecipeStepList[PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].LoopStartStep].StepName : ""; else PMModule.RecipeRunningInfo.NextStepName = PMModule.RecipeRunningInfo.RecipeStepList.Count > step + 1 ? PMModule.RecipeRunningInfo.RecipeStepList[step + 1].StepName : ""; if (PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepName.ToLower() == "standby") { PMModule.StringProcessFlowState = PMModule.ProcessFlowState.Standby.ToString(); } else if (PMModule.RecipeRunningInfo.RecipeStepList.Count - 1 == _currentStepNumber) { PMModule.StringProcessFlowState = PMModule.ProcessFlowState.End.ToString(); } else { PMModule.StringProcessFlowState = PMModule.ProcessFlowState.Run.ToString(); } } private void MonitorRecipeAlaramAction() { if (_state != RecipeRunningState.TimeWait && _state != RecipeRunningState.ConditionWait) return; if (_alarmNames.Count == 0) return; int group = -1, temp = 0; string iAlarmConditionTable = "1:"; if (IsSubReciep) { for (int i = 0; i < _alarmNames.Count; i++) { iAlarmConditionTable = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].AlarmConditionTable; temp = (int)Singleton.Instance.AlarmDic[iAlarmConditionTable.ToString()][_alarmNames[i]].Group; if (!PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].AlarmActionSets.ContainsKey(temp)) continue; var type = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].AlarmActionSets[temp].ProcessingType; if (temp >= group && (group == -1 || type != "Ignore Alarm")) group = temp; } } else { for (int i = 0; i < _alarmNames.Count; i++) { iAlarmConditionTable = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].AlarmConditionTable; temp = (int)Singleton.Instance.AlarmDic[iAlarmConditionTable.ToString()][_alarmNames[i]].Group; if (!PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].AlarmActionSets.ContainsKey(temp)) continue; var type = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].AlarmActionSets[temp].ProcessingType; if (temp >= group && (group == -1 || type != "Ignore Alarm")) group = temp; } } _alarmNames.Clear(); if (group == -1) return; string alarmAction = "", alarmDetails = ""; List abortRecipes = new List(); if (IsSubReciep) { alarmAction = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].AlarmActionSets[group].ProcessingType; alarmDetails = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].AlarmActionSets[group].ProcessingDetails; abortRecipes = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps[_currentSubRecipeStepNumber].AlarmActionSets[group].AbortRecipeStepList; } else { alarmAction = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].AlarmActionSets[group].ProcessingType; alarmDetails = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].AlarmActionSets[group].ProcessingDetails; abortRecipes = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].AlarmActionSets[group].AbortRecipeStepList; } switch (alarmAction) { case "Jump Abort Recipe": alarmDetails = alarmDetails.Replace("Abort Recipe/", string.Empty); Abort(); _alarmAction = RecipeAlaramAction.JumpAbortRecipe; break; case "Jump Step": alarmDetails = alarmDetails.Replace("Jump Step/", string.Empty); _jumpStepNumber = PMModule.RecipeRunningInfo.RecipeStepList.FindIndex(x => x.StepName == alarmDetails); _alarmAction = RecipeAlaramAction.JumpStep; _state = RecipeRunningState.StepCompleted; break; case "Jump Step(Cancel Call Loop)": alarmDetails = alarmDetails.Replace("Jump Step(Cancel Call Loop)/", string.Empty); _jumpStepNumber = PMModule.RecipeRunningInfo.RecipeStepList.FindIndex(x => x.StepName == alarmDetails); _alarmAction = RecipeAlaramAction.JumpStepCancelCallLoop; IsJumpStepCancelCallLoop = true; _state = RecipeRunningState.StepCompleted; break; case "Abort": IsExecuteAbort = true; break; case "Hold": PMModule.IsPaused = true; ContinueAction = RecipeContinueMode.None; _alarmAction = RecipeAlaramAction.Hold; break; case "Ignore Alarm": _alarmAction = RecipeAlaramAction.IgnoreAlaram; break; default: _alarmAction = RecipeAlaramAction.IgnoreAlaram; break; } } private void MonitorRecipePause() { if (_state != RecipeRunningState.TimeWait && _state != RecipeRunningState.ConditionWait) return; //if (PMModule.IsPaused) //{ // _state = RecipeRunningState.Paused; //} } public override void Abort() { PMModule.AbortRecipe();//暂时这么做 PMModule.RecipeRunningInfo.IsLooping = false; PMModule.RecipeRunningInfo.LoopCountCurrent = 0; PMModule.RecipeRunningInfo.LoopCountSet = 0; IsExecuteAbort = true; IsSubReciep = false; PMModule.IsPaused = false; PMModule.IsHeaterProfile = false; PMModule.IsHeaterProfileSuccess = false; if (!_holdTimer.IsIdle()) { _holdTimeElpasedTime += _holdTimer.GetElapseTime(); _holdTimer.Stop(); } CurrentLoopCount = 0; CurrentAbortRecipeLoopCount = 0; CurrentSubRecipeLoopCount = 0; _state = RecipeRunningState.RecipeCompleted;//暂时这么做 return;//暂时这么做 //_totalElpasedTime = 0; PMModule.RecipeRunningInfo.BeginTime = DateTime.Now; double total = 0; for (int i = 0; i < PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].AbortRecipeSteps.Count; i++) { total += PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].AbortRecipeSteps[i].StepTime; } PMModule.RecipeRunningInfo.TotalTime = _totalElpasedTime + total; ResetTrig(); //PMModule.ResetToleranceAlarm(); //PMModule.ResetToleranceAlarmChecker(); PMModule.ExecuteAbortRecipeWarning.Set($"from recipe name:{PMModule.RecipeRunningInfo.RecipeName} step:{_currentStepNumber} start execute abort recipe."); _state = RecipeRunningState.ExecStep; } public void UpdateProcessDataPJid(string pjId) { _dbCallback.RecipeUpdatePjId(PMModule.RecipeRunningInfo.InnerId.ToString(), pjId); } public void ExitProcess() { if (_state == RecipeRunningState.RecipeCompleted) { PMModule.StringProcessFlowState= PMModule.ProcessFlowState.Standby.ToString(); _faCallback.RecipeComplete(PMModule.Module, PMModule.RecipeRunningInfo.RecipeName); _dbCallback.RecipeComplete(PMModule.RecipeRunningInfo.InnerId.ToString()); _fdc.Stop(); } else { if (PMModule.IsExcuteIdleRecipe) { _faCallback.RecipeComplete(PMModule.Module, PMModule.RecipeRunningInfo.RecipeName); _dbCallback.RecipeComplete(PMModule.RecipeRunningInfo.InnerId.ToString()); _fdc.Stop(); } else { _faCallback.RecipeFailed(PMModule.Module, PMModule.RecipeRunningInfo.RecipeName); _dbCallback.RecipeFailed(PMModule.RecipeRunningInfo.InnerId.ToString()); _fdc.Stop(); }; } } public void PauseRecipe() { PMModule.IsPaused = true; ContinueAction = RecipeContinueMode.None; } public void ContinueRecipe() { PMModule.IsPaused = false; ContinueAction = RecipeContinueMode.StepContinue; } public void SkipCurrentRecipeStep() { if (_state == RecipeRunningState.ConditionWait || _state == RecipeRunningState.TimeWait || _state == RecipeRunningState.Paused) { _state = RecipeRunningState.StepCompleted; _loopEnd = true; PMModule.RecipeRunningInfo.IsLooping = false; PMModule.RecipeRunningInfo.LoopCountCurrent = 0; PMModule.RecipeRunningInfo.LoopCountSet = 0; PMModule.IsPaused = false; if (!_holdTimer.IsIdle()) { _holdTimeElpasedTime += _holdTimer.GetElapseTime(); _holdTimer.Stop(); } } if (IsSubReciep) { ResetLoop(PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps, _currentSubRecipeStepNumber); } else { ResetLoop(PMModule.RecipeRunningInfo.RecipeStepList, _currentStepNumber); } } private void ResetLoop(List checkRecipeSeps, int currentStepNumber) { if (checkRecipeSeps == null) return; var hasLoopStart = false; for (int i = currentStepNumber; i >= 0; i--) { if (checkRecipeSeps[i].IsLoopStartStep) { hasLoopStart = true; break; } if (checkRecipeSeps[i].IsLoopEndStep) { hasLoopStart = false;//前面有end,说明没有循环 break; } } if (hasLoopStart) { for (int i = currentStepNumber; i < checkRecipeSeps.Count; i++) { if (checkRecipeSeps[i].IsLoopStartStep) { break;//没有循环 } if (checkRecipeSeps[i].IsLoopEndStep) { checkRecipeSeps[i].IsLoopEndStep = false;//跳出skip step之间的循环 break; } } } } public void LeakCheckRetry() { JumpCurrentRecipeStep(_currentStepNumber - 1, PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber - 1].StepName); } public void JumpCurrentRecipeStep(int stepNumber, string stepName, bool isAlarmConditionCall = false) { PMModule.AbortLeakCheck(); LOG.Write($"Jump to step stepNumber={stepNumber} stepName={stepName}, currentStepNumber={_currentStepNumber}"); if (_state == RecipeRunningState.ConditionWait || _state == RecipeRunningState.TimeWait || _state == RecipeRunningState.Paused || _state == RecipeRunningState.ExecStep) { _loopEnd = true; PMModule.RecipeRunningInfo.IsLooping = false; PMModule.RecipeRunningInfo.LoopCountCurrent = 0; PMModule.RecipeRunningInfo.LoopCountSet = 0; CurrentLoopCount = 0; CurrentAbortRecipeLoopCount = 0; CurrentSubRecipeLoopCount = 0; IsSubReciep = false; if (IsSubReciep) { _faCallback.RecipeStepEnd(PMModule.Module, PMModule.RecipeRunningInfo.RecipeName, _currentSubRecipeStepNumber + 1); _dbCallback.RecipeStepEnd(PMModule.RecipeRunningInfo.InnerId.ToString(), _currentSubRecipeStepNumber + 1, _fdc.DataList, SC.GetStringValue("PM1.TempCorrection"), SC.GetStringValue("PM1.Heater.PID")); ResetLoop(PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].SubRecipeSteps, _currentSubRecipeStepNumber); } else { _faCallback.RecipeStepEnd(PMModule.Module, PMModule.RecipeRunningInfo.RecipeName, _currentStepNumber); _dbCallback.RecipeStepEnd(PMModule.RecipeRunningInfo.InnerId.ToString(), _currentStepNumber, _fdc.DataList, SC.GetStringValue("PM1.TempCorrection"), SC.GetStringValue("PM1.Heater.PID")); ResetLoop(PMModule.RecipeRunningInfo.RecipeStepList, _currentStepNumber); } if (_callSubSteps != null) { foreach (var key in _callSubSteps.Keys) { if (PMModule.RecipeRunningInfo.RecipeStepList.Count > key) { PMModule.RecipeRunningInfo.RecipeStepList[key].IsCallSubStep = _callSubSteps[key].Item1; PMModule.RecipeRunningInfo.RecipeStepList[key].SubRecipeLoopCount = _callSubSteps[key].Item2; } } _currentSubRecipeStepNumber = CurSubRecipeStepTotalLoopCount = 0; } _isJumpStep = true; _currentStepNumber = stepNumber - 1; if (_currentStepNumber < 0) _currentStepNumber = 0; _totalElpasedTime = RefreshElpasedTime(); _state = RecipeRunningState.StepCompleted; PMModule.IsPaused = false; if (!_holdTimer.IsIdle()) { _holdTimeElpasedTime += _holdTimer.GetElapseTime(); _holdTimer.Stop(); } } } private double RefreshElpasedTime() { double total = 0; try { for (int i = 0; i < _currentStepNumber; i++) { if (!PMModule.RecipeRunningInfo.RecipeStepList[i].IsJumpStep) { if (PMModule.RecipeRunningInfo.RecipeStepList[i].IsLoopEndStep) { int iLoopStartStep = PMModule.RecipeRunningInfo.RecipeStepList[i].LoopStartStep; for (int j = 0; j < PMModule.RecipeRunningInfo.RecipeStepList[i].LoopCount; j++) { for (int m = iLoopStartStep; m <= i; m++) { if (PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeSteps != null && PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeSteps.Count > _currentSubRecipeStepNumber) { total += SubRecipeCalTotalTime(i) * PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeLoopCount; } total += PMModule.RecipeRunningInfo.RecipeStepList[m].StepTime; } } } else { if (PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeSteps != null && PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeSteps.Count > _currentSubRecipeStepNumber) { total += SubRecipeCalTotalTime(i) * PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeLoopCount; } total += PMModule.RecipeRunningInfo.RecipeStepList[i].StepTime; } } } } catch (Exception ex) { LOG.Write(ex); return -1; } return (int)total; } public void RespondAlarm(string name) { if (!_alarmNames.Contains(name)) _alarmNames.Add(name); } protected int CalcRecipeTime() { double total = 0; int iStart = PMModule.IsJobProcess ? 1 : 0; try { for (int i = iStart; i < PMModule.RecipeRunningInfo.RecipeStepList.Count; i++) //for (int i = PMModule.RecipeRunningInfo.RecipeStepList.Count - 1; i <= iStart; i--) { if (!PMModule.RecipeRunningInfo.RecipeStepList[i].IsJumpStep) { if (PMModule.RecipeRunningInfo.RecipeStepList[i].IsLoopEndStep) { int iLoopStartStep = PMModule.RecipeRunningInfo.RecipeStepList[i].LoopStartStep; total += PMModule.RecipeRunningInfo.RecipeStepList[i].StepTime; for (int j = 0; j < PMModule.RecipeRunningInfo.RecipeStepList[i].LoopCount - 1; j++) { for (int m = iLoopStartStep; m <= i; m++) { if (PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeSteps != null && PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeSteps.Count > _currentSubRecipeStepNumber) { total += SubRecipeCalTotalTime(i) * PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeLoopCount; } total += PMModule.RecipeRunningInfo.RecipeStepList[m].StepTime; } } } else { if (PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeSteps != null && PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeSteps.Count > _currentSubRecipeStepNumber) { total += SubRecipeCalTotalTime(i) * PMModule.RecipeRunningInfo.RecipeStepList[i].SubRecipeLoopCount; } total += PMModule.RecipeRunningInfo.RecipeStepList[i].StepTime; } } else { i = PMModule.RecipeRunningInfo.RecipeStepList[i].JumpStepNo - 1;// -1是因为i++ } } } catch (Exception ex) { LOG.Write(ex); return -1; } return (int)total; } private int AbortRecipeCalTotalTime() { double total = 0; List abortRecipeSteps; abortRecipeSteps = PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].AbortRecipeSteps; try { for (int i = 0; i < abortRecipeSteps.Count; i++) { if (!abortRecipeSteps[i].IsJumpStep) { if (abortRecipeSteps[i].IsLoopStartStep) { int iLoopEndStep = 0; for (int j = 0; j < abortRecipeSteps[i].LoopCount; j++) { for (int m = i; m < abortRecipeSteps.Count; m++) { total += abortRecipeSteps[m].StepTime; if (abortRecipeSteps[m].IsLoopEndStep) { iLoopEndStep = m; break; } } } i = iLoopEndStep; } else { total += abortRecipeSteps[i].StepTime; } } else { i = abortRecipeSteps[i].JumpStepNo - 1;// -1是因为i++ } } } catch (Exception ex) { LOG.Write(ex); return -1; } return (int)total; } public void SetContinue(string continueMode) { switch (continueMode) { case "Step continue": ContinueAction = RecipeContinueMode.StepContinue; break; case "Step restart": ContinueAction = RecipeContinueMode.StepRestart; break; case "Next step": ContinueAction = RecipeContinueMode.NextStep; break; case "Recipe restart": ContinueAction = RecipeContinueMode.RecipeRestart; break; case "Recipe complete": ContinueAction = RecipeContinueMode.RecipeCompleted; break; case "Wafer return and job stop": ContinueAction = RecipeContinueMode.WaferReturnAndJobStop; break; } PMModule.ResetToleranceChecker(); } private double SubRecipeCalTotalTime(int currentStepNumber) { double total = 0; for (int k = _currentSubRecipeStepNumber; k < PMModule.RecipeRunningInfo.RecipeStepList[currentStepNumber].SubRecipeSteps.Count; k++) { if (!PMModule.RecipeRunningInfo.RecipeStepList[currentStepNumber].SubRecipeSteps[k].IsJumpStep) { if (PMModule.RecipeRunningInfo.RecipeStepList[currentStepNumber].SubRecipeSteps[k].IsLoopEndStep) { int iSystemLoopStartStep = PMModule.RecipeRunningInfo.RecipeStepList[currentStepNumber].SubRecipeSteps[k].LoopStartStep; total += PMModule.RecipeRunningInfo.RecipeStepList[currentStepNumber].SubRecipeSteps[k].StepTime; for (int n = 0; n < PMModule.RecipeRunningInfo.RecipeStepList[currentStepNumber].SubRecipeSteps[k].LoopCount - 1; n++) { for (int l = iSystemLoopStartStep; l <= k; l++) { total += PMModule.RecipeRunningInfo.RecipeStepList[currentStepNumber].SubRecipeSteps[l].StepTime; } } } else { total += PMModule.RecipeRunningInfo.RecipeStepList[currentStepNumber].SubRecipeSteps[k].StepTime; } } else { k = PMModule.RecipeRunningInfo.RecipeStepList[currentStepNumber].SubRecipeSteps[k].JumpStepNo - 1;// -1是因为k++ } } return total; } private void SubRecipeLoopEndCheck(List recipeSteps) { if (_alarmAction == RecipeAlaramAction.JumpStep || _alarmAction == RecipeAlaramAction.JumpStepCancelCallLoop) { _currentSubRecipeStepNumber = _jumpStepNumber; _alarmAction = RecipeAlaramAction.None; _alarmNames.Clear(); return; } if (recipeSteps[_currentSubRecipeStepNumber].IsLoopEndStep) { if (IsJumpStepCancelCallLoop) { _currentSubRecipeStepNumber++; IsJumpStepCancelCallLoop = false; return; } //重新读取循环的设定次数 CurSubRecipeStepTotalLoopCount = recipeSteps[_currentSubRecipeStepNumber].LoopCount; if (CurrentSubRecipeLoopCount >= CurSubRecipeStepTotalLoopCount) { CurrentSubRecipeLoopCount = CurSubRecipeStepTotalLoopCount = 0; _currentSubRecipeStepNumber++; PMModule.RecipeRunningInfo.IsLooping = false; PMModule.RecipeRunningInfo.LoopCountCurrent = 0; PMModule.RecipeRunningInfo.LoopCountSet = 0; } else { _currentSubRecipeStepNumber = recipeSteps[_currentSubRecipeStepNumber].LoopStartStep; } } else { _currentSubRecipeStepNumber++; } } private void RecipeLoopEndCheck(List recipeSteps) { if (_alarmAction == RecipeAlaramAction.JumpStep || _alarmAction == RecipeAlaramAction.JumpStepCancelCallLoop) { _currentStepNumber = _jumpStepNumber; _alarmAction = RecipeAlaramAction.None; _alarmNames.Clear(); return; } if (recipeSteps[_currentStepNumber].IsLoopEndStep) { if (IsJumpStepCancelCallLoop) { _currentStepNumber++; IsJumpStepCancelCallLoop = false; return; } //重新读取循环的设定次数 CurStepTotalLoopCount = recipeSteps[_currentStepNumber].LoopCount; if (CurrentLoopCount >= CurStepTotalLoopCount) { CurrentLoopCount = CurStepTotalLoopCount = 0; _currentStepNumber++; PMModule.RecipeRunningInfo.IsLooping = false; PMModule.RecipeRunningInfo.LoopCountCurrent = 0; PMModule.RecipeRunningInfo.LoopCountSet = 0; } else { _currentStepNumber = recipeSteps[_currentStepNumber].LoopStartStep; } } else { _currentStepNumber++; } } private void CheckTolerance() { //foreach (var key in _trigMfcToleranceAlarms.Keys) //{ // if (PMModule.GasMFCs.ContainsKey(key) && _trigMfcToleranceWarnings.ContainsKey(key)) // { // _trigMfcToleranceAlarms[key].CLK = PMModule.GasMFCs[key].CheckToleranceAlarm(); // if (_trigMfcToleranceAlarms[key].Q) // PMModule.GasMFCs[key].SetToleranceAlarm(); // _trigMfcToleranceWarnings[key].CLK = PMModule.GasMFCs[key].CheckToleranceWarning(); // if (_trigMfcToleranceWarnings[key].Q && !_trigMfcToleranceAlarms[key].Q) // PMModule.GasMFCs[key].SetToleranceWarning(); // } //} //_trigHeaterBottomToleranceAlarm.CLK = PMModule.CheckHeaterBottomToleranceAlaram(); //if (_trigHeaterBottomToleranceAlarm.Q) // PMModule.SetHeaterBottomToleranceAlaram(); //_trigHeaterBottomToleranceWarning.CLK = PMModule.CheckHeaterBottomToleranceWarning(); //if (_trigHeaterBottomToleranceWarning.Q && !_trigHeaterBottomToleranceAlarm.Q) // PMModule.SetHeaterBottomToleranceWarning(); //_trigHeaterCenterBottomToleranceAlarm.CLK = PMModule.CheckHeaterCenterBottomToleranceAlaram(); //if (_trigHeaterCenterBottomToleranceAlarm.Q) // PMModule.SetHeaterCenterBottomToleranceAlaram(); //_trigHeaterCenterBottomToleranceWarning.CLK = PMModule.CheckHeaterCenterBottomToleranceWarning(); //if (_trigHeaterCenterBottomToleranceWarning.Q && !_trigHeaterCenterBottomToleranceAlarm.Q) // PMModule.SetHeaterCenterBottomToleranceWarning(); //_trigHeaterCenterToleranceAlarm.CLK = PMModule.CheckHeaterCenterToleranceAlaram(); //if (_trigHeaterCenterToleranceAlarm.Q) // PMModule.SetHeaterCenterToleranceAlaram(); //_trigHeaterCenterToleranceWarning.CLK = PMModule.CheckHeaterCenterToleranceWarning(); //if (_trigHeaterCenterToleranceWarning.Q && !_trigHeaterCenterToleranceAlarm.Q) // PMModule.SetHeaterCenterToleranceWarning(); //_trigHeaterCenterTopToleranceAlarm.CLK = PMModule.CheckHeaterCenterTopToleranceAlaram(); //if (_trigHeaterCenterTopToleranceAlarm.Q) // PMModule.SetHeaterCenterTopToleranceAlaram(); //_trigHeaterCenterTopToleranceWarning.CLK = PMModule.CheckHeaterCenterTopToleranceWarning(); //if (_trigHeaterCenterTopToleranceWarning.Q && !_trigHeaterCenterTopToleranceAlarm.Q) // PMModule.SetHeaterCenterTopToleranceWarning(); //_trigHeaterTopToleranceAlarm.CLK = PMModule.CheckHeaterTopToleranceAlaram(); //if (_trigHeaterTopToleranceAlarm.Q) // PMModule.SetHeaterTopToleranceAlaram(); //_trigHeaterTopToleranceWarning.CLK = PMModule.CheckHeaterTopToleranceWarning(); //if (_trigHeaterTopToleranceWarning.Q && !_trigHeaterTopToleranceAlarm.Q) // PMModule.SetHeaterTopToleranceWarning(); //_trigPressureToleranceAlarm.CLK = PMModule.CheckPressureToleranceAlaram(); //if (_trigPressureToleranceAlarm.Q) // PMModule.SetPressureToleranceAlaram(); //_trigPressureToleranceWarning.CLK = PMModule.CheckPressureToleranceWarning(); //if (_trigPressureToleranceWarning.Q && !_trigPressureToleranceAlarm.Q) // PMModule.SetPressureToleranceWarning(); } private void ResetTrig() { PMModule.ResetAlarmCondition(); foreach (var key in _trigMfcToleranceAlarms.Keys) { if (_trigMfcToleranceWarnings.ContainsKey(key)) { _trigMfcToleranceAlarms[key].RST = true; _trigMfcToleranceWarnings[key].RST = true; } } _trigHeaterBottomToleranceAlarm.RST = true; _trigHeaterBottomToleranceWarning.RST = true; _trigHeaterCenterBottomToleranceAlarm.RST = true; _trigHeaterCenterBottomToleranceWarning.RST = true; _trigHeaterCenterToleranceAlarm.RST = true; _trigHeaterCenterToleranceWarning.RST = true; _trigHeaterCenterTopToleranceAlarm.RST = true; _trigHeaterCenterTopToleranceWarning.RST = true; _trigHeaterTopToleranceAlarm.RST = true; _trigHeaterTopToleranceWarning.RST = true; _trigPressureToleranceAlarm.RST = true; _trigPressureToleranceWarning.RST = true; _trigInputSignalTimeOutAlarm.RST = true; _trigTemperatureConvergenceTimeOutAlarm.RST = true; _trigReachTempTimeOutAlarm.RST = true; _trigPressureConvergenceTimeOutAlarm.RST = true; _trigReachPressureTimeOutAlarm.RST = true; _trigAutoProfileTimeOutAlarm.RST = true; _trigHeaterProfileFinish.RST = true; _trigLeakCheckFinish.RST = true; _trigBoatWaitCondition.RST = true; _trigAPCWaitCondition.RST = true; _trigAUXWaitCondition.RST = true; _trigHeaterWaitCondition.RST = true; _trigMFCWaitCondition.RST = true; _infoHeaterProfileFinish = ""; _infoAUXWaitCondition = ""; _infoHeaterWaitCondition = ""; _infoMFCWaitCondition = ""; } private void RecipeExec(string type, List curSteps, int currentStepNumber, double curStepElpasedTimeBeforePaused, int otherRecipeStartStepNumber = 0) { var reason = ""; _stepTimer.Start(curSteps[currentStepNumber].StepTime * 1000 - curStepElpasedTimeBeforePaused); _showStepNo = currentStepNumber; Notify($"{type} running step {currentStepNumber + 1}:{curSteps[currentStepNumber].StepName}"); var stopwatch = new Stopwatch(); stopwatch.Start(); //执行工艺程序命令 foreach (var recipeCmd in curSteps[currentStepNumber].RecipeCommands.Keys) { if (!OP.CanDoOperation($"{_doModule}.{recipeCmd}", out reason, curSteps[currentStepNumber].RecipeCommands[recipeCmd])) { if (!OP.CanDoOperation($"{Module}.{recipeCmd}", out reason, curSteps[currentStepNumber].RecipeCommands[recipeCmd])) { if (!OP.CanDoOperation($"{ModuleName.System}.{recipeCmd}", out reason, curSteps[currentStepNumber].RecipeCommands[recipeCmd])) { PMModule.CheckCanDoOperationAlarm.Set($"Can not execute {recipeCmd}, {reason}"); return; } else { OP.DoOperation($"{ModuleName.System}.{recipeCmd}", out string reason1, 0, curSteps[currentStepNumber].RecipeCommands[recipeCmd]); } } else { OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, 0, curSteps[currentStepNumber].RecipeCommands[recipeCmd]); } } else { OP.DoOperation($"{_doModule}.{recipeCmd}", out string reason1, 0, curSteps[currentStepNumber].RecipeCommands[recipeCmd]); } } LOG.Write($"step exec time {stopwatch.ElapsedMilliseconds}"); if (curSteps[currentStepNumber].EndBy == EnumEndByCondition.ByTime && !PMModule.IsBoatMoveToLoadPosition) _state = RecipeRunningState.TimeWait; else _state = RecipeRunningState.ConditionWait; _faCallback.RecipeStepStart(PMModule.Module, PMModule.RecipeRunningInfo.RecipeName, otherRecipeStartStepNumber != 0 ? otherRecipeStartStepNumber : currentStepNumber); if (type == "Sub recipe") _dbCallback.RecipeStepStart(PMModule.RecipeRunningInfo.InnerId.ToString(), _currentStepNumber, PMModule.RecipeRunningInfo.RecipeStepList.Count > _currentStepNumber ? PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepName : "", PMModule.RecipeRunningInfo.RecipeStepList.Count > _currentStepNumber ? (float)PMModule.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime : 0, $"{(otherRecipeStartStepNumber != 0 ? otherRecipeStartStepNumber : currentStepNumber)}", curSteps[currentStepNumber].StepName, (float)curSteps[currentStepNumber].StepTime, $"{PMModule.RecipeRunningInfo.SubRecipeCurrentLoopCount}/{PMModule.RecipeRunningInfo.SubRecipeLoopCount}"); else _dbCallback.RecipeStepStart(PMModule.RecipeRunningInfo.InnerId.ToString(), otherRecipeStartStepNumber != 0 ? otherRecipeStartStepNumber : currentStepNumber, curSteps[currentStepNumber].StepName, (float)curSteps[currentStepNumber].StepTime, "", "", 0, ""); _fdc.Start(curSteps[currentStepNumber].RecipeCommands); } } }