using System; using System.Collections.Generic; using System.Diagnostics; using Aitex.Core.Common; using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.Device; using Aitex.Core.RT.Device.Devices; 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.Equipment; using MECF.Framework.Common.SubstrateTrackings; using SicPM1.RecipeExecutions; using SicPM1.Routines; namespace SicPM1.RecipeRoutine { public enum RecipeContinueMode { None, WaferReturnAndJobStop, RecipeCompleted, StepContinue, StepRestart, RecipeRestart, NextStep, } public enum RoutineType { DefaultRoutine, AtmRoutine, VacRoutine, ProcessIdleRoutine, PumpRoutine, VentRoutine, PurgeRoutine, CleanRoutine, ExchangeMORoutine, IsolationRoutine, LeakCheckRoutine, AbortRoutine } public partial class PMMacroRoutine : PMBaseRoutine { enum RoutineStep { WaitProcess, } enum RecipeRunningState { Error, RecipeCompleted, ExecStep, TimeWait, ConditionWait, StepCompleted, Paused, } private object _recipeLocker = new object(); private RecipeRunningState _state = RecipeRunningState.ExecStep; private RecipeRunningState _pausedState = RecipeRunningState.ExecStep; private DeviceTimer _estimatedTimeCalcTimer = new DeviceTimer();//用于定时计算工艺程序估计的结束时间 private double _curStepElpasedTimeBeforePaused; private double _curStepElpasedTimeBeforePaused2; //前序所有步总的时间 private double _preStepTotalTime; public RecipeContinueMode ContinueAction { get; set; } public DateTime _recipeStartTime { get; private set; } public string CurrentRecipeContent { get; private set; } private int _currentStepNumber; private int _dummyStepCount; public int CurStepTotalLoopCount { get; private set; } public double CurStepTotalTime { get { if (PmDevice.RecipeRunningInfo.RecipeStepList == null || PmDevice.RecipeRunningInfo.RecipeStepList.Count == 0 || _state == RecipeRunningState.RecipeCompleted || _state == RecipeRunningState.Error) return 0; return PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime * 1000; } } public int CurrentLoopCount { get; private set; } public int CurStartLoopStep; private DeviceTimer _stepTimer = new DeviceTimer(); private DeviceTimer _stepTimer2 = new DeviceTimer(); private DeviceTimer _recipeTimer = new DeviceTimer(); public bool IsPaused { private set; get; } private double CurStepLeftTime { get { return _stepTimer.GetTotalTime() - _stepTimer.GetElapseTime(); } } public double EstimatedTotalLeftTime { get; private set; } private RecipeDBCallback _dbCallback; private Fdc _fdc; private int _currentStepIndex = 99; private IoInterLock _pmInterLock; private string _recipeName; private RoutineType _routineType; #region Parse private bool _isPSUHeaterJumpMode; private bool _isSCRHeaterJumpMode; private bool _isMFCJumpMode; #endregion public PMMacroRoutine(ModuleName module, PM1Module pm1) : base(module, pm1) { Module = module.ToString(); Name = "Routine"; _dbCallback = new RecipeDBCallback(); _fdc = new Fdc(Module); _pmInterLock = DEVICE.GetDevice($"{Module}.PMInterLock"); } public void Init(string recipeName, RoutineType routineType = RoutineType.DefaultRoutine) { _recipeName = recipeName; _routineType = routineType; } public bool SetRoutineRunning(bool eValue,out string reason) { reason = string.Empty; if(_routineType == RoutineType.ProcessIdleRoutine) { if (!_pmInterLock.SetPMProcessIdleRunning(eValue, out reason)) { return false; } } else if (_routineType == RoutineType.CleanRoutine) { if (!_pmInterLock.SetPMCleanRoutineRunning(eValue, out reason)) { return false; } } else if (_routineType == RoutineType.PurgeRoutine) { if (!_pmInterLock.SetPMPurgeRoutineRunning(eValue, out reason)) { return false; } } else if (_routineType == RoutineType.PumpRoutine) { if (!_pmInterLock.SetPMPumpRoutineRunning(eValue, out reason)) { return false; } } else if (_routineType == RoutineType.VentRoutine) { if (!_pmInterLock.SetPMVentRoutineRunning(eValue, out reason)) { return false; } } else if (_routineType == RoutineType.ExchangeMORoutine) { if (!_pmInterLock.SetPMExchangeMoRoutineRunning(eValue, out reason)) { return false; } } else if (_routineType == RoutineType.VacRoutine) { } else if (_routineType == RoutineType.AtmRoutine) { } else { if (!_pmInterLock.SetPMProcessRunning(eValue, out reason)) { return false; } } return true; } public override Result Start(params object[] param) { Reset(); //解析Recipe if (!RecipeParser.Parse(_recipeName, Module, out var recipeHead, out var recipeSteps, out string reason)) { Stop($"Load recipe {_recipeName} failed, {reason}"); return Result.FAIL; } if(!SetRoutineRunning(true,out reason)) { EV.PostAlarmLog(Module, $"can not run Routine, {reason}"); return Result.FAIL; } if (_routineType == RoutineType.PurgeRoutine) { _pmInterLock.DoLidCloseRoutineSucceed = false; } else if (_routineType == RoutineType.CleanRoutine) { _pmInterLock.DoLidOpenRoutineSucceed = false; } //先打开加热 PmDevice.SetHeatEnable(true); _currentStepIndex = 99; //设置当前Step/当前循环步/当前总循环步为0 _currentStepNumber = 0; CurStartLoopStep = 0; CurrentLoopCount = CurrentLoopCount = 0; _preStepTotalTime = 0; _dummyStepCount = 0; _estimatedTimeCalcTimer.Start(1000); PmDevice.RecipeRunningInfo.RecipeName = _recipeName; PmDevice.RecipeRunningInfo.Head = recipeHead; PmDevice.RecipeRunningInfo.RecipeStepList = recipeSteps; PmDevice.RecipeRunningInfo.InnerId = Guid.NewGuid(); PmDevice.RecipeRunningInfo.BeginTime = DateTime.Now; PmDevice.RecipeRunningInfo.TotalTime = CalcRecipeTime(); _state = RecipeRunningState.ExecStep; _recipeTimer.Start(int.MaxValue); _dbCallback.RecipeStart(PmDevice.Module, 0, PmDevice.RecipeRunningInfo.InnerId.ToString(), PmDevice.RecipeRunningInfo.RecipeName); _dbCallback.RecipeUpdateStatus(PmDevice.RecipeRunningInfo.InnerId.ToString(), "InProcess"); WaferManager.Instance.UpdateWaferProcessStatus(ModuleHelper.Converter(Module), 0, EnumWaferProcessStatus.InProcess); _fdc.Reset(); Notify($"Start"); return Result.RUN; } public override Result Monitor() { if (!PmDevice.CheckEnableRunProcess(out string reason)) { EV.PostAlarmLog(Module, reason); return Result.FAIL; } MonitorRecipeEndTime(); MonitorRecipeRunInfo(); lock (_recipeLocker) { try { switch (_state) { case RecipeRunningState.ExecStep: { PmDevice.ResetToleranceChecker(); if (ContinueAction != RecipeContinueMode.StepContinue) { _curStepElpasedTimeBeforePaused = 0; _curStepElpasedTimeBeforePaused2 = 0; } ContinueAction = RecipeContinueMode.None; if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsLoopStartStep) { CurStartLoopStep = _currentStepNumber; CurStepTotalLoopCount = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].LoopCount; } _stepTimer.Start(PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime * 1000 - _curStepElpasedTimeBeforePaused); if (!_stepTimer2.IsIdle()) { _curStepElpasedTimeBeforePaused2 += _stepTimer2.GetElapseTime(); _stepTimer2.Stop(); } _stepTimer2.Start(int.MaxValue); Notify($"Running step {_currentStepNumber + 1} : {PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepName}"); if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsDummyStep) { _dummyStepCount++; } //执行工艺程序命令 foreach (var recipeCmd in PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands.Keys) { if (recipeCmd == "SusHeaterSetMode") { if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd] == "Jump") _isPSUHeaterJumpMode = true; else _isPSUHeaterJumpMode = false; continue; } if (recipeCmd == "WWHeaterSetMode") { if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd] == "Jump") _isSCRHeaterJumpMode = true; else _isSCRHeaterJumpMode = false; continue; } if (recipeCmd == "FlowSetMode") { if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd] == "Jump") _isMFCJumpMode = true; else _isMFCJumpMode = false; continue; } if (IsCmdSkip(recipeCmd)) // 不是注册的方法,需要跳过 continue; if (!OP.CanDoOperation($"{Module}.{recipeCmd}", out reason, PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd])) { EV.PostAlarmLog(Module, $"Can not execute {recipeCmd}, {reason}"); return Result.FAIL; } else { int time = (int)PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime * 1000; if (recipeCmd.StartsWith("TC1") && _isPSUHeaterJumpMode) { time = 1; } if (recipeCmd.StartsWith("TC2") && _isSCRHeaterJumpMode) { time = 1; } if (recipeCmd.StartsWith("Mfc") && recipeCmd.EndsWith(".Ramp") && !PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsDummyStep) { if (_isMFCJumpMode) { time = 1; } } if ((recipeCmd == "TV.SetPressure" || recipeCmd == "PMServo.SetActualSpeed" || recipeCmd.StartsWith("Pressure") && recipeCmd.EndsWith(".Ramp") || recipeCmd.StartsWith("Mfc") && recipeCmd.EndsWith(".Ramp")) && !PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsDummyStep) { if (_currentStepNumber >= 1) { int previousStepNumber = _currentStepNumber - 1; if (PmDevice.RecipeRunningInfo.RecipeStepList[previousStepNumber].IsDummyStep) previousStepNumber = _currentStepNumber - 2; if (PmDevice.RecipeRunningInfo.RecipeStepList[previousStepNumber].RecipeCommands.ContainsKey(recipeCmd)) { string previousValue = PmDevice.RecipeRunningInfo.RecipeStepList[previousStepNumber].RecipeCommands[recipeCmd]; string currentValue = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd]; if (previousValue == currentValue) { time = 1; } } } } if (recipeCmd.EndsWith(AITValveOperation.GVTurnValve)) // 阀门 { OP.DoOperation($"{Module}.{recipeCmd}", PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd]); } else { OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd]); } } } if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].EndBy == EnumEndByCondition.ByTime) _state = RecipeRunningState.TimeWait; else _state = RecipeRunningState.ConditionWait; _dbCallback.RecipeStepStart(PmDevice.RecipeRunningInfo.InnerId.ToString(), _currentStepNumber, PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepName, (float)PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime); _fdc.Start(PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands); } break; case RecipeRunningState.TimeWait: { if (IsPaused) { _state = RecipeRunningState.Paused; } if (_stepTimer.IsTimeout()) { _state = RecipeRunningState.StepCompleted; } } break; case RecipeRunningState.ConditionWait: { //如果暂停,则进入暂停状态 if (IsPaused) { _state = RecipeRunningState.Paused; } //设置的压力 double.TryParse(PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands["TV.SetPressure"], out double setPressure); //实时反馈的压力 double feedBackPressure = DEVICE.GetDevice($"{Module}.PT1").FeedBack; double _pmPressureMaxDiff = SC.GetValue($"PM.{Module}.ThrottlePressureMaxDiff"); if(Math.Abs(setPressure - feedBackPressure) <= _pmPressureMaxDiff) { _state = RecipeRunningState.StepCompleted; } } break; case RecipeRunningState.Paused: PmDevice.PauseRecipe(out reason); if (!_stepTimer.IsIdle()) { _curStepElpasedTimeBeforePaused += _stepTimer.GetElapseTime(); _stepTimer.Stop(); } switch (ContinueAction) { case RecipeContinueMode.None: break; case RecipeContinueMode.WaferReturnAndJobStop: //Singleton.Instance.CheckToPostMessage((int)RouteManager.MSG.StopJob); _state = RecipeRunningState.Error; break; case RecipeContinueMode.RecipeCompleted: _state = RecipeRunningState.RecipeCompleted; break; case RecipeContinueMode.StepContinue: _state = RecipeRunningState.ExecStep; break; case RecipeContinueMode.StepRestart: _state = RecipeRunningState.ExecStep; break; case RecipeContinueMode.RecipeRestart: _currentStepNumber = 0; _state = RecipeRunningState.ExecStep; break; case RecipeContinueMode.NextStep: _state = RecipeRunningState.StepCompleted; break; } break; case RecipeRunningState.StepCompleted: { _preStepTotalTime += CurStepTotalTime/1000; //放在前面,stepnumber后面会被更新 _stepTimer2.Stop(); _dbCallback.RecipeStepEnd(PmDevice.RecipeRunningInfo.InnerId.ToString(), _currentStepNumber, _fdc.DataList); _fdc.Stop(); if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsLoopEndStep) { CurrentLoopCount++; if (CurrentLoopCount >= CurStepTotalLoopCount) { CurrentLoopCount = CurStepTotalLoopCount = 0; CurStartLoopStep = 0; _currentStepNumber++; } else { _currentStepNumber = CurStartLoopStep; } } else { _currentStepNumber++; } //判断最后一步是否执行完 if (_currentStepNumber >= PmDevice.RecipeRunningInfo.RecipeStepList.Count) { _currentStepNumber = PmDevice.RecipeRunningInfo.RecipeStepList.Count - 1; _state = RecipeRunningState.RecipeCompleted; } else { _state = RecipeRunningState.ExecStep; } } break; case RecipeRunningState.RecipeCompleted: { _recipeTimer.Stop(); if (!SetRoutineRunning(false, out reason)) { EV.PostAlarmLog(Module, $"can not run Process, {reason}"); return Result.FAIL; } //设置Succeed状态 if(_routineType == RoutineType.PurgeRoutine) { _pmInterLock.SetLidOpenRoutineSucceed(true, out reason); } else if (_routineType == RoutineType.CleanRoutine) { _pmInterLock.SetLidClosedRoutineSucceed(true, out reason); } //设置当前Step/当前循环步/当前总循环步为0 _currentStepNumber = 0; CurStartLoopStep = 0; CurrentLoopCount = CurrentLoopCount = 0; Notify("Finished"); return Result.DONE; } case RecipeRunningState.Error: { if (!SetRoutineRunning(false, out reason)) { EV.PostAlarmLog(Module, $"can not run Process, {reason}"); return Result.FAIL; } return Result.DONE; } default: break; } } catch (Exception ex) { PmDevice.SetHeaterStopRamp(); PmDevice.SetMfcStopRamp(PmDevice.GetMfcListByGroupName(MfcGroupName.All)); PmDevice.SetRotationStopRamp(); if (!SetRoutineRunning(false, out reason)) { EV.PostAlarmLog(Module, $"can not run Process, {reason}"); return Result.FAIL; } LOG.Write(ex); return Result.FAIL; } } return Result.RUN; } private void MonitorRecipeRunInfo() { PmDevice.RecipeRunningInfo.StepNumber = _currentStepNumber + 1 - _dummyStepCount; //CurStepNum start from 0, ignore dummy step PmDevice.RecipeRunningInfo.StepName = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepName; PmDevice.RecipeRunningInfo.StepTime = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime; PmDevice.RecipeRunningInfo.StepElapseTime = _stepTimer.IsIdle() ? _curStepElpasedTimeBeforePaused / 1000 : (_stepTimer.GetElapseTime() + _curStepElpasedTimeBeforePaused) / 1000; PmDevice.RecipeRunningInfo.TotalElapseTime = CalcElapseRecipeTime(); PmDevice.RecipeRunningInfo.StepElapseTime2 = _stepTimer2.IsIdle() ? _curStepElpasedTimeBeforePaused2 / 1000 : (_stepTimer2.GetElapseTime() + _curStepElpasedTimeBeforePaused2) / 1000; PmDevice.RecipeRunningInfo.TotalElapseTime2 = _recipeTimer.GetElapseTime() / 1000; if (_currentStepIndex != PmDevice.RecipeRunningInfo.StepNumber) { Notify($"Start Recipe: Step:{PmDevice.RecipeRunningInfo.StepNumber} Name:{PmDevice.RecipeRunningInfo.StepName} "); _currentStepIndex = PmDevice.RecipeRunningInfo.StepNumber; } } public override void Abort() { _state = RecipeRunningState.RecipeCompleted; _dbCallback.RecipeFailed(PmDevice.RecipeRunningInfo.InnerId.ToString()); _fdc.Stop(); PmDevice.RecipeRunningInfo.StepName = string.Empty; PmDevice.RecipeRunningInfo.StepNumber = 0; PmDevice.RecipeRunningInfo.StepTime = 0; PmDevice.RecipeRunningInfo.StepElapseTime = 0; PmDevice.RecipeRunningInfo.TotalTime = 0; PmDevice.RecipeRunningInfo.TotalElapseTime = 0; if (!SetRoutineRunning(false, out string reason)) { EV.PostAlarmLog(Module, $"can not run Process, {reason}"); } //根据Routine类型执行Abort SetRoutineAbort(); base.Abort(); } private List _lstGroup1 = new List() { "V46", "V46s", "V73" }; private List _lstGroup2 = new List() { "V46", "V46s" }; private List _lstGroup3 = new List() { "V43", "V43s", "V45" }; //默认为TMA换源参数 private int mfc7Or10 = 7; private int mfc8Or12 = 8; private int mfc11 = 11; private int pc2Or3 = 2; public void SetRoutineAbort() { if (_routineType == RoutineType.ProcessIdleRoutine) { PmDevice._ioThrottleValve.StopRamp(); PmDevice.SetMfcStopRamp(PmDevice.GetMfcListByGroupName(MfcGroupName.All)); PmDevice.SetHeaterStopRamp(); PmDevice.SetRotationStopRamp(); PmDevice.SetRotationServo(0, 0); } else if (_routineType == RoutineType.CleanRoutine) { PmDevice._ioThrottleValve.StopRamp(); PmDevice.SetMfcStopRamp(PmDevice.GetMfcListByGroupName(MfcGroupName.All)); PmDevice.SetRotationServo(0, 0); } else if (_routineType == RoutineType.PurgeRoutine) { PmDevice._ioThrottleValve.StopRamp(); PmDevice.SetMfcStopRamp(PmDevice.GetMfcListByGroupName(MfcGroupName.All)); PmDevice.SetRotationServo(0, 0); } else if (_routineType == RoutineType.PumpRoutine) { PmDevice.SetRotationServo(0, 0); } else if (_routineType == RoutineType.VentRoutine) { PmDevice._ioThrottleValve.StopRamp(); PmDevice.SetMfcStopRamp(PmDevice.GetMfcListByGroupName(MfcGroupName.All)); PmDevice.SetRotationServo(0, 0); } else if (_routineType == RoutineType.ExchangeMORoutine) { PmDevice.SetIoValue(_lstGroup1, false); PmDevice.SetIoValue(_lstGroup2, false); PmDevice.SetMfcValueToDefault(new List { mfc7Or10 }); PmDevice.SetMfcValueToDefault(new List { mfc8Or12 }); PmDevice.SetMfcValueToDefault(new List { mfc11 }); PmDevice.SetPCValueToDefault(new List { pc2Or3 }); PmDevice.SetRotationServo(0, 0); } else if (_routineType == RoutineType.VacRoutine) { PmDevice.SetRotationServo(0, 0); } } public void ExitProcess() { if (_state == RecipeRunningState.RecipeCompleted) { _dbCallback.RecipeComplete(PmDevice.RecipeRunningInfo.InnerId.ToString()); _fdc.Stop(); } else { _dbCallback.RecipeFailed(PmDevice.RecipeRunningInfo.InnerId.ToString()); _fdc.Stop(); } } public void PauseRecipe() { if (_state != RecipeRunningState.TimeWait && _state != RecipeRunningState.ConditionWait) return; if (!IsPaused) { IsPaused = true; _pausedState = _state; _state = RecipeRunningState.Paused; } } public void SkipCurrentRecipeStep() { if (_state == RecipeRunningState.ConditionWait || _state == RecipeRunningState.TimeWait) { _state = RecipeRunningState.StepCompleted; } } protected int CalcRecipeTime() { double total = 0; for (int i = 0; i < PmDevice.RecipeRunningInfo.RecipeStepList.Count; i++) { if (!PmDevice.RecipeRunningInfo.RecipeStepList[i].IsDummyStep) // 不统计虚拟Step的时间 { int loopTimes = PmDevice.RecipeRunningInfo.RecipeStepList[i].LoopCount == 0 ? 1 : PmDevice.RecipeRunningInfo.RecipeStepList[i].LoopCount; total += PmDevice.RecipeRunningInfo.RecipeStepList[i].StepTime * loopTimes; } } return (int)total; } protected int CalcElapseRecipeTime() { double total = 0; //for (int i = 0; i < _currentStepNumber; i++) //{ // if (!PMDevice.RecipeRunningInfo.RecipeStepList[i].IsDummyStep) // 不统计虚拟Step的时间 // { // total += PMDevice.RecipeRunningInfo.RecipeStepList[i].StepTime; // } //} total = _preStepTotalTime; total += PmDevice.RecipeRunningInfo.StepElapseTime; return (int)total; } protected void MonitorRecipeEndTime() { try { if (!_estimatedTimeCalcTimer.IsTimeout()) return; _estimatedTimeCalcTimer.Start(1000); EstimatedTotalLeftTime = 0; if (_state == RecipeRunningState.RecipeCompleted) return; if (!(_currentStepNumber >= 0 && _currentStepNumber <= PmDevice.RecipeRunningInfo.RecipeStepList.Count - 1)) return; if (CurStepLeftTime > 0) { EstimatedTotalLeftTime = CurStepLeftTime; } int nextBegin = _currentStepNumber; bool IsInLoop = false; int iNum1 = 0; int iNum2 = 0; //int j=i; for (int j = _currentStepNumber; j < PmDevice.RecipeRunningInfo.RecipeStepList.Count; j++) { if (PmDevice.RecipeRunningInfo.RecipeStepList[j].IsLoopEndStep) { iNum2 = j; IsInLoop = true; break; } else if (j > _currentStepNumber && PmDevice.RecipeRunningInfo.RecipeStepList[j].IsLoopStartStep) { IsInLoop = false; break; } } if (IsInLoop) { iNum1 = _currentStepNumber; for (int j = _currentStepNumber; j >= 0; j--) { if (PmDevice.RecipeRunningInfo.RecipeStepList[j].IsLoopStartStep) { iNum1 = j; break; } } for (int j = _currentStepNumber + 1; j <= iNum2; j++) { EstimatedTotalLeftTime += PmDevice.RecipeRunningInfo.RecipeStepList[j].StepTime * 1000 * (PmDevice.RecipeRunningInfo.RecipeStepList[iNum1].LoopCount - CurrentLoopCount + 1); } for (int j = iNum1; j <= _currentStepNumber; j++) { EstimatedTotalLeftTime += PmDevice.RecipeRunningInfo.RecipeStepList[j].StepTime * 1000 * (PmDevice.RecipeRunningInfo.RecipeStepList[iNum1].LoopCount - CurrentLoopCount); } nextBegin = iNum2 + 1; } else { nextBegin++; } for (int j = nextBegin; j < PmDevice.RecipeRunningInfo.RecipeStepList.Count; j++) { if (PmDevice.RecipeRunningInfo.RecipeStepList[j].IsLoopStartStep) { //j=i; iNum1 = j; iNum2 = j + 1; double lr1 = 0; for (int m = j; m < PmDevice.RecipeRunningInfo.RecipeStepList.Count; m++) { lr1 += PmDevice.RecipeRunningInfo.RecipeStepList[m].StepTime * 1000; if (PmDevice.RecipeRunningInfo.RecipeStepList[m].IsLoopEndStep) { iNum2 = m; break; } } EstimatedTotalLeftTime += lr1 * PmDevice.RecipeRunningInfo.RecipeStepList[iNum1].LoopCount; j = iNum2; } else { EstimatedTotalLeftTime += PmDevice.RecipeRunningInfo.RecipeStepList[j].StepTime * 1000; } } } catch (Exception ex) { LOG.Write(ex); } } 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; } IsPaused = false; PmDevice.ResetToleranceChecker(); } } }