123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- using System;
- using System.Collections.Generic;
- using System.Xml;
- using Aitex.Common.Util;
- using Aitex.Core.RT.Event;
- using Aitex.Core.RT.Log;
- using Aitex.Core.RT.SCCore;
- using JetVirgoPM.Devices;
- namespace JetVirgoPM.PMs.RecipeExecutors
- {
- 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() + @"\Recipe\JetVirgoPM\Process\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.Chamber1Temperature = rcpDataDoc.DocumentElement.HasAttribute("Chamber1Temperature") ? rcpDataDoc.DocumentElement.Attributes["Chamber1Temperature"].Value : "";
- recipeHead.Chamber2Temperature = rcpDataDoc.DocumentElement.HasAttribute("Chamber2Temperature") ? rcpDataDoc.DocumentElement.Attributes["Chamber2Temperature"].Value : "";
- recipeHead.PumpingPinState = rcpDataDoc.DocumentElement.HasAttribute("PumpingPinState") ? rcpDataDoc.DocumentElement.Attributes["PumpingPinState"].Value : "";
- recipeHead.VentingPinState = rcpDataDoc.DocumentElement.HasAttribute("VentingPinState") ? rcpDataDoc.DocumentElement.Attributes["VentingPinState"].Value : "";
- recipeHead.PinDownPressure = rcpDataDoc.DocumentElement.HasAttribute("PinDownPressure") ? rcpDataDoc.DocumentElement.Attributes["PinDownPressure"].Value : "1000";
- //For keep vacuum after idle clean
- recipeHead.NotToPurgeOrVent = rcpDataDoc.DocumentElement.HasAttribute("NotToPurgeOrVent") ? rcpDataDoc.DocumentElement.Attributes["NotToPurgeOrVent"].Value : "";
- 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 = Math.Max(double.Parse(dic["Rf1.SetPowerOnTime"]), double.Parse(dic["Rf2.SetPowerOnTime"]));
- if (recipeStep.StepTime <= 0)
- {
- LOG.Error("recipe 没有定义RF Power on的时间");
- return false;
- }
- }
- int rf1Power = (int)Convert.ToDouble(dic["Rf1.SetPower"]);
- dic.Add("Rf1.SetPowerOnOff", rf1Power > 0 ? "true" : "false");
- if (SC.GetValue<bool>($"{chamberId}.BiasRf1.EnableBiasRF"))
- {
- int rfPowerBias1 = (int)Convert.ToDouble(dic["BiasRf1.SetPower"]);
- dic.Add("BiasRf1.SetPowerOnOff", rfPowerBias1 > 0 ? "true" : "false");
- // RS232 AdTec match
- if (SC.GetValue<int>($"{chamberId}.match1.CommunicationType") == (int)CommunicationType.RS232 &&
- SC.GetValue<int>($"{chamberId}.match1.MFG") == (int)MatchMFG.AdTec)
- {
- //BiasRf1.SetMatchProcessMode
- dic["match1.SetMatchProcessMode"] = dic["BiasRf1.SetMatchProcessMode"];
- dic.Remove("BiasRf1.SetMatchProcessMode");
- dic["match1.SetMatchPositionC1"] = dic["BiasRf1.SetMatchPositionC1"];
- dic.Remove("BiasRf1.SetMatchPositionC1");
- dic["match1.SetMatchPositionC2"] = dic["BiasRf1.SetMatchPositionC2"];
- dic.Remove("BiasRf1.SetMatchPositionC2");
- }
-
- }
- else
- {
- dic.Remove("BiasRf1.SetPower");
- dic.Remove("BiasRf1.SetMatchProcessMode");
- dic.Remove("BiasRf1.SetMatchPositionC1");
- dic.Remove("BiasRf1.SetMatchPositionC2");
- }
- int rf2Power = (int)Convert.ToDouble(dic["Rf2.SetPower"]);
- dic.Add("Rf2.SetPowerOnOff", rf2Power > 0 ? "true" : "false");
- if (SC.GetValue<bool>($"{chamberId}.BiasRf2.EnableBiasRF"))
- {
- int rfPowerBias = (int)Convert.ToDouble(dic["BiasRf2.SetPower"]);
- dic.Add("BiasRf2.SetPowerOnOff", rfPowerBias > 0 ? "true" : "false");
- // RS232 AdTec match
- if (SC.GetValue<int>($"{chamberId}.match1.CommunicationType") == (int)CommunicationType.RS232 &&
- SC.GetValue<int>($"{chamberId}.match1.MFG") == (int)MatchMFG.AdTec)
- {
- dic["match2.SetMatchProcessMode"] = dic["BiasRf2.SetMatchProcessMode"];
- dic.Remove("BiasRf2.SetMatchProcessMode");
- dic["match2.SetMatchPositionC1"] = dic["BiasRf2.SetMatchPositionC1"];
- dic.Remove("BiasRf2.SetMatchPositionC1");
- dic["match2.SetMatchPositionC2"] = dic["BiasRf2.SetMatchPositionC2"];
- dic.Remove("BiasRf2.SetMatchPositionC2");
- }
- }
- else
- {
- dic.Remove("BiasRf2.SetPower");
- dic.Remove("BiasRf2.SetMatchProcessMode");
- dic.Remove("BiasRf2.SetMatchPositionC1");
- dic.Remove("BiasRf2.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", "MfcGas6", "PressureControl", "Rf1", "Rf2", "BiasRf1", "BiasRf2" };
- Dictionary<string, object[]> tolerance = new Dictionary<string, object[]>();
- foreach (var item in items)
- {
- if (item == "BiasRf1" && !SC.GetValue<bool>($"{chamberId}.BiasRf1.EnableBiasRF"))
- {
- dic.Remove(($"{item}.SoftTolerance"));
- dic.Remove(($"{item}.HardTolerance"));
- continue;
- }
- if (item == "BiasRf2" && !SC.GetValue<bool>($"{chamberId}.BiasRf2.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("Rf1.SetPowerOnTime");
- dic.Remove("Rf2.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;
- }
- 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;
- }
- }
- }
|