using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Xml; using Aitex.Core.RT.Log; using Aitex.Core.RT.RecipeCenter; using MECF.Framework.Common.Equipment; using SciChart.Core.Extensions; using Venus_Unity; namespace MECF.Framework.Common.Jobs { public enum JobRecipeType { PreLotClean, Process, WTWClean, PostLotClean } public enum SequenceLLInOutPath { AInBOut, BInAOut, DInDOut, AInAOut, BInBOut, } [Serializable] [DataContract] public class SequenceInfo { [DataMember] public List Steps { get; set; } [DataMember] public string Name { get; set; } //[DataMember] //public string PreWaferCleanRecipe { get; set; } //[DataMember] //public string PostWaferCleanRecipe { get; set; } [DataMember] public string WTWCleanRecipe { get; set; } [DataMember] public List PMs { get; set; } [DataMember] public string ThicknessType { get; set; } [DataMember] public Guid InnerId { get; set; } [DataMember] public SequenceLLInOutPath LLInOutPath { get; set; } [DataMember] public int LLDelayTime { get; set; } public SequenceInfo(string name) { Name = name; InnerId = Guid.NewGuid(); LLInOutPath = SequenceLLInOutPath.DInDOut; LLDelayTime = 0; Steps = new List(); } public string GetRecipe(ModuleName pm) { if (!ModuleHelper.IsPm(pm)) return string.Empty; string attr = $"{pm}Recipe"; foreach (var step in Steps) { if (step.StepModules.Contains(pm)) { return (string)step.StepParameter[attr]; } } return string.Empty; } public string GetPreCleanRecipe(ModuleName pm) { if (!ModuleHelper.IsPm(pm)) return string.Empty; string attr = $"{pm}PreLotClean"; foreach (var step in Steps) { if (step.StepModules.Contains(pm) && step.StepParameter.ContainsKey(attr)) { return (string)step.StepParameter[attr]; } } return string.Empty; } public string GetWTWCleanRecipe(ModuleName pm) { if (!ModuleHelper.IsPm(pm)) return string.Empty; string attr = $"{pm}WTWClean"; foreach (var step in Steps) { if (step.StepModules.Contains(pm) && step.StepParameter.ContainsKey(attr)) { return (string)step.StepParameter[attr]; } } return string.Empty; } public string GetPostCleanRecipe(ModuleName pm) { if (!ModuleHelper.IsPm(pm)) return string.Empty; string attr = $"{pm}PostLotClean"; foreach (var step in Steps) { if (step.StepModules.Contains(pm) && step.StepParameter.ContainsKey(attr)) { return (string)step.StepParameter[attr]; } } return string.Empty; } // public string GetRecipe(ModuleName pm, JobRecipeType jobRecipeType) // { // if (!ModuleHelper.IsPm(pm)) // return string.Empty; // string attr = $"{pm}Recipe"; // foreach (var step in Steps) // { // if (step.StepModules.Contains(pm)) // { // string recipeInfoString = (string)step.StepParameter[attr]; // var recipeInfoDictionary= SerializeHelper.Instance.StringToDictionary(recipeInfoString); // if (recipeInfoDictionary.Keys.Contains(jobRecipeType.ToString())) // { // return recipeInfoDictionary[jobRecipeType.ToString()]; // } // } // } // return string.Empty; // } //} } public class SequenceInfoHelper { public static SequenceInfo GetInfo(string seqFile) { SequenceInfo info = new SequenceInfo(seqFile); info.PMs = new List(); string content = RecipeFileManager.Instance.GetSequenceAndTryAppendLL(seqFile, false); if (!string.IsNullOrEmpty(content)) { try { XmlDocument dom = new XmlDocument(); dom.LoadXml(content); XmlNodeList lstStepNode = dom.SelectNodes("Aitex/TableSequenceData/Step"); if (lstStepNode == null) { //LOG.Error($"{seqFile} has no step"); return null; } var nodeData = dom.SelectSingleNode("Aitex/TableSequenceData"); if (nodeData != null) { var node = nodeData as XmlElement; info.ThicknessType = node.GetAttribute("ThicknessType"); } foreach (var nodeModelChild in lstStepNode) { XmlElement nodeStep = nodeModelChild as XmlElement; SequenceStepInfo stepInfo = new SequenceStepInfo(); foreach (XmlAttribute attr in nodeStep.Attributes) { stepInfo.StepParameter[attr.Name] = attr.Value; if (attr.Name == "Position" || attr.Name == "LLSelection" || attr.Name == "PMSelection") { if (attr.Value == "LL" || attr.Value == "PM") continue; string[] pos = attr.Value.Split(','); if (pos.Length < 1) { LOG.Write(eEvent.WARN_SEQUENCE, ModuleName.System, $"{seqFile} Position {attr.Value} can not be empty"); return null; } foreach (var po in pos) { if (po.IsEmpty()) continue; if (attr.Name == "PMSelection") { info.PMs.Add(ModuleHelper.Converter(po)); } if (po == "Cooling") { stepInfo.StepModules.AddIfNotContains(ModuleName.Cooling1); stepInfo.StepModules.AddIfNotContains(ModuleName.Cooling2); continue; } if (po == "Aligner") { stepInfo.StepModules.AddIfNotContains(ModuleName.Aligner1); stepInfo.StepModules.AddIfNotContains(ModuleName.Aligner2); continue; } ModuleName module = ModuleHelper.Converter(po); if (module == ModuleName.System) { //LOG.Error($"{seqFile} Position {po} not valid"); return null; } stepInfo.StepModules.Add(module); } continue; } if (attr.Name == "PMARecipe") { } if (attr.Name == "WTWClean") { info.WTWCleanRecipe = attr.Value; } //if (attr.Name == "PreClean") //{ // info.PreWaferCleanRecipe = attr.Value; //} //if (attr.Name == "PostClean") //{ // info.PostWaferCleanRecipe = attr.Value; //} } info.Steps.Add(stepInfo); } // Loadlock Single In Single Out property check var llSteps = info.Steps.FindAll(item => item.StepModules.Contains(ModuleName.LLA) || item.StepModules.Contains(ModuleName.LLB)); if (llSteps.Count == 2) { if (llSteps[0].StepModules.Count == 1 && llSteps[1].StepModules.Count == 1) { if (llSteps[0].StepModules[0] != llSteps[1].StepModules[0]) { info.LLInOutPath = llSteps[0].StepModules[0] == ModuleName.LLA ? SequenceLLInOutPath.AInBOut : SequenceLLInOutPath.BInAOut; } else { info.LLInOutPath = llSteps[0].StepModules[0] == ModuleName.LLA ? SequenceLLInOutPath.AInAOut : SequenceLLInOutPath.BInBOut; } } if (llSteps[1].StepParameter.ContainsKey("LLDelayTime")) { if (int.TryParse((string)llSteps[1].StepParameter["LLDelayTime"], out int delay)) { info.LLDelayTime = delay; } } } } catch (Exception ex) { LOG.WriteExeption(ex); return null; } return info; } else { return null; } } public static SequenceInfo KeplerGetInfo(string seqFile) { SequenceInfo info = new SequenceInfo(seqFile); info.PMs = new List(); string content = RecipeFileManager.Instance.GetSequenceAndTryAppendLL(seqFile, false); if (!string.IsNullOrEmpty(content)) { try { XmlDocument dom = new XmlDocument(); dom.LoadXml(content); XmlNodeList lstStepNode = dom.SelectNodes("Aitex/TableSequenceData/Step"); if (lstStepNode == null) { //LOG.Error($"{seqFile} has no step"); return null; } var nodeData = dom.SelectSingleNode("Aitex/TableSequenceData"); if (nodeData != null) { var node = nodeData as XmlElement; info.ThicknessType = node.GetAttribute("ThicknessType"); } foreach (var nodeModelChild in lstStepNode) { XmlElement nodeStep = nodeModelChild as XmlElement; SequenceStepInfo stepInfo = new SequenceStepInfo(); foreach (XmlAttribute attr in nodeStep.Attributes) { if (attr.Name == "PMARecipe" || attr.Name == "PMBRecipe" || attr.Name == "PMCRecipe" || attr.Name == "PMDRecipe") { string module = attr.Name.Substring(0, 3); var dictionarys = SerializeHelper.Instance.StringToDictionary(attr.Value); foreach (var dictionary in dictionarys) { string key; if (dictionary.Key == "Process") { key = $"{module}Recipe"; } else { key = $"{module}{dictionary.Key}"; } stepInfo.StepParameter[key] = dictionary.Value; } } else { stepInfo.StepParameter[attr.Name] = attr.Value; } if (attr.Name == "Position" || attr.Name == "LLSelection" || attr.Name == "PMSelection") { if (attr.Value == "LL" || attr.Value == "PM") continue; string[] pos = attr.Value.Split(','); if (pos.Length < 1) { LOG.Write(eEvent.WARN_SEQUENCE, ModuleName.System, $"{seqFile} Position {attr.Value} can not be empty"); return null; } foreach (var po in pos) { if (po.IsEmpty()) continue; if (attr.Name == "PMSelection") { info.PMs.Add(ModuleHelper.Converter(po)); } if (po == "Cooling") { stepInfo.StepModules.AddIfNotContains(ModuleName.Cooling1); stepInfo.StepModules.AddIfNotContains(ModuleName.Cooling2); continue; } if (po == "Aligner") { stepInfo.StepModules.AddIfNotContains(ModuleName.Aligner1); stepInfo.StepModules.AddIfNotContains(ModuleName.Aligner2); continue; } ModuleName module = ModuleHelper.Converter(po); if (module == ModuleName.System) { //LOG.Error($"{seqFile} Position {po} not valid"); return null; } stepInfo.StepModules.Add(module); } continue; } //if (attr.Name == "PMARecipe") //{ //} //if (attr.Name == "WTWClean") //{ // info.WTWCleanRecipe = attr.Value; //} //if (attr.Name == "PreClean") //{ // info.PreWaferCleanRecipe = attr.Value; //} //if (attr.Name == "PostClean") //{ // info.PostWaferCleanRecipe = attr.Value; //} } info.Steps.Add(stepInfo); } // Loadlock Single In Single Out property check var llSteps = info.Steps.FindAll(item => item.StepModules.Contains(ModuleName.LLA) || item.StepModules.Contains(ModuleName.LLB)); if (llSteps.Count == 2) { if (llSteps[0].StepModules.Count == 1 && llSteps[1].StepModules.Count == 1) { if (llSteps[0].StepModules[0] != llSteps[1].StepModules[0]) { info.LLInOutPath = llSteps[0].StepModules[0] == ModuleName.LLA ? SequenceLLInOutPath.AInBOut : SequenceLLInOutPath.BInAOut; } else { info.LLInOutPath = llSteps[0].StepModules[0] == ModuleName.LLA ? SequenceLLInOutPath.AInAOut : SequenceLLInOutPath.BInBOut; } } if (llSteps[1].StepParameter.ContainsKey("LLDelayTime")) { if (int.TryParse((string)llSteps[1].StepParameter["LLDelayTime"], out int delay)) { info.LLDelayTime = delay; } } } } catch (Exception ex) { LOG.WriteExeption(ex); return null; } return info; } else { return null; } } } }