Sic08/Modules/Mainframe/PMs/RecipeExecutions/Process.cs

1048 lines
43 KiB
C#
Raw Normal View History

2023-04-13 15:35:13 +08:00
using System;
using System.Collections.Generic;
using Aitex.Core.Common;
2023-03-28 13:24:11 +08:00
using Aitex.Core.RT.DataCenter;
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.RT.Tolerance;
using Aitex.Core.Util;
using MECF.Framework.Common.DBCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.SubstrateTrackings;
2023-04-23 14:18:42 +08:00
using MECF.Framework.UI.Core.TrayCoating;
2023-04-13 15:35:13 +08:00
using SicModules.PMs.Routines.Base;
2023-03-28 13:24:11 +08:00
using static Aitex.Core.RT.Device.PmDevices.DicMode;
2023-04-13 15:35:13 +08:00
namespace SicModules.PMs.RecipeExecutions
2023-03-28 13:24:11 +08:00
{
public enum RecipeContinueMode
{
None,
WaferReturnAndJobStop,
RecipeCompleted,
StepContinue,
StepRestart,
RecipeRestart,
NextStep,
}
public partial class Process : PMBaseRoutine
{
enum RoutineStep
{
WaitProcess,
}
enum RecipeRunningState
{
Error,
RecipeCompleted,
ExecStep,
TimeWait,
ConditionWait,
StepCompleted,
Paused,
}
private object _recipeLocker = new object();
private bool _hasRecordRunTime = false;
private RecipeRunningState _state = RecipeRunningState.ExecStep;
private RecipeRunningState _pausedState = RecipeRunningState.ExecStep;
private DeviceTimer _estimatedTimeCalcTimer = new DeviceTimer();//用于定时计算工艺程序估计的结束时间
private double _curStepElpasedTimeBeforePaused;
private double _curStepElpasedTimeBeforePaused2;
private List<int> _lstSkipSteps = new List<int>();
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;
}
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 bool _isDryRun;
private int _delayTimeDryRun;
private double _tempOffset;
private int _currentStepIndex = 99;
private IoInterLock _pmInterLock;
#region Parse
private bool _isPSUHeaterJumpMode;
private bool _isSCRHeaterJumpMode;
private bool _isMFCJumpMode;
#endregion
#region Check
private PeriodicJob _thread;
private DeviceTimer _rampCalcTimer = new DeviceTimer();//用于定时获取PC的Ramp
protected ToleranceChecker[] _mfcGapChecker = new ToleranceChecker[32];
protected R_TRIG[] _mfcTrig = new R_TRIG[32];
protected ToleranceChecker[] _pcGapChecker = new ToleranceChecker[7];
protected R_TRIG[] _pcTrig = new R_TRIG[7];
protected R_TRIG[] _pcTrig2 = new R_TRIG[7];
protected double[] _pressurePrevious = new double[7];
#endregion
public Process(ModuleName module, PMModule pm1) : base(module, pm1)
{
Module = module.ToString();
Name = "Process";
_dbCallback = new RecipeDBCallback();
_fdc = new Fdc(Module);
_pmInterLock = DEVICE.GetDevice<IoInterLock>($"{Module}.PMInterLock");
for (int i = 0; i < _mfcGapChecker.Length; i++)
{
_mfcGapChecker[i] = new ToleranceChecker();
_mfcTrig[i] = new R_TRIG();
}
for (int i = 0; i < _pcGapChecker.Length; i++)
{
_pcGapChecker[i] = new ToleranceChecker();
_pcTrig[i] = new R_TRIG();
_pcTrig2[i] = new R_TRIG();
}
Initialize();
Calculte();
_thread = new PeriodicJob(10 * 1000, Calculte, "Calculte Standard Deviation", false);
}
public override Result Start(params object[] param)
{
Reset();
_hasRecordRunTime = false;
if (!_pmInterLock.SetPMProcessRunning(true, out string reason))
{
EV.PostAlarmLog(Module, $"can not run Process, {reason}");
return Result.FAIL;
}
_lstSkipSteps = new List<int>();
_currentStepIndex = 99;
_currentStepNumber = CurStepTotalLoopCount = 0;
_dummyStepCount = 0;
_estimatedTimeCalcTimer.Start(1000);
_rampCalcTimer.Start(1000);
PmDevice.RecipeRunningInfo.InnerId = Guid.NewGuid();
PmDevice.RecipeRunningInfo.BeginTime = DateTime.Now;
PmDevice.RecipeRunningInfo.TotalTime = CalcRecipeTime();
PmDevice.RecipeRunningInfo.IsRoutineAbort = false;
_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);
WaferManager.Instance.GetWafer(ModuleHelper.Converter(Module), 0).TrayProcessCount--;
_fdc.Reset();
_isDryRun = SC.GetValue<bool>($"PM.{Module}.DryRun.IsDryRun");
_delayTimeDryRun = SC.GetValue<int>($"PM.{Module}.DryRun.DryRunDelayTime");
_tempOffset = SC.GetValue<double>($"PM.{Module}.Process.TempOffset");
_thread.Start();
Notify($"Start");
return Result.RUN;
}
public override Result Monitor()
{
if (!PmDevice.CheckEnableRunProcess(out string reason))
{
EV.PostAlarmLog(Module, reason);
return Result.FAIL;
}
if (_isDryRun) // 空跑工艺
{
try
{
DryRunProcess((int)RoutineStep.WaitProcess, $"Chamber:{Name}:WaitProcess", _delayTimeDryRun);
}
catch (RoutineBreakException)
{
return Result.RUN;
}
catch (RoutineFaildException)
{
return Result.FAIL;
}
Notify("End");
return Result.DONE;
}
else
{
MonitorRecipeEndTime();
MonitorRecipeRunInfo();
lock (_recipeLocker)
{
try
{
switch (_state)
{
case RecipeRunningState.ExecStep:
{
PmDevice.ResetToleranceChecker();
//int stepTime = (int)PMDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime * 1000;
if (ContinueAction != RecipeContinueMode.StepContinue)
{
_curStepElpasedTimeBeforePaused = 0;
_curStepElpasedTimeBeforePaused2 = 0;
}
ContinueAction = RecipeContinueMode.None;
if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsLoopStartStep)
{
CurStepTotalLoopCount = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].LoopCount;
if (CurStepTotalLoopCount == 0)
{
CurrentLoopCount = 0;
}
else
{
CurrentLoopCount++;
}
}
//stepTime = (int)(PMDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime - _curStepElpasedTimeBeforePaused / 1000);
_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 - _curStepElpasedTimeBeforePaused);// (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)
{
if (_lstSkipSteps.Count>0 && _lstSkipSteps.Contains(previousStepNumber)) //上一步是跳步过来的,这一步和上一步的值是相同的不用设置
{
continue;
}
time = 1;
}
}
}
}
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;
//ResetChecker();
_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;
2023-04-23 14:18:42 +08:00
Grow();
2023-03-28 13:24:11 +08:00
}
//ToleranceChecker();
SkipStepForHeat();
break;
case RecipeRunningState.ConditionWait:
{
if (_stepTimer.IsTimeout())
{
_state = RecipeRunningState.StepCompleted;
2023-04-23 14:18:42 +08:00
Grow();
2023-03-28 13:24:11 +08:00
}
}
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<RouteManager>.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:
{
//放在前面stepnumber后面会被更新
_stepTimer2.Stop();
_dbCallback.RecipeStepEnd(PmDevice.RecipeRunningInfo.InnerId.ToString(), _currentStepNumber, _fdc.DataList);
_fdc.Stop();
if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsLoopEndStep)
{
//重新读取循环的设定次数
for (int nn = _currentStepNumber; nn >= 0; nn--)
{
if (PmDevice.RecipeRunningInfo.RecipeStepList[nn].IsLoopStartStep)
{
CurStepTotalLoopCount = PmDevice.RecipeRunningInfo.RecipeStepList[nn].LoopCount;
break;
}
}
if (CurrentLoopCount >= CurStepTotalLoopCount)
{
CurrentLoopCount = CurStepTotalLoopCount = 0;
_currentStepNumber++;
}
else
{
int n = _currentStepNumber - 1;
int next = -1;
while (n >= 0)
{
if (PmDevice.RecipeRunningInfo.RecipeStepList[n].IsLoopStartStep)
{
next = n;
break;
}
n--;
}
if (next == -1)
throw new Exception("Loop End control error");
_currentStepNumber = next;
}
}
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:
{
//更新PM的Runtime
if (!_hasRecordRunTime)
{
_hasRecordRunTime = true;
RuntimeDataRecorder.UpdateElapseTimePM(Module + " Process", (int)(_recipeTimer.GetElapseTime() / 60000));
}
_recipeTimer.Stop();
Notify("Finished");
return Result.DONE;
}
case RecipeRunningState.Error:
{
//更新PM的Runtime
if (!_hasRecordRunTime)
{
_hasRecordRunTime = true;
RuntimeDataRecorder.UpdateElapseTimePM(Module+" Process", (int)(_recipeTimer.GetElapseTime() / 60000));
}
return Result.DONE;
}
default:
break;
}
}
catch (Exception ex)
{
PmDevice.SetHeaterStopRamp();
PmDevice.SetMfcStopRamp(PmDevice.GetMfcListByGroupName(MfcGroupName.All));
PmDevice.SetRotationStopRamp();
LOG.Write(ex);
return Result.FAIL;
}
}
return Result.RUN;
}
}
private void MonitorRecipeRunInfo()
{
try
{
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;
2023-04-23 14:18:42 +08:00
PmDevice.RecipeRunningInfo.GrowthRate = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].GrowthRate;
2023-03-28 13:24:11 +08:00
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 (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands.ContainsKey("SHArH2Switch.SetValve"))
{
PmDevice.RecipeRunningInfo.ArH2Switch = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands["SHArH2Switch.SetValve"];
}
if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands.ContainsKey("N2Dilution.SetValve"))
{
PmDevice.RecipeRunningInfo.N2FlowMode = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands["N2Dilution.SetValve"];
}
if (_currentStepIndex != PmDevice.RecipeRunningInfo.StepNumber)
{
Notify($"Start Recipe: Step:{PmDevice.RecipeRunningInfo.StepNumber} Name:{PmDevice.RecipeRunningInfo.StepName} ");
_currentStepIndex = PmDevice.RecipeRunningInfo.StepNumber;
}
}
catch (Exception ex)
{
}
}
public override void Abort()
{
//更新PM的Runtime
PmDevice.RecipeRunningInfo.IsRoutineAbort = true;
if (!_hasRecordRunTime)
{
_hasRecordRunTime = true;
RuntimeDataRecorder.UpdateElapseTimePM(Module + " Process", (int)(_recipeTimer.GetElapseTime() / 60000));
}
_state = RecipeRunningState.RecipeCompleted;
_dbCallback.RecipeFailed(PmDevice.RecipeRunningInfo.InnerId.ToString());
_fdc.Stop();
PmDevice.AbortRunProcess(out string reason);
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;
//PMDevice.Rf.SetPowerOnOff(false, out _);
//PMDevice.Microwave.SetPowerOnOff(false, out _);
//PMDevice.GasLine1.SetFlow(out _, 0, 0);
//PMDevice.GasLine2.SetFlow(out _, 0, 0);
//PMDevice.GasLine3.SetFlow(out _, 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();
}
_thread.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)
{
_lstSkipSteps.Add(_currentStepNumber);
_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的时间
{
total += PmDevice.RecipeRunningInfo.RecipeStepList[i].StepTime;
}
}
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 += 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();
}
public void DryRunProcess(int id, string stepName, int delayTime)
{
Tuple<bool, Result> ret = Delay(id, () =>
{
Notify($"Dry run process {delayTime} seconds");
_stepSpan = new TimeSpan(0, 0, 0, (int)delayTime);
_stepStartTime = DateTime.Now;
_stepName = stepName;
return true;
}, delayTime * 1000);
if (ret.Item1)
{
if (ret.Item2 == Result.FAIL)
{
throw (new RoutineFaildException());
}
throw new RoutineBreakException();
}
}
public void ToleranceChecker()
{
#region MFC
for (int i = 0; i < _mfcGapChecker.Length; i++)
{
_mfcGapChecker[i].Monitor(PmDevice._mfcList[i].FeedBack, PmDevice._mfcList[i].SetPoint * (1 - 2 / 100), PmDevice._mfcList[i].SetPoint * (1 + 2 / 100), 5 * 60);
if (_mfcGapChecker[i].Trig)
{
EV.PostWarningLog(Module, $"{PmDevice._mfcList[i].Name} flow gap > 2%, over 5 minites");
}
}
for (int i = 0; i < _mfcTrig.Length; i++)
{
double gap = Convert.ToDouble(dbMfcGapResults[i].StdDev);
double setPoint = Convert.ToDouble(dbMfcSetPointResults[i].Mean);
_mfcTrig[i].CLK = gap / setPoint > 1 / 100;
if (_mfcTrig[i].Q)
{
EV.PostWarningLog(Module, $"{PmDevice._mfcList[i].Name} flow standard deviation > 1%, for 5 minites");
}
}
#endregion
#region PC
for (int i = 0; i < _pcGapChecker.Length; i++)
{
_pcGapChecker[i].Monitor(PmDevice._pcList[i].FeedBack, PmDevice._pcList[i].SetPoint - 60, PmDevice._pcList[i].SetPoint + 60, 5 * 60);
if (_pcGapChecker[i].Trig)
{
EV.PostWarningLog(Module, $"{PmDevice._pcList[i].Name} flow gap > 60 mbar over 5 minites");
}
}
for (int i = 0; i < _pcTrig.Length; i++)
{
double gap = Convert.ToDouble(dbPcGapResults[i].StdDev);
//double setPoint = Convert.ToDouble(dbPcSetPointResults[i].StdDev);
_pcTrig[i].CLK = gap > 10;
if (_pcTrig[i].Q)
{
EV.PostWarningLog(Module, $"{PmDevice._mfcList[i].Name} flow standard deviation > 1%, for 5 minites");
}
}
if (_rampCalcTimer.IsTimeout())
{
for (int i = 0; i < _pcTrig2.Length; i++)
{
_pcTrig2[i].CLK = Math.Abs(PmDevice._pcList[i].FeedBack - _pressurePrevious[i]) > 90;
if (_pcTrig2[i].Q)
{
EV.PostWarningLog(Module, $"{PmDevice._mfcList[i].Name} pressure ramp > 90 mbar");
}
_pressurePrevious[i] = PmDevice._pcList[i].FeedBack;
}
_rampCalcTimer.Start(1000);
}
#endregion
}
public void ResetChecker()
{
#region MFC
for (int i = 0; i < _mfcGapChecker.Length; i++)
{
_mfcGapChecker[i].Reset(5 * 60);
}
for (int i = 0; i < _mfcTrig.Length; i++)
{
_mfcTrig[i].RST = true;
}
#endregion
#region PC
for (int i = 0; i < _pcGapChecker.Length; i++)
{
_pcGapChecker[i].Reset(5 * 60);
}
for (int i = 0; i < _pcTrig.Length; i++)
{
_pcTrig[i].RST = true;
}
#endregion
}
public void SkipStepForHeat()
{
int stepCount = PmDevice.RecipeRunningInfo.RecipeStepList.Count;
if (_currentStepNumber + 1 < stepCount)
{
var currentStep = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber];
var nextStep = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber + 1];
if (currentStep.IsDummyStep)
return;
if (nextStep.IsDummyStep)
nextStep = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber + 2];
if (!currentStep.RecipeCommands.ContainsKey("TC1.SetHeaterMode") || !nextStep.RecipeCommands.ContainsKey("TC1.SetHeaterMode"))
return;
HeaterControlMode currentPSUMode = (HeaterControlMode)Enum.Parse(typeof(HeaterControlMode), currentStep.RecipeCommands["TC1.SetHeaterMode"]);
HeaterControlMode nextPSUMode = (HeaterControlMode)Enum.Parse(typeof(HeaterControlMode), nextStep.RecipeCommands["TC1.SetHeaterMode"]);
if (currentPSUMode == HeaterControlMode.Power && nextPSUMode != HeaterControlMode.Power)
{
float PSUL2InputTemp =(float)DATA.Poll($"{Module}.TC1.L2InputTempSetPoint"); // (float)DATA.Poll($"{Module}.TC1.L1PVFeedBack"); 测试用
float nextL2Temp = Convert.ToSingle(nextStep.RecipeCommands["TC1.SetL2TargetSP"]);
if (nextL2Temp > PSUL2InputTemp && nextL2Temp - PSUL2InputTemp < Math.Abs(_tempOffset))
{
SkipCurrentRecipeStep();
EV.PostInfoLog(Module, $"Current PSU middle temperature is {PSUL2InputTemp}℃ and Power mode, next step PSU middle temperature setpoint is {nextL2Temp}℃ and {nextPSUMode} mode." +
$" TempOffset is {_tempOffset}℃. Need jump step!");
}
}
}
}
2023-04-23 14:18:42 +08:00
public void Grow()
{
var wi = WaferManager.Instance.GetWafer(ModuleHelper.Converter(Module), 0);
OP.DoOperation($"CoatingManager.Grow",
new object[] {
2023-04-23 14:18:42 +08:00
(wi.TrayOriginSlot+1).ToString(),
PmDevice.RecipeRunningInfo.GrowthRate,
PmDevice.RecipeRunningInfo.StepTime ,
Module });
}
2023-03-28 13:24:11 +08:00
}
}