using System;
using System.Collections.Generic;
using System.Xml;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Job;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.RecipeCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.Util;
using Aitex.Core.RT.SCCore;
using Aitex.Platform;
using Aitex.RT.Properties;
using Aitex.Triton160.Common;
using Aitex.Triton160.RT.Device;
using Aitex.Triton160.RT.Module;
namespace Aitex.Triton160.RT.Routine.Process
{
public class Process : CommonRoutine
{
///
/// 工艺程序运行引擎状态定义
///
enum RecipeEngineState
{
Error,
RecipeCompleted,
ExecStep,
TimeWait,
ConditionWait,
StepCompleted,
Paused,
}
enum CycleCountResetFlag
{
ResetByDay,
ResetByRecipe,
}
///
/// 工艺程序数据
///
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();//用于定时计算工艺程序估计的结束时间
private int _currentRecipeCycleCount = 0;
private string _previousRecipeName;
private string _processCompleteInfo;
private bool _isProcessCompleted;
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;
}
public string CurrentJobName
{
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;
var ResetFlag = (int)SC.GetValue(SCName.ProcessConfig_RecipeCycleCouterFlag);
lock (_lockerTotalCycle)
{
if (ResetFlag == (int)CycleCountResetFlag.ResetByDay)
{
if (_recipeTotalCycle.ContainsKey(DateTimeRecipeBaseName))
return _recipeTotalCycle[DateTimeRecipeBaseName];
}
else
{
return _currentRecipeCycleCount;
}
}
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 Process(string module, string name)
{
Module = module;
Name = name;
Display = Resources.Process_Process_Process;
RecipeStartTime = new DateTime(0);
EstimatedTotalLeftTime = 0;
}
public bool Initialize()
{
InitCommon();
CalcEstimatedRecipeEndTime();
return true;
}
public Result Start(params object[] param)
{
RecipeStartTime = DateTime.Now;
CurrentRecipeBaseName = (string)param[0];
if (String.Equals(_previousRecipeName,CurrentRecipeBaseName))
_currentRecipeCycleCount++;
else
{
_currentRecipeCycleCount = 1;
_previousRecipeName = CurrentRecipeBaseName;
}
CurrentRecipeRunningName = (string)param[1];
RecipeChangeNo = (int)param[2];
CurrentLotName = (string)param[3];
CurrentRecipeContent = (string)param[4];
CurrentRecipeHead = (RecipeHead)param[5];
CurrentRecipeStepList = (List)param[6];
CurrentJobName = (string)param[7];
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);
}
}
CurStepNum = CurStepTotalLoopCount = 0;
_estimatedTimeCalcTimer.Start(1000);
//TmService.NotifySusceptorStatusChanged(RecipeName, SusceptorStatus.InProcessing); //@AAA
EV.PostSoundMessage(String.Format("Run Recipe {0}", CurrentRecipeRunningName));
EV.PostMessage(Module, EventEnum.RecipeStart, Module, CurrentRecipeRunningName);
//更新当前的工艺状态到数据库中
Singleton.Instance.CurrentRunningJob.JobResult = JobStatus.InProcessing;
Singleton.Instance.UpdateProcessStatus(Singleton.Instance.CurrentRunningJob.RecipeRunId, JobStatus.InProcessing);
_state = RecipeEngineState.ExecStep;
return Result.RUN;
}
public void PopProcessEndDialog()
{
if(_isProcessCompleted)
{
if (_trigExitMessage.Q)
{
EV.PostPopDialogMessage(EventLevel.InformationNoDelay, string.Format(Resources.Process_Exit_0RecipeCompletelyRun, Module), _processCompleteInfo);
}
}
else
{
EV.PostPopDialogMessage(EventLevel.Warning, string.Format(Resources.Process_Exit_0RecipeWasAborted, Module), _processCompleteInfo);
}
}
///
/// quiting current state
///
///
public void Exit()
{
if (DeviceModel.PressureControl != null)
{
DeviceModel.PressureControl.EnableTolerance = false;
}
var ts = DateTime.Now - RecipeStartTime;
var totalTime = string.Format("{0}:{1}:{2}", Convert.ToInt32(ts.TotalHours), ts.Minutes, ts.Seconds);
JobInfo job = Singleton.Instance.CurrentRunningJob;
_isProcessCompleted = _state == RecipeEngineState.RecipeCompleted;
if (_isProcessCompleted)
{
//正常工艺运行结束
Singleton.Instance.AddRecord(job.RecipeRunId, CarrierDataType.ProcessNormalEnd, totalTime, "recipe finished");
_processCompleteInfo = 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.PostMessage(Module, EventEnum.ProcessSuccEnd, Module, _processCompleteInfo);
_trigExitMessage.CLK = true;
job.JobResult = JobStatus.Processed;
}
else
{
//人为终止工艺运行结束
Singleton.Instance.AddRecord(job.RecipeRunId, CarrierDataType.PostProcessErrorEnd, totalTime, "recipe aborted");
string _processCompleteInfo = 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.PostMessage(Module, EventEnum.RecipeAborted, Module, _processCompleteInfo);
//TmProxy.NotifyProcessEnded(false);
//Update susceptor information
job.JobResult = JobStatus.Troubled;
}
if((int)SC.GetValue(SCName.ProcessConfig_ProcessFinishedReminderFlag) == 0)
{
PopProcessEndDialog();
}
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) ||
(DeviceModel.MfcGas4 != null && DeviceModel.MfcGas4.SetPoint > 0.001) ||
(DeviceModel.MfcGas5 != null && DeviceModel.MfcGas5.SetPoint > 0.001);
}
}
///
/// 工艺程序运行引擎放于此处
///
public Result Monitor()
{
string reason = string.Empty;
CalcEstimatedRecipeEndTime();
//检查软件互锁是否强制停止运行工艺程序
//if (!doRoutineRunning.Value)
//{
// if (!doRoutineRunning.Check(true, out reason))
// {
// EV.PostMessage(Module, EventEnum.RecipeAbortedByInterlock, Module, reason);
// return Result.FAIL; // Reactor.PostEvent(new AlarmHandleCommand("软件互锁"));
// }
//}
//工艺程序运行监控,自动打开阀门如果对应的MFC设定设置大于0
if (DeviceModel.ValveMfc1 != null && DeviceModel.MfcGas1 != null)
DeviceModel.ValveMfc1.TurnValve(DeviceModel.MfcGas1.SetPoint > 0, out reason);
if (DeviceModel.ValveMfc2 != null && DeviceModel.MfcGas2 != null)
DeviceModel.ValveMfc2.TurnValve(DeviceModel.MfcGas2.SetPoint > 0, out reason);
if (DeviceModel.ValveMfc3 != null && DeviceModel.MfcGas3 != null)
DeviceModel.ValveMfc3.TurnValve(DeviceModel.MfcGas3.SetPoint > 0, out reason);
if (DeviceModel.ValveMfc4 != null && DeviceModel.MfcGas4 != null)
DeviceModel.ValveMfc4.TurnValve(DeviceModel.MfcGas4.SetPoint > 0, out reason);
if (DeviceModel.ValveMfc5 != null && DeviceModel.MfcGas5 != null)
DeviceModel.ValveMfc5.TurnValve(DeviceModel.MfcGas5.SetPoint > 0, out reason);
if (DeviceModel.ValveProcessGasFinal != null)
{
DeviceModel.ValveProcessGasFinal.TurnValve(
(DeviceModel.MfcGas1 != null && DeviceModel.MfcGas1.SetPoint > 0)
|| (DeviceModel.MfcGas2 != null && DeviceModel.MfcGas2.SetPoint > 0)
|| (DeviceModel.MfcGas3 != null && DeviceModel.MfcGas3.SetPoint > 0)
|| (DeviceModel.MfcGas4 != null && DeviceModel.MfcGas4.SetPoint > 0)
|| (DeviceModel.MfcGas5 != null && DeviceModel.MfcGas5.SetPoint > 0), out reason);
}
//工艺程序运行引擎
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.PostMessage(Module, EventEnum.RecipeStepStart, Module, CurrentRecipeRunningName, CurStepNum + 1, _recipeStepList[CurStepNum].StepName);
//执行工艺程序命令
foreach (var recipeCmd in _recipeStepList[CurStepNum].RecipeCommands.Keys)
{
if (!DEVICE.CanDo(recipeCmd))
{
EV.PostMessage(Module, EventEnum.RecipeItemUnknow, 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]);
}
}
//if (string.IsNullOrEmpty(_recipeStepList[CurStepNum].EndBy) || String.Compare(_recipeStepList[CurStepNum].EndBy, "None", true) == 0)
{
_state = RecipeEngineState.TimeWait;
}
//else
//{
// _state = RecipeEngineState.ConditionWait;
//}
}
break;
case RecipeEngineState.TimeWait:
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.PostMessage(Module, EventEnum.RecipeStepComplete, 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
{
CurStepNum++;
}
if (CurStepNum >= _recipeStepList.Count)
{
//EV.PostMessage(Module, EventEnum.RecipeComplete, Module, RecipeName);
CurStepNum = _recipeStepList.Count - 1;
_state = RecipeEngineState.RecipeCompleted;
return Result.DONE;
}
else
{
_state = RecipeEngineState.ExecStep;
}
}
break;
case RecipeEngineState.RecipeCompleted:
{
return Result.DONE;
}
case RecipeEngineState.Error:
return Result.FAIL;
default:
break;
}
}
catch (Exception ex)
{
EV.PostMessage(Module, EventEnum.RecipeProcessException, Module, CurStepNum + 1, "语法错误");
LOG.Write(ex);
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.PostMessage(Module, EventEnum.RecipePaused, 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 = string.Format("{0}:{1}:{2}", ((int)tspan.TotalHours).ToString("00"), tspan.Minutes.ToString("00"), tspan.Seconds.ToString("00"));
curStepNode.SetAttribute("Time", timeString);
LOG.Write(string.Format("执行Resume命令,将当前第{0}步时间修改为{1}", 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.PostMessage(Module, EventEnum.RecipeResumed, 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.PostMessage(Module, EventEnum.RecipeItemUnknow, 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.PostMessage(Module, EventEnum.RecipeAborted, Module, Resources.Process_AbortRecipe_UserAbortedRecipe);
}
///
/// 跳至工艺程序下一步
///
public void SkipCurrentRecipeStep()
{
if (_state == RecipeEngineState.Paused)
{
EV.PostMessage(Module, EventEnum.ReactorCmdReject, 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 = string.Format("{0}:{1}:{2}", ((int)tspan.TotalHours).ToString("00"), tspan.Minutes.ToString("00"), tspan.Seconds.ToString("00"));
curStepNode.SetAttribute("Time", timeString);
LOG.Write(string.Format("step skipped,step {0} time changed to {1}", currentStepNo, 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.RecipeStepSkipped, 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.ReadRecipeFail, Module, CurrentRecipeRunningName);
return false;
}
else
{
string oldRecipeName = CurrentRecipeRunningName;
CurrentRecipeRunningName = string.Format("{0}-{1}-({2})", DateTime.Now.ToString("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.PostMessage(Module, EventEnum.RecipeUpdated, 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);
}
}
}
}