using System;
using System.Collections.Generic;
using System.Xml;
using Aitex.Core.Equipment.SusceptorDefine;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.RecipeCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.Util;
using MECF.Framework.Common.DBCore;
using MECF.Framework.Common.Equipment;
using Virgo_DRT.Devices;
namespace Virgo_DRT.Modules.PMs
{
class ProcessRoutine : PMRoutineBase
{
///
/// 工艺程序运行引擎状态定义
///
private enum RecipeEngineState
{
Error,
RecipeCompleted,
ExecStep,
TimeWait,
ConditionWait,
StepCompleted,
Paused,
}
///
/// 工艺程序数据
///
private object _lockerTotalCycle = new object();
private Dictionary _recipeTotalCycle = new Dictionary();
//public bool IsAtmRecipeRun { private set; get; }
private DeviceTimer _beginPauseTimer = new DeviceTimer();
///
/// 防止工艺程序运行线程和外部更新工艺程序数据的线程并发进行
///
private object _recipeLocker = new object();
///
/// 当前工艺执行引擎的状态
///
private RecipeEngineState _state = RecipeEngineState.ExecStep;
private RecipeEngineState _pausedState = RecipeEngineState.ExecStep;
private DeviceTimer _estimatedTimeCalcTimer = new DeviceTimer();//用于定时计算工艺程序估计的结束时间
public DateTime RecipeStartTime { get; private set; }
public int RecipeChangeNo { get; private set; }
public string CurrentRecipeBaseName { get; private set; }
public string CurrentRecipeRunningName { get; private set; }
public string CurrentRecipeContent { get; private set; }
public string CurrentLotName { get; set; }
private List _recipeStepList = new List();
public List CurrentRecipeStepList
{
get
{
return _recipeStepList;
}
set
{
_recipeStepList = value;
}
}
public RecipeHead CurrentRecipeHead { get; set; }
public int CurStepNum { get; private set; }
public int CurStepTotalLoopCount { get; private set; }
public double CurStepTotalTime
{
get
{
if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)
return 0;
return _recipeStepList[CurStepNum].StepTime * 1000;
}
}
public int CurrentLoopCount
{
get;
private set;
}
private DeviceTimer StepTimer = new DeviceTimer();
public bool IsPaused
{
private set;
get;
}
public string CurStepComment
{
get
{
if (_recipeStepList == null || _recipeStepList.Count == 0)
return string.Empty;
return _recipeStepList[CurStepNum].StepName;
}
}
public double CurStepLeftTime
{
get
{
if (IsPaused)
return StepTimer.GetTotalTime() - StepTimer.GetElapseTime() + _beginPauseTimer.GetElapseTime();
//return Math.Max(0,StepTimer.GetTotalTime() - StepTimer.GetElapseTime());
return StepTimer.GetTotalTime() - StepTimer.GetElapseTime();
}
}
public double CurStepElpasedTime
{
get
{
if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)
return 0;
return StepTimer.GetElapseTime();
}
}
public double CurStepTotalRfTime
{
get
{
if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)
return 0;
if (_recipeStepList[CurStepNum].RecipeCommands.ContainsKey("Rf.SetPower") &&
!string.IsNullOrEmpty(_recipeStepList[CurStepNum].RecipeCommands["Rf.SetPower"]) &&
Convert.ToDouble(_recipeStepList[CurStepNum].RecipeCommands["Rf.SetPower"]) > 0.1)
return CurStepTotalTime;
return 0;
}
}
public int TotalCycle
{
get
{
if (string.IsNullOrEmpty(DateTimeRecipeBaseName))
return 0;
lock (_lockerTotalCycle)
{
if (_recipeTotalCycle.ContainsKey(DateTimeRecipeBaseName))
return _recipeTotalCycle[DateTimeRecipeBaseName];
}
return 0;
}
}
public string DateTimeRecipeBaseName
{
get
{
if (string.IsNullOrEmpty(CurrentRecipeBaseName))
return "";
return DateTime.Now.ToString("yyyyMMdd") + CurrentRecipeBaseName;
}
}
public double PausedTime
{
get
{
return IsPaused ? _beginPauseTimer.GetElapseTime() : 0;
}
}
public double EstimatedTotalLeftTime
{
get;
private set;
}
public int RecipeTotalStepNum
{
get
{
return _recipeStepList.Count;
}
}
public ProcessRoutine(JetPM chamber) : base(chamber)
{
Name = "ProcessRoutine";
RecipeStartTime = new DateTime(0);
EstimatedTotalLeftTime = 0;
CalcEstimatedRecipeEndTime();
}
public Result Start(params object[] param)
{
RecipeStartTime = DateTime.Now;
CurrentRecipeBaseName = (string)param[0];
CurrentRecipeRunningName = (string)param[1];
RecipeChangeNo = (int)param[2];
CurrentLotName = (string)param[3];
CurrentRecipeContent = (string)param[4];
CurrentRecipeHead = (RecipeHead)param[5];
CurrentRecipeStepList = (List)param[6];
if (!_chamber.IsRFGInterlockOn)
{
EV.PostAlarmLog(Module, "射频电源 Interlock条件不满足");
return Result.VERIFYFAIL;
}
lock (_lockerTotalCycle)
{
if (_recipeTotalCycle.ContainsKey(DateTimeRecipeBaseName))
_recipeTotalCycle[DateTimeRecipeBaseName] += 1;
else
{
_recipeTotalCycle[DateTimeRecipeBaseName] = 1;
}
List keys = new List();
foreach (KeyValuePair item in _recipeTotalCycle)
{
if (!item.Key.StartsWith(DateTime.Now.ToString("yyyyMMdd")))
keys.Add(item.Key);
}
foreach (string key in keys)
{
_recipeTotalCycle.Remove(key);
}
}
_chamber.OpenValve(ValveType.PROCESS, true);
CurStepNum = CurStepTotalLoopCount = 0;
_estimatedTimeCalcTimer.Start(1000);
//EV.PostSoundMessage($"Run Recipe {CurrentRecipeRunningName}");
EV.PostInfoLog(Module, $"工艺程序 {CurrentRecipeRunningName} 开始运行");
//更新当前的工艺状态到数据库中
//Singleton.Instance.CurrentRunningJob.JobResult = JobStatus.InProcessing;
//Singleton.Instance.UpdateProcessStatus(Singleton.Instance.CurrentRunningJob.RecipeRunId, JobStatus.InProcessing);
ProcessDataRecorder.UpdateStatus(RecipeRunGuid.ToString(), SusceptorStatus.InProcessing.ToString());
_state = RecipeEngineState.ExecStep;
return Result.RUN;
}
///
/// quiting current state
///
///
public void Exit()
{
_chamber.IsPressureToleranceEnabled = false;
var ts = DateTime.Now - RecipeStartTime;
var totalTime = $"{Convert.ToInt32(ts.TotalHours)}:{ts.Minutes}:{ts.Seconds}";
//JobInfo job = Singleton.Instance.CurrentRunningJob;
bool isProcessCompleted = _state == RecipeEngineState.RecipeCompleted;
if (isProcessCompleted)
{
//正常工艺运行结束
//Singleton.Instance.AddRecord(job.RecipeRunId, CarrierDataType.ProcessNormalEnd, totalTime, "recipe finished");
//string info = string.Format(Resources.Process_Exit_Recipe0RNStartTime1RNEndTime2RNTotalTime3,
// CurrentRecipeRunningName, RecipeStartTime.ToString("yyyy/MM/dd HH:mm:ss"),
// DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), totalTime);
EV.PostInfoLog(Module, $"工艺程序 {CurrentRecipeRunningName} 正常运行完毕");
//if (true)
//{
// EV.PostPopDialogMessage(EventLevel.Information, string.Format(Resources.Process_Exit_0RecipeCompletelyRun, Module), info);
//}
//job.JobResult = JobStatus.Processed;
}
else
{
//人为终止工艺运行结束
//Singleton.Instance.AddRecord(job.RecipeRunId, CarrierDataType.PostProcessErrorEnd, totalTime, "recipe aborted");
string info = string.Format("Recipe:{0}\r\nStart time:{1:yyyy/MM/dd HH:mm:ss}\r\nEnd time:{2:yyyy/MM/dd HH:mm:ss}\r\nTotal time:{3}",
CurrentRecipeRunningName, RecipeStartTime, DateTime.Now, totalTime);
EV.PostWarningLog(Module, info);
EV.PostPopDialogMessage(EventLevel.Warning, $"{Module} recipe was aborted", info);
//Update susceptor information
//job.JobResult = JobStatus.Troubled;
}
//job.ProcessEndTime = DateTime.Now;
//重置工艺程序名
CurrentRecipeRunningName = string.Empty;
CurrentLotName = string.Empty;
//stop all ramping when quiting processing state
//StopRamp();
}
//private void CheckPressureStability()
//{
// //如果有ThrottleValve 就检查Throttle Valve的tolerance
// if (DeviceModel.PressureControl != null)
// {
// DeviceModel.PressureControl.EnableTolerance =
// DeviceModel.MfcGas1 != null && DeviceModel.MfcGas1.SetPoint > 0.001 ||
// DeviceModel.MfcGas2 != null && DeviceModel.MfcGas2.SetPoint > 0.001 ||
// DeviceModel.MfcGas3 != null && DeviceModel.MfcGas3.SetPoint > 0.001;
// }
//}
///
/// 工艺程序运行引擎放于此处
///
public Result Monitor()
{
string reason = string.Empty;
CalcEstimatedRecipeEndTime();
//检查软件互锁是否强制停止运行工艺程序
//if (!doRoutineRunning.Value)
//{
// if (!doRoutineRunning.Check(true, out reason))
// {
// EV.PostMessage(Module.ToString(), EventEnum.RecipeAbortedByInterlock, Module, reason);
// return Result.FAIL; // Reactor.PostEvent(new AlarmHandleCommand("软件互锁"));
// }
//}
//工艺程序运行监控,自动打开阀门如果对应的MFC设定设置大于0
_chamber.Monitor();
if (_chamber.IsError)
return Result.FAIL;
if (_chamber.CheckFactoryScrubberSysAlarm)
{
_chamber.OpenValve(ValveType.FAST_PUMP, false);
_chamber.OpenValve(ValveType.SOFT_PUMP, false);
EV.PostAlarmLog(Module, $"{Module} {Name} Factory Scrubber System is alarm ");
return Result.FAIL;
}
//工艺程序运行引擎
lock (_recipeLocker)
{
try
{
switch (_state)
{
case RecipeEngineState.ExecStep:
{
//工艺程序循环设置
if (_recipeStepList[CurStepNum].IsLoopStartStep)
{
CurStepTotalLoopCount = _recipeStepList[CurStepNum].LoopCount;
if (CurStepTotalLoopCount == 0)
{
CurrentLoopCount = 0;
}
else
{
CurrentLoopCount++;
}
}
//当前工艺程序步的定时器设定
StepTimer.Start(_recipeStepList[CurStepNum].StepTime * 1000);
//Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId,
// CarrierDataType.RecipeStepStart, (CurStepNum + 1).ToString(),
// string.Format(Resources.Process_Monitor_RecipeRunningStartStep01, CurStepNum + 1, _recipeStepList[CurStepNum].StepName));
//发送信息到用户界面
EV.PostInfoLog(Module, $"工艺程序 {CurrentRecipeRunningName} 第{CurStepNum + 1} 步开始:{_recipeStepList[CurStepNum].StepName}");
//执行工艺程序命令
foreach (var cmdkey in _recipeStepList[CurStepNum].RecipeCommands.Keys)
{
string recipeCmd = cmdkey;
string param = _recipeStepList[CurStepNum].RecipeCommands[recipeCmd];
if (string.IsNullOrWhiteSpace(param)) continue;
if (!OP.CanDoOperation($"{Module}." + recipeCmd, out reason, param))
{
EV.PostAlarmLog(Module, $"不能执行 {recipeCmd}, {reason}");
return Result.FAIL;
}
else
{
var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);
if (_recipeStepList[CurStepNum].IsJumpStep)
rampTime_ms = 0;
OP.DoOperation($"{Module}." + recipeCmd, out string reason1, rampTime_ms, param);
}
// if (!DEVICE.CanDo(recipeCmd))
//{
// EV.PostMessage(Module.ToString(), EventEnum.DefaultWarning, Module, recipeCmd);
//}
//else
//{
// var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);
// if (_recipeStepList[CurStepNum].IsJumpStep)
// rampTime_ms = 0;
// string str = _recipeStepList[CurStepNum].RecipeCommands[cmdkey];
// if (!string.IsNullOrEmpty(str))
// DEVICE.Do(recipeCmd, rampTime_ms, false, str);
//}
}
string endby = _recipeStepList[CurStepNum].EndBy;
if (string.IsNullOrEmpty(endby) ||
string.Compare(endby, "EndByStepTime", StringComparison.OrdinalIgnoreCase) == 0 ||
string.Compare(endby, "EndByRfTime", StringComparison.OrdinalIgnoreCase) == 0)
{
_state = RecipeEngineState.TimeWait;
}
else
{
_state = RecipeEngineState.ConditionWait;
}
}
break;
case RecipeEngineState.TimeWait:
_chamber.CheckPressureStability();
if (StepTimer.IsTimeout())
{
_state = RecipeEngineState.StepCompleted;
}
break;
case RecipeEngineState.ConditionWait:
{
//var endbyCondition = (EndByCondition)Enum.Parse(typeof(EndByCondition), _recipeStepList[CurStepNum].EndBy, true);
//var endbyValue = Convert.ToDouble(_recipeStepList[CurStepNum].EndByValue);
//if (isStepEndby(endbyCondition, endbyValue))
{
_state = RecipeEngineState.StepCompleted;
}
}
break;
case RecipeEngineState.Paused:
break;
case RecipeEngineState.StepCompleted:
{
//发送新的一步开始的信息到用户界面
EV.PostInfoLog(Module, $"工艺程序 {CurrentRecipeRunningName} 第{CurStepNum + 1}步结束");
//添加石墨盘信息
//Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepNormalEnd, (CurStepNum + 1).ToString(), string.Format("recipe running:end step {0}", CurStepNum + 1));
//判断是否当前步循环终止
if (_recipeStepList[CurStepNum].IsLoopEndStep)
{
//重新读取循环的设定次数
for (int nn = CurStepNum; nn >= 0; nn--)
{
if (_recipeStepList[nn].IsLoopStartStep)
{
CurStepTotalLoopCount = _recipeStepList[nn].LoopCount;
break;
}
}
if (CurrentLoopCount >= CurStepTotalLoopCount)
{
CurrentLoopCount = CurStepTotalLoopCount = 0;
CurStepNum++;
}
else
{
int n = CurStepNum - 1;
int next = -1;
while (n >= 0)
{
if (_recipeStepList[n].IsLoopStartStep)
{
next = n;
break;
}
n--;
}
if (next == -1)
throw new Exception("Loop End control error");
CurStepNum = next;
}
}
else
{
if (CurStepNum < _recipeStepList.Count - 1)
{
CurStepNum++;
_state = RecipeEngineState.ExecStep;
}
else
{
EV.PostInfoLog(Module, $"工艺 {CurrentRecipeRunningName} 完毕");
CurStepNum = _recipeStepList.Count - 1;
_state = RecipeEngineState.RecipeCompleted;
return Result.DONE;
}
}
}
break;
case RecipeEngineState.RecipeCompleted:
return Result.DONE;
case RecipeEngineState.Error:
return Result.FAIL;
default:
break;
}
}
catch (Exception ex)
{
EV.PostAlarmLog(Module, $"{CurStepNum + 1}, 语法错误, {ex.Message}");
return Result.FAIL;
}
}
return Result.RUN;
}
///
/// 暂停工艺程序运行
///
public void PauseRecipe()
{
if (_state != RecipeEngineState.TimeWait && _state != RecipeEngineState.ConditionWait)
return;
if (!IsPaused)
{
string reason = string.Empty;
IsPaused = true;
_pausedState = _state;
_state = RecipeEngineState.Paused;
_beginPauseTimer.Start(0);
//Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepPaused, CurStepNum.ToString(), string.Format(Resources.Process_PauseRecipe_工艺运行中当前第0步暂停, CurStepNum + 1));
EV.PostInfoLog(Module, $"工艺程序'{CurrentRecipeRunningName}'第{CurStepNum + 1}步暂停");
//pause mfc
//pause pc
//StopRamp();
}
}
///
/// 恢复工艺程序运行
///
public void ResumeRecipe()
{
if (IsPaused)
{
//update current recipe step time
string recipeXml = CurrentRecipeContent;
int currentStepNo = CurStepNum;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(recipeXml);
var stepNodes = xmlDoc.SelectNodes("/TableRecipeData/Step");
if (currentStepNo >= 0 && currentStepNo < stepNodes.Count)
{
var curStepNode = stepNodes[currentStepNo] as XmlElement;
var curStepNewTime = CurStepTotalTime + PausedTime;
if (curStepNewTime < 0)
curStepNewTime = 0;
TimeSpan tspan = new TimeSpan(0, 0, 0, 0, (int)curStepNewTime);
var timeString =
$"{((int)tspan.TotalHours).ToString("00")}:{tspan.Minutes.ToString("00")}:{tspan.Seconds.ToString("00")}";
curStepNode.SetAttribute("Time", timeString);
LOG.Write($"执行Resume命令,将当前第{currentStepNo}步时间修改为{timeString}");
UpdateRecipe(xmlDoc.OuterXml);
}
//Resume recipe
IsPaused = false;
_state = _pausedState;
//Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepResume, CurStepNum.ToString(), string.Format("工艺运行中:当前第{0}步,取消暂停", CurStepNum + 1));
EV.PostInfoLog(Module, $"工艺程序'{CurrentRecipeRunningName}'第{CurStepNum + 1}步继续");
//resume recipe
double stepElapsedTime = StepTimer.GetElapseTime() - _beginPauseTimer.GetElapseTime();
double stepLeftTime = StepTimer.GetTotalTime() - stepElapsedTime;
if (stepLeftTime < 0)
stepLeftTime = 0;
//更新当前步的定时器时间
StepTimer.Restart(StepTimer.GetTotalTime() + _beginPauseTimer.GetElapseTime());
//重新执行当前工艺程序步
foreach (var recipeCmd in _recipeStepList[CurStepNum].RecipeCommands.Keys)
{
if (!DEVICE.CanDo(recipeCmd))
{
EV.PostInfoLog(Module, $"不可识别的工艺程序控制命令{recipeCmd}");
}
else
{
var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);
if (_recipeStepList[CurStepNum].IsJumpStep)
rampTime_ms = 0;
DEVICE.Do(recipeCmd, rampTime_ms, false, _recipeStepList[CurStepNum].RecipeCommands[recipeCmd]);
}
}
}
}
///
/// 终止工艺程序运行
///
public void AbortRecipe()
{
ResumeRecipe();
_state = RecipeEngineState.RecipeCompleted;
CalcEstimatedRecipeEndTime();
//StopRamp();
//send informational event
//Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepResume, CurStepNum.ToString(), string.Format("recipe running:aborted in step {0}", CurStepNum + 1));
EV.PostInfoLog(Module, "工艺程序被终止运行");
}
///
/// 跳至工艺程序下一步
///
public void SkipCurrentRecipeStep()
{
if (_state == RecipeEngineState.Paused)
{
EV.PostInfoLog(Module, "在 Pause Recipe 状态下不能执行 Skip to next step 命令");
return;
}
try
{
//update current recipe step time
string recipeXml = CurrentRecipeContent;
int currentStepNo = CurStepNum;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(recipeXml);
var stepNodes = xmlDoc.SelectNodes("/TableRecipeData/Step");
if (currentStepNo >= 0 && currentStepNo < stepNodes.Count)
{
var curStepNode = stepNodes[currentStepNo] as XmlElement;
var curStepElapsedTime = CurStepTotalTime - CurStepLeftTime;//ms
if (curStepElapsedTime < 0)
curStepElapsedTime = 0;
TimeSpan tspan = new TimeSpan(0, 0, 0, 0, (int)curStepElapsedTime);
var timeString =
$"{((int)tspan.TotalHours).ToString("00")}:{tspan.Minutes.ToString("00")}:{tspan.Seconds.ToString("00")}";
curStepNode.SetAttribute("Time", timeString);
LOG.Write($"step skipped,step {currentStepNo} time changed to {timeString}");
//recipe update command
UpdateRecipe(xmlDoc.OuterXml);
}
}
catch (Exception ex)
{
LOG.Write(ex);
}
if (_state == RecipeEngineState.ConditionWait || _state == RecipeEngineState.TimeWait)
{
_state = RecipeEngineState.StepCompleted;
//send informational event
EV.PostMessage(Module, EventEnum.GeneralInfo, Module, CurrentRecipeRunningName, CurStepNum + 1);
//Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeStepJump, CurStepNum.ToString(), string.Format("Recipe Running:current step {0},skip to next step", CurStepNum + 1));
}
}
public bool UpdateRecipe(string newRecipeContent)
{
lock (_recipeLocker)
{
RecipeHead head = null;
List newRecipeData = null;
if (!Recipe.Parse(newRecipeContent, out head, out newRecipeData))
{
EV.PostMessage(Module, EventEnum.DefaultAlarm, Module, CurrentRecipeRunningName);
return false;
}
else
{
string oldRecipeName = CurrentRecipeRunningName;
CurrentRecipeRunningName =
$"{DateTime.Now:yyyyMMddHHmmss}-{CurrentRecipeBaseName}-({RecipeChangeNo++})";
//update local recipe data
_recipeStepList = newRecipeData;
CurrentRecipeContent = newRecipeContent;
//Singleton.Instance.UpdateProcessRecipeName(Singleton.Instance.CurrentRunningJob.RecipeRunId, CurrentRecipeRunningName);
//update susceptor recipe name
//Susceptor sus = SusceptorManager.Instance.GetSystemSusceptors()[ModuleName.System];
//if (sus != null)
//{
// sus.RecipeName = RecipeName;
// SusceptorManager.Instance.Persist();
//}
//send informational event
EV.PostInfoLog(Module, $"运行工艺程序'{oldRecipeName}'第{CurStepNum + 1}步时更新工艺程序为'{CurrentRecipeRunningName}");
//Singleton.Instance.AddRecord(Singleton.Instance.CurrentRunningJob.RecipeRunId, CarrierDataType.RecipeUpdated, CurStepNum.ToString(), string.Format("工艺运行中:当前第{0}步,更新程序:{1}", CurStepNum + 1, CurrentRecipeRunningName));
//notify recipe change event to TM
RecipeFileManager.Instance.SaveRecipeHistory(ModuleName.System.ToString(), CurrentRecipeRunningName, CurrentRecipeContent);
}
}
return true;
}
///
/// Status name
///
///
public override string ToString()
{
return "recipe running";
}
protected void sendRecipeStopToSmart()
{
///工艺停止发送StreamOffCommand
// NotifierSmart.SendCommand("StreamOffCommand", Reactor.ChamId);
}
///
/// 工艺程序估计结束时间计算
///
protected void CalcEstimatedRecipeEndTime()
{
try
{
//(*计算当前工艺程序预计所需的总时间,从当前步开始计算剩余步的估算时间+已经既成事实的时间 => 总的估计时间,采用该种方式进行总工艺时间理论上最为精确*)
if (!_estimatedTimeCalcTimer.IsTimeout())
return;
_estimatedTimeCalcTimer.Start(1000);
EstimatedTotalLeftTime = 0;
if (_state == RecipeEngineState.RecipeCompleted)
return;
if (!(CurStepNum >= 0 && CurStepNum <= _recipeStepList.Count - 1))
return;
if (CurStepLeftTime > 0)
{
EstimatedTotalLeftTime = CurStepLeftTime;
}
int nextBegin = CurStepNum;
//(*判断当前是否处于循环之中*)
bool IsInLoop = false;
int iNum1 = 0;
int iNum2 = 0;
//int j=i;
for (int j = CurStepNum; j < _recipeStepList.Count; j++)
{
if (_recipeStepList[j].IsLoopEndStep)
{
iNum2 = j;
IsInLoop = true;
break;
}
else if (j > CurStepNum && _recipeStepList[j].IsLoopStartStep)
{
IsInLoop = false;
break;
}
}
if (IsInLoop)
{
//(*当前步处于循环中*)
iNum1 = CurStepNum;
for (int j = CurStepNum; j >= 0; j--)
{
if (_recipeStepList[j].IsLoopStartStep)
{
iNum1 = j;
break;
}
}
for (int j = CurStepNum + 1; j <= iNum2; j++)
{
EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000 * (_recipeStepList[iNum1].LoopCount - CurrentLoopCount + 1);
}
for (int j = iNum1; j <= CurStepNum; j++)
{
EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000 * (_recipeStepList[iNum1].LoopCount - CurrentLoopCount);
}
nextBegin = iNum2 + 1;
}
else
{
nextBegin++;
}
//(*当前步处于循环外*)
for (int j = nextBegin; j < _recipeStepList.Count; j++)
{
if (_recipeStepList[j].IsLoopStartStep)
{
//j=i;
iNum1 = j;
iNum2 = j + 1;
double lr1 = 0;
for (int m = j; m < _recipeStepList.Count; m++)
{
lr1 += _recipeStepList[m].StepTime * 1000;
if (_recipeStepList[m].IsLoopEndStep)
{
iNum2 = m;
break;
}
}
EstimatedTotalLeftTime = EstimatedTotalLeftTime + lr1 * _recipeStepList[iNum1].LoopCount;
j = iNum2;
}
else
{
EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000;
}
//END_WHILE
}
}
catch (Exception ex)
{
LOG.Write(ex);
}
}
}
}