|
@@ -1,427 +0,0 @@
|
|
|
-using Aitex.Common.Util;
|
|
|
-using Aitex.Core.RT.Event;
|
|
|
-using Aitex.Core.RT.Log;
|
|
|
-using Aitex.Core.RT.SCCore;
|
|
|
-//using EPInterface.Datas;
|
|
|
-using System;
|
|
|
-using System.Collections.Generic;
|
|
|
-using System.Xml;
|
|
|
-
|
|
|
-namespace Venus_RT.Modules
|
|
|
-{
|
|
|
- /// <summary>
|
|
|
- /// Recipe head
|
|
|
- /// </summary>
|
|
|
- public class RecipeHead
|
|
|
- {
|
|
|
- public string RecipeVariation { get; set; }
|
|
|
- public string CreationTime { get; set; }
|
|
|
- public string LastRevisionTime { get; set; }
|
|
|
- public string CreatedBy { get; set; }
|
|
|
- public string LastModifiedBy { get; set; }
|
|
|
- public string PressureMode { get; set; }
|
|
|
- public string Description { get; set; }
|
|
|
- public string Barcode { get; set; }
|
|
|
- public string BasePressure { get; set; }
|
|
|
- public string PumpDownLimit { get; set; }
|
|
|
- //public string ElectrodeTemp { get; set; }
|
|
|
- //public string HeaterTemp { get; set; }
|
|
|
- public string PurgeActive { get; set; }
|
|
|
- public string MatchPositionC1 { get; set; }
|
|
|
- public string MatchPositionC2 { get; set; }
|
|
|
- public string SubstrateTemp { get; set; }
|
|
|
- public string PumpingPinState { get; set; }
|
|
|
- public string NotToPurgeOrVent { get; set; } //For keep vacuum after idle clean
|
|
|
- public string VentingPinState { get; set; }
|
|
|
- public string PinDownPressure { get; set; }
|
|
|
- }
|
|
|
-
|
|
|
- public class RecipeStep
|
|
|
- {
|
|
|
- public string StepName;
|
|
|
- public double StepTime;
|
|
|
- public bool IsJumpStep;
|
|
|
- public bool IsLoopStartStep;
|
|
|
- public bool IsLoopEndStep;
|
|
|
- public int LoopCount;
|
|
|
- public string EndBy;
|
|
|
- public string EndPointConfig;
|
|
|
- public bool FaultIfNoEPDTrigger;
|
|
|
-
|
|
|
- //public double EndByValue;
|
|
|
- public Dictionary<string, string> RecipeCommands = new Dictionary<string, string>();
|
|
|
- public Dictionary<string, object[]> ToleranceCommands = new Dictionary<string, object[]>();
|
|
|
- }
|
|
|
-
|
|
|
- public class Recipe
|
|
|
- {
|
|
|
- /// <summary>
|
|
|
- /// 当前Recipe Run 记录对应的Guid
|
|
|
- /// 每个Recipe Run 都对应有一个唯一的Guid
|
|
|
- /// </summary>
|
|
|
- public static Guid CurrentRecipeRunGuid;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// 解析工艺程序文件
|
|
|
- /// </summary>
|
|
|
- /// <param name="recipeName">工艺程序名</param>
|
|
|
- /// <param name="xmlRecipeData">xml格式的工艺数据内容</param>
|
|
|
- /// <param name="recipeData">返回解析的工艺数据变量</param>
|
|
|
- /// <returns>True:解析成功 | False:解析失败</returns>
|
|
|
- public static bool Parse(string chamberId, string recipe, out RecipeHead recipeHead, out List<RecipeStep> recipeData)
|
|
|
- {
|
|
|
- recipeHead = new RecipeHead();
|
|
|
- recipeData = new List<RecipeStep>();
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- //获取工艺程序文件中允许的命令字符串列表
|
|
|
- //目的:如果工艺程序文件中含有规定之外的命令,则被禁止执行
|
|
|
- HashSet<string> recipeAllowedCommands = new HashSet<string>();
|
|
|
- XmlDocument rcpFormatDoc = new XmlDocument();
|
|
|
-
|
|
|
- string recipeSchema = PathManager.GetCfgDir() + "RecipeFormat.xml";
|
|
|
- rcpFormatDoc.Load(recipeSchema);
|
|
|
-
|
|
|
- XmlNodeList rcpItemNodeList = rcpFormatDoc.SelectNodes("/Aitex/TableRecipeFormat/Catalog/Group/Step");
|
|
|
- foreach (XmlElement item in rcpItemNodeList)
|
|
|
- recipeAllowedCommands.Add(item.Attributes["ControlName"].Value);
|
|
|
-
|
|
|
- //获取工艺程序文件中所有步的内容
|
|
|
- XmlDocument rcpDataDoc = new XmlDocument();
|
|
|
- rcpDataDoc.LoadXml(recipe);
|
|
|
-
|
|
|
- recipeHead.PressureMode = rcpDataDoc.DocumentElement.HasAttribute("PressureMode") ? rcpDataDoc.DocumentElement.Attributes["PressureMode"].Value : "";
|
|
|
-
|
|
|
- recipeHead.BasePressure = rcpDataDoc.DocumentElement.HasAttribute("BasePressure") ? rcpDataDoc.DocumentElement.Attributes["BasePressure"].Value : "";
|
|
|
-
|
|
|
- recipeHead.PumpDownLimit = rcpDataDoc.DocumentElement.HasAttribute("PumpDownLimit") ? rcpDataDoc.DocumentElement.Attributes["PumpDownLimit"].Value : "";
|
|
|
-
|
|
|
- recipeHead.PurgeActive = rcpDataDoc.DocumentElement.HasAttribute("PurgeActive") ? rcpDataDoc.DocumentElement.Attributes["PurgeActive"].Value : "";
|
|
|
-
|
|
|
- recipeHead.MatchPositionC1 = rcpDataDoc.DocumentElement.HasAttribute("MatchPositionC1") ? rcpDataDoc.DocumentElement.Attributes["MatchPositionC1"].Value : "";
|
|
|
-
|
|
|
- recipeHead.MatchPositionC2 = rcpDataDoc.DocumentElement.HasAttribute("MatchPositionC2") ? rcpDataDoc.DocumentElement.Attributes["MatchPositionC2"].Value : "";
|
|
|
-
|
|
|
- recipeHead.Barcode = rcpDataDoc.DocumentElement.HasAttribute("Barcode") ? rcpDataDoc.DocumentElement.Attributes["Barcode"].Value : "";
|
|
|
-
|
|
|
- recipeHead.SubstrateTemp = rcpDataDoc.DocumentElement.HasAttribute("SubstrateTemp") ? rcpDataDoc.DocumentElement.Attributes["SubstrateTemp"].Value : "";
|
|
|
-
|
|
|
- recipeHead.PumpingPinState = rcpDataDoc.DocumentElement.HasAttribute("PumpingPinState") ? rcpDataDoc.DocumentElement.Attributes["PumpingPinState"].Value : "Down";
|
|
|
-
|
|
|
- //For keep vacuum after idle clean
|
|
|
- recipeHead.NotToPurgeOrVent = rcpDataDoc.DocumentElement.HasAttribute("NotToPurgeOrVent") ? rcpDataDoc.DocumentElement.Attributes["NotToPurgeOrVent"].Value : "";
|
|
|
-
|
|
|
- recipeHead.VentingPinState = rcpDataDoc.DocumentElement.HasAttribute("VentingPinState") ? rcpDataDoc.DocumentElement.Attributes["VentingPinState"].Value : "Down";
|
|
|
-
|
|
|
- recipeHead.PinDownPressure = rcpDataDoc.DocumentElement.HasAttribute("PinDownPressure") ? rcpDataDoc.DocumentElement.Attributes["PinDownPressure"].Value : "1000";
|
|
|
-
|
|
|
- XmlNodeList stepNodeList = rcpDataDoc.SelectNodes("/TableRecipeData/Step");
|
|
|
- for (int i = 0; i < stepNodeList.Count; i++)
|
|
|
- {
|
|
|
- var recipeStep = new RecipeStep();
|
|
|
- recipeData.Add(recipeStep);
|
|
|
-
|
|
|
- XmlElement stepNode = stepNodeList[i] as XmlElement;
|
|
|
- Dictionary<string, string> dic = new Dictionary<string, string>();
|
|
|
-
|
|
|
- //遍历Step节点
|
|
|
- foreach (XmlAttribute att in stepNode.Attributes)
|
|
|
- {
|
|
|
- if (recipeAllowedCommands.Contains(att.Name))
|
|
|
- {
|
|
|
- dic.Add(att.Name, att.Value);
|
|
|
- }
|
|
|
- }
|
|
|
- //遍历Step子节点中所有的attribute属性节点
|
|
|
- foreach (XmlElement subStepNode in stepNode.ChildNodes)
|
|
|
- {
|
|
|
- foreach (XmlAttribute att in subStepNode.Attributes)
|
|
|
- {
|
|
|
- if (recipeAllowedCommands.Contains(att.Name))
|
|
|
- {
|
|
|
- dic.Add(att.Name, att.Value);
|
|
|
- }
|
|
|
- }
|
|
|
- //遍历Step子节点的子节点中所有的attribute属性节点
|
|
|
- foreach (XmlElement subsubStepNode in subStepNode.ChildNodes)
|
|
|
- {
|
|
|
- foreach (XmlAttribute att in subsubStepNode.Attributes)
|
|
|
- {
|
|
|
- if (recipeAllowedCommands.Contains(att.Name))
|
|
|
- {
|
|
|
- dic.Add(att.Name, att.Value);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- recipeStep.IsJumpStep = true;//!Convert.ToBoolean(dic["Ramp"]);
|
|
|
- recipeStep.StepName = dic["Name"];
|
|
|
- recipeStep.StepTime = double.Parse(dic["Time"]);
|
|
|
- string loopStr = dic["Loop"];
|
|
|
- recipeStep.IsLoopStartStep = System.Text.RegularExpressions.Regex.Match(loopStr, @"Loop\x20\d+\s*$").Success;
|
|
|
- recipeStep.IsLoopEndStep = System.Text.RegularExpressions.Regex.Match(loopStr, @"Loop End$").Success;
|
|
|
- if (recipeStep.IsLoopStartStep)
|
|
|
- recipeStep.LoopCount = Convert.ToInt32(loopStr.Replace("Loop", string.Empty));
|
|
|
- else
|
|
|
- recipeStep.LoopCount = 0;
|
|
|
- //recipeStep.EndByValue = Convert.ToDouble(dic["EndValue"]);
|
|
|
- recipeStep.EndBy = dic["EndBy"];
|
|
|
-
|
|
|
- if (recipeStep.EndBy == "EndByRfTime")
|
|
|
- {
|
|
|
- recipeStep.StepTime = double.Parse(dic["Rf.SetPowerOnTime"]);
|
|
|
-
|
|
|
- if (recipeStep.StepTime <= 0)
|
|
|
- {
|
|
|
- //LOG.Error("recipe 没有定义RF Power on的时间");
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- int rfPower = (int)Convert.ToDouble(dic["Rf.SetPower"]);
|
|
|
- dic.Add("Rf.SetPowerOnOff", rfPower > 0 ? "true" : "false");
|
|
|
- if (SC.GetValue<bool>($"{chamberId}.BiasRf.EnableBiasRF"))
|
|
|
- {
|
|
|
- int rfPowerBias = (int)Convert.ToDouble(dic["BiasRf.SetPower"]);
|
|
|
- dic.Add("BiasRf.SetPowerOnOff", rfPowerBias > 0 ? "true" : "false");
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- dic.Remove("BiasRf.SetPower");
|
|
|
- dic.Remove("BiasRf.SetMatchProcessMode");
|
|
|
- dic.Remove("BiasRf.SetMatchPositionC1");
|
|
|
- dic.Remove("BiasRf.SetMatchPositionC2");
|
|
|
- }
|
|
|
-
|
|
|
- bool epdInstalled = SC.ContainsItem("System.SetUp.EPDInstalled") && SC.GetValue<bool>($"System.SetUp.EPDInstalled");
|
|
|
-
|
|
|
- if (!epdInstalled)
|
|
|
- {
|
|
|
- if (dic.ContainsKey("EPD.SetConfig"))
|
|
|
- dic.Remove("EPD.SetConfig");
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- recipeStep.EndPointConfig = dic.ContainsKey("EPD.SetConfig") ? dic["EPD.SetConfig"] : null;
|
|
|
-
|
|
|
- if (string.IsNullOrEmpty(recipeStep.EndPointConfig))
|
|
|
- {
|
|
|
- if (recipeStep.EndBy == "EndByEndPoint")
|
|
|
- {
|
|
|
- EV.PostWarningLog("System", "EndPoint is empty");
|
|
|
- return false;
|
|
|
- }
|
|
|
- recipeStep.EndPointConfig = SC.GetStringValue("System.EndPoint.EndPointDefaultValue");
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- //if (!ParseEPD(recipeStep.EndPointConfig, out EPDConfig config))
|
|
|
- //{
|
|
|
- // EV.PostWarningLog("System", "EndPoint config is not valid");
|
|
|
- // return false;
|
|
|
- //}
|
|
|
-
|
|
|
- //recipeStep.FaultIfNoEPDTrigger = config.FaultIfNoEPDTrigger;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //tolerance
|
|
|
- List<string> items = new List<string>() { "MfcGas1", "MfcGas2", "MfcGas3", "MfcGas4", "MfcGas5", "PressureControl", "Rf", "BiasRf" };
|
|
|
- Dictionary<string, object[]> tolerance = new Dictionary<string, object[]>();
|
|
|
- foreach (var item in items)
|
|
|
- {
|
|
|
- if (item == "BiasRf" && !SC.GetValue<bool>($"{chamberId}.BiasRf.EnableBiasRF"))
|
|
|
- {
|
|
|
- dic.Remove(($"{item}.SoftTolerance"));
|
|
|
- dic.Remove(($"{item}.HardTolerance"));
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- var time = SC.GetValue<int>($"{chamberId}.RecipeToleranceIgnoreTime");
|
|
|
- var warning = dic.ContainsKey($"{item}.SoftTolerance") ? dic[$"{item}.SoftTolerance"] : "0";
|
|
|
- var alarm = dic.ContainsKey($"{item}.HardTolerance") ? dic[$"{item}.HardTolerance"] : "0";
|
|
|
- tolerance[$"{item}.SetRecipeTolerance"] = new object[]
|
|
|
- {
|
|
|
- time, warning, alarm
|
|
|
- };
|
|
|
-
|
|
|
- dic.Remove(($"{item}.SoftTolerance"));
|
|
|
- dic.Remove(($"{item}.HardTolerance"));
|
|
|
- }
|
|
|
-
|
|
|
- recipeStep.ToleranceCommands = tolerance;
|
|
|
-
|
|
|
- //dic.Remove("Ramp");
|
|
|
- dic.Remove("StepNo");
|
|
|
- dic.Remove("Name");
|
|
|
- dic.Remove("Loop");
|
|
|
- dic.Remove("Time");
|
|
|
- dic.Remove("EndBy");
|
|
|
- //dic.Remove("EndValue");
|
|
|
- dic.Remove("Rf.SetPowerOnTime");
|
|
|
-
|
|
|
- foreach (string key in dic.Keys)
|
|
|
- recipeStep.RecipeCommands.Add(key, dic[key]);
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- //LOG.Write(ex);
|
|
|
- return false;
|
|
|
- }
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- //private static bool ParseEPD(string config, out EPDConfig epdConfig)
|
|
|
- //{
|
|
|
- // epdConfig = new EPDConfig();
|
|
|
-
|
|
|
- // try
|
|
|
- // {
|
|
|
- // epdConfig.nParameterCount = 1;
|
|
|
-
|
|
|
- // string[] items = config.Split(';');
|
|
|
- // foreach (var item in items)
|
|
|
- // {
|
|
|
- // if (string.IsNullOrEmpty(item))
|
|
|
- // continue;
|
|
|
-
|
|
|
- // string[] pairs = item.Split('=');
|
|
|
- // if (pairs.Length != 2)
|
|
|
- // continue;
|
|
|
-
|
|
|
- // switch (pairs[0])
|
|
|
- // {
|
|
|
- // case "ExposureTime":
|
|
|
- // epdConfig.Columns[0].nCCDExposureTime = int.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "WaveLengthA":
|
|
|
- // epdConfig.Columns[0].nWaveLength[0] = ushort.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "BinningA":
|
|
|
- // epdConfig.Columns[0].nBinning[0] = ushort.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "WaveLengthB":
|
|
|
- // epdConfig.Columns[0].nWaveLength[1] = ushort.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "BinningB":
|
|
|
- // epdConfig.Columns[0].nBinning[1] = ushort.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "WaveLengthC":
|
|
|
- // epdConfig.Columns[0].nWaveLength[2] = ushort.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "BinningC":
|
|
|
- // epdConfig.Columns[0].nBinning[2] = ushort.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "WaveLengthD":
|
|
|
- // epdConfig.Columns[0].nWaveLength[3] = ushort.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "BinningD":
|
|
|
- // epdConfig.Columns[0].nBinning[3] = ushort.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
-
|
|
|
- // case "Fd":
|
|
|
- // epdConfig.Columns[0].cFunc = pairs[1];
|
|
|
- // break;
|
|
|
- // case "PrefilterTime":
|
|
|
- // epdConfig.Columns[0].nPreFilterTime = int.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "PostfilterTime":
|
|
|
- // epdConfig.Columns[0].nPostFilterTime = int.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "AlgorithmType":
|
|
|
- // epdConfig.Columns[0].algorithmType = MapType(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "Criteria":
|
|
|
- // epdConfig.Columns[0].nCriteria = float.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
-
|
|
|
- // case "DelayTime":
|
|
|
- // epdConfig.Columns[0].nDelayTime = int.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "ValidationTime":
|
|
|
- // epdConfig.Columns[0].nValidationTime = int.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "ValidationValue":
|
|
|
- // epdConfig.Columns[0].nValidationValue = int.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "TimeWindow":
|
|
|
- // epdConfig.Columns[0].nTimeWindow = int.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "MinimalTime":
|
|
|
- // epdConfig.Columns[0].nMinimalTime = int.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "PostponeTime":
|
|
|
- // epdConfig.Columns[0].nPostponeTime = int.Parse(pairs[1]);
|
|
|
- // break;
|
|
|
-
|
|
|
- // case "Control":
|
|
|
- // epdConfig.Columns[0].bControl = Convert.ToBoolean(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "Normalization":
|
|
|
- // epdConfig.Columns[0].bNormalization = Convert.ToBoolean(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "EnablePostponePercent":
|
|
|
- // epdConfig.Columns[0].bPostponePercent = Convert.ToBoolean(pairs[1]);
|
|
|
- // break;
|
|
|
- // case "EnableCriterialPercent":
|
|
|
- // epdConfig.Columns[0].bCriteriaPercent = Convert.ToBoolean(pairs[1]);
|
|
|
- // break;
|
|
|
-
|
|
|
-
|
|
|
- // case "EnableEventTrigger":
|
|
|
- // epdConfig.Columns[0].bEvtTrigger = Convert.ToBoolean(pairs[1]);
|
|
|
- // break;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- // case "IsFaultIfNoTrigger":
|
|
|
- // epdConfig.FaultIfNoEPDTrigger = Convert.ToBoolean(pairs[1]);
|
|
|
- // break;
|
|
|
-
|
|
|
- // }
|
|
|
- // }
|
|
|
-
|
|
|
- // return true;
|
|
|
- // }
|
|
|
- // catch (Exception ex)
|
|
|
- // {
|
|
|
- // LOG.Write(ex);
|
|
|
- // EV.PostMessage("System", EventEnum.DefaultAlarm, "EPD config input not valid, ", ex.Message);
|
|
|
- // return false;
|
|
|
- // }
|
|
|
-
|
|
|
-
|
|
|
- //}
|
|
|
-
|
|
|
-
|
|
|
- //private static AlgorithmType MapType(string type)
|
|
|
- //{
|
|
|
- // switch (type)
|
|
|
- // {
|
|
|
- // case "Unknown": return AlgorithmType.ALG_NONE;
|
|
|
- // case "Above_ABS_Value": return AlgorithmType.ALG_RISE_VALUE;
|
|
|
- // case "Below_ABS_Value": return AlgorithmType.ALG_FALL_VALUE;
|
|
|
- // case "Drop_Percent": return AlgorithmType.ALG_FALL_PERCENT;
|
|
|
- // case "Up_Percent": return AlgorithmType.ALG_RISE_PERCENT;
|
|
|
- // case "Range_In": return AlgorithmType.ALG_RANGE_IN;
|
|
|
- // case "Gradient": return AlgorithmType.ALG_GRADIENT;
|
|
|
- // case "Peek": return AlgorithmType.ALG_PEAK;
|
|
|
- // case "Valley": return AlgorithmType.ALG_VALLEY;
|
|
|
- // case "Min_Drop_Percent": return AlgorithmType.ALG_MIN_FALL_PERCENT;
|
|
|
- // case "Min_Up_Percent": return AlgorithmType.ALG_MIN_RISE_PERCENT;
|
|
|
- // case "Max_Drop_Percent": return AlgorithmType.ALG_MAX_FALL_PERCENT;
|
|
|
- // case "Max_Up_Percent": return AlgorithmType.ALG_MAX_RISE_PERCENT;
|
|
|
- // case "Rise_Fall": return AlgorithmType.ALG_RISE_FALL;
|
|
|
- // case "Fall_Rise": return AlgorithmType.ALG_FALL_RISE;
|
|
|
- // }
|
|
|
-
|
|
|
- // return AlgorithmType.ALG_NONE;
|
|
|
- //}
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-}
|