using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms.VisualStyles; using System.Xml.Schema; using System.Xml; using System.IO; using Aitex.Core.RT.Log; using System.Text.RegularExpressions; using Aitex.Common.Util; using Aitex.Core.RT.Event; using Aitex.Core.Util; using Aitex.Core.Utilities; using Aitex.Core.WCF; using MECF.Framework.Common.OperationCenter; using MECF.Framework.Common.Properties; using MECF.Framework.Common.RecipeCenter; using System.Collections.ObjectModel; using Aitex.Core.RT.SCCore; using MECF.Framework.Common.DataCenter; using Microsoft.VisualBasic.FileIO; using MECF.Framework.Common.CommonData; namespace Aitex.Core.RT.RecipeCenter { public class RecipeFileManager : Singleton { //sequence文件 统一放在 Recipes/Sequence 文件夹下面 public const string SequenceFolder = "Sequence"; public const string SourceModule = "Recipe"; public const string WaferFlowFolder = "WaferFlow"; string _chamberId; private bool _recipeIsValid; private List _validationErrors = new List(); private List _validationWarnings = new List(); private Dictionary> _recipeItems; IRecipeFileContext _rcpContext; private ISequenceFileContext _seqContext; public RecipeFileManager() { _chamberId = SC.GetStringValue("System.Recipe.RecipeChamberType"); if (_chamberId == null) _chamberId = "Track"; } public void Initialize(IRecipeFileContext context) { Initialize(context, null, true); } public void Initialize(IRecipeFileContext context, bool enableService) { Initialize(context, null, enableService); } public void Initialize(IRecipeFileContext rcpContext, ISequenceFileContext seqContext, bool enableService) { _rcpContext = rcpContext == null ? new DefaultRecipeFileContext() : rcpContext; _seqContext = seqContext == null ? new DefaultSequenceFileContext() : seqContext; CultureSupported.UpdateCoreCultureResource(CultureSupported.English); if (enableService) { Singleton.Instance.Initialize(new Type[] { typeof(RecipeService) }); } var dir = string.Format("{0}{1}\\", PathManager.GetRecipeDir(), SequenceFolder); DirectoryInfo di = new DirectoryInfo(dir); if (!di.Exists) { di.Create(); } } private void ValidationEventHandler(object sender, ValidationEventArgs e) { switch (e.Severity) { case XmlSeverityType.Error: _validationErrors.Add(e.Message); _recipeIsValid = false; break; case XmlSeverityType.Warning: _validationWarnings.Add(e.Message); break; } } /// /// XML schema checking /// /// /// /// /// /// public bool ValidateRecipe(string chamberId, string recipeName, string recipeContent, out List reason) { try { XmlDocument document = new XmlDocument(); document.LoadXml(recipeContent); MemoryStream schemaStream = new MemoryStream(ASCIIEncoding.ASCII.GetBytes(GetRecipeSchema(chamberId))); XmlReader xmlSchemaReader = XmlReader.Create(schemaStream); XmlSchema schema1 = XmlSchema.Read(xmlSchemaReader, ValidationEventHandler); document.Schemas.Add(schema1); document.LoadXml(recipeContent); ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler); _recipeIsValid = true; _validationErrors = new List(); _validationWarnings = new List(); // Validates recipe. document.Validate(eventHandler); } catch (Exception ex) { LOG.Write(ex.Message); _recipeIsValid = false; } if (!_recipeIsValid && _validationErrors.Count == 0) { _validationErrors.Add(Resources.RecipeFileManager_ValidateRecipe_XMLSchemaValidateFailed); } reason = _validationErrors; return _recipeIsValid; } /// /// 检查变量ramp rate /// /// /// /// /// /// /// /// False:check ok, True: check failed public bool CheckRampRate(int stepNo, string rampEnable, string varName, string rampTime, double maxRampUpRate, double maxRampDownRate) { try { if (stepNo <= 0) return false; if (varName == "AZone.Setpoint" || varName == "BZone.Setpoint" || varName == "CZone.Setpoint" || varName == "DZone.Setpoint") { string curStepHeatCtrlMode = _recipeItems[stepNo]["Heater.Mode"]; string lastStepHeatCtrlMode = _recipeItems[stepNo - 1]["Heater.Mode"]; if (curStepHeatCtrlMode != lastStepHeatCtrlMode) return false; } bool isRampEnable = bool.Parse(rampEnable); string[] timeStr = rampTime.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); double hh = 0; double mm = 0; double ss = 0; if (timeStr.Length == 3) { hh = double.Parse(timeStr[0]); mm = double.Parse(timeStr[1]); ss = double.Parse(timeStr[2]); } else if (timeStr.Length == 2) { mm = double.Parse(timeStr[0]); ss = double.Parse(timeStr[1]); } else if (timeStr.Length == 1) { ss = double.Parse(timeStr[0]); } double totalTimeSec = hh * 3600 + mm * 60 + ss; double diff = double.Parse(_recipeItems[stepNo][varName]) - double.Parse(_recipeItems[stepNo - 1][varName]); if (!isRampEnable || totalTimeSec <= 0) { //jump if (diff != 0) return true; return false; } else { double rampRate = diff / totalTimeSec; if ((rampRate > 0 && rampRate >= maxRampUpRate) || (rampRate < 0 && rampRate <= -maxRampDownRate)) return true; return false; } } catch (Exception ex) { LOG.Write(ex.Message); return true; } } public bool GetRecipeChecked(string chamberId, string recipeName) { string chamberType = chamberId.Split('\\')[0]; string processType = chamberId.Split('\\')[1]; string recipeContent = LoadRecipe(chamberId, recipeName, false); var xmlRecipe = new XmlDocument(); try { if (string.IsNullOrEmpty(recipeContent)) throw new Exception("invalid recipe file."); xmlRecipe.LoadXml(recipeContent); XmlNodeList nodeSteps = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; foreach (var item in nodeSteps) { XmlElement step = item as XmlElement; string strModuleName = step.Attributes["ModuleName"]?.Value; if (string.IsNullOrEmpty(strModuleName)) continue; if (!string.IsNullOrEmpty(strModuleName)) { string[] temp = strModuleName.Split(',')[0].Split(' '); if (temp.Length > 1) strModuleName = temp[1]; } else continue; if (ovenModuleName.Contains(strModuleName)) strModuleName = "Oven"; string linkRecipeName = step.Attributes["RecipeName"]?.Value; if (string.IsNullOrEmpty(linkRecipeName)) continue; string[] subRecipeNames = linkRecipeName.Split(','); foreach (var subItem in subRecipeNames) { string subRecipeName = string.Empty; string[] subRecipeNameStrings = subItem.Split(':'); if (subRecipeNameStrings.Length > 1) { subRecipeName = subRecipeNameStrings[1]; } else { subRecipeName = subRecipeNameStrings[0]; } if (!GetRecipeChecked($"{_chamberId}\\{strModuleName}", subRecipeName)) { return false; } } } //check system reicpe string strSystemReicpeName = nodeConfig.Attributes["SystemRecipe"]?.Value; if (!string.IsNullOrEmpty(strSystemReicpeName)) { if (!GetRecipeChecked($"{_chamberId}\\System", strSystemReicpeName)) { return false; } } //check pump recipe string pumpRecipeName = nodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(pumpRecipeName)) { if (!GetRecipeChecked($"{_chamberId}\\Pump", pumpRecipeName)) { return false; } } XmlElement nodeData = xmlRecipe.SelectSingleNode($"Aitex/TableRecipeData") as XmlElement; string checkResult = nodeData.Attributes["CheckResult"].Value; if (string.IsNullOrEmpty(checkResult)) return false; else return true; } catch (Exception ex) { LOG.Write(ex); return false; } } public List GetRecipeByPathFileNodes(string prefix, string recipeName) { List recipeFileNodes = new List(); return recipeFileNodes; } public string LoadRecipeByFullPath(string fullPath) { string rcp = string.Empty; try { //_IsURecipe = false; using (StreamReader fs = new StreamReader(fullPath)) { rcp = fs.ReadToEnd(); fs.Close(); } } catch (Exception ex) { try { using (StreamReader fs = new StreamReader(fullPath)) { rcp = fs.ReadToEnd(); fs.Close(); //_IsURecipe = true; } } catch { LOG.Write(ex, $"load recipe file failed, {fullPath}"); rcp = string.Empty; }; } return rcp; } /// /// Check recipe content /// /// /// /// /// public bool CheckRecipe(string chamberId, string recipeName, out List reasons) { reasons = new List(); string chamberType = chamberId.Split('\\')[0]; string processType = chamberId.Split('\\')[1]; string recipeContent = LoadRecipe(chamberId, recipeName, false); var xmlRecipe = new XmlDocument(); try { if (string.IsNullOrEmpty(recipeContent)) throw new Exception("invalid recipe file."); xmlRecipe.LoadXml(recipeContent); XmlNodeList nodeSteps = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; switch (processType) { case "WaferFlow": CheckWaferFlowRecipe(nodeConfig, nodeSteps, out reasons); break; case "COT": CheckSpinRecipe(nodeConfig, nodeSteps, true, out reasons); break; case "DEV": CheckSpinRecipe(nodeConfig, nodeSteps, false, out reasons); break; case "ADH": CheckADHRecipe(nodeSteps, out reasons); break; case "Oven": CheckOvenRecipe(nodeSteps, out reasons); break; case "Dummy": CheckDummyRecipe(nodeSteps, out reasons); break; } } catch (Exception ex) { reasons.Add(ex.Message); LOG.Write(ex); return false; } XmlElement nodeData = xmlRecipe.SelectSingleNode($"Aitex/TableRecipeData") as XmlElement; bool bResult = reasons.Count == 0; if (bResult) { nodeData.SetAttribute("CheckResult", "Correct"); } else { nodeData.SetAttribute("CheckResult", "Error"); } SaveRecipe(chamberId, recipeName, xmlRecipe.OuterXml, false, false); return bResult; } /// /// Check recipe content /// /// /// /// /// public bool CheckRestoreRecipe(string chamberId, string recipeName, out List reasons) { reasons = new List(); string chamberType = chamberId.Split('\\')[0]; string processType = chamberId.Split('\\')[1]; string recipeContent = LoadRestoreRecipe(chamberId, recipeName, false); var xmlRecipe = new XmlDocument(); try { if (string.IsNullOrEmpty(recipeContent)) throw new Exception("invalid recipe file."); xmlRecipe.LoadXml(recipeContent); XmlNodeList nodeSteps = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; switch (processType) { case "WaferFlow": CheckWaferFlowRecipe(nodeConfig, nodeSteps, out reasons); break; case "COT": CheckSpinRecipe(nodeConfig, nodeSteps, true, out reasons); break; case "DEV": CheckSpinRecipe(nodeConfig, nodeSteps, false, out reasons); break; case "ADH": CheckADHRecipe(nodeSteps, out reasons); break; case "Oven": CheckOvenRecipe(nodeSteps, out reasons); break; } } catch (Exception ex) { reasons.Add(ex.Message); LOG.Write(ex); return false; } XmlElement nodeData = xmlRecipe.SelectSingleNode($"Aitex/TableRecipeData") as XmlElement; bool bResult = reasons.Count == 0; if (bResult) { nodeData.SetAttribute("CheckResult", "Correct"); } else { nodeData.SetAttribute("CheckResult", "Error"); } SaveRestoreRecipe(chamberId, recipeName, xmlRecipe.OuterXml, false, false); return bResult; } void CheckWaferFlowRecipe(XmlNode nodeConfig, XmlNodeList nodeSteps, out List reasons) { reasons = new List(); if (nodeSteps.Count <= 0) { reasons.Add("steps count is 0"); return; } if (nodeSteps.Count < 5) { reasons.Add("steps count is less than 5"); return; } int beginStepIndex = 0; int endStepIndex = 1; for (int i = 0; i < nodeSteps.Count; i++) { if (nodeSteps[i].Attributes["ModuleName"].Value.Contains("End UNC")) { int.TryParse(nodeSteps[i].Attributes["StepNo"].Value, out endStepIndex); break; } } endStepIndex--; if (endStepIndex <= 0) { reasons.Add($"Current recipe muste contains end step"); return; } string key = "System.SetUp.BlockNumber"; string numberVlaue = SC.GetStringValue(key); var numberOfBlock = int.Parse((numberVlaue.Replace("Block", ""))); for (int i = beginStepIndex; i <= endStepIndex; i++) { int stepNo = i + 1; string strModuleName = nodeSteps[i].Attributes["ModuleName"].Value; if (!string.IsNullOrEmpty(strModuleName)) { //check module name is changed var modules = strModuleName.Split(','); strModuleName = modules[0].Split(' ')[1]; foreach (var item in modules) { string blockIndex = item.Split(' ')[0].Split('-')[0]; if (blockIndex == "1") continue; if (numberOfBlock == 3 && blockIndex == "3") blockIndex = "4"; string moduleIndex = item.Split(' ')[0].Split('-')[1]; string moduleKey = $"System.SetUp.Block{blockIndex}.{moduleIndex}.Name"; var value = SC.GetStringValue(moduleKey); if (strModuleName != value?.ToString()) { reasons.Add($"Step{stepNo} module name has been changed to {value}"); } } } else { reasons.Add($"Step{stepNo} module name is empty"); return; } if (i == 0)//check step1 { string moduleName = "UNC"; if (!strModuleName.Equals(moduleName)) { reasons.Add($"Step{stepNo} module muste be {moduleName}"); } continue; } if (i == 1)//check step2 { string moduleName = "TRS,TCP"; if (!moduleName.Contains(strModuleName)) { reasons.Add($"Step{stepNo} module muste be {moduleName} module"); } } if (i == endStepIndex - 1)//check last second step { string moduleName = "TRS,TCP"; if (!moduleName.Contains(strModuleName)) { reasons.Add($"Step{stepNo} module muste be {moduleName} module"); } if (strModuleName == nodeSteps[1].Attributes["ModuleName"].Value) { reasons.Add($"Step{stepNo} module muste be different with step1 module"); } } if (i == endStepIndex)//check last step { string moduleName = "UNC"; if (!strModuleName.Equals(moduleName)) { reasons.Add($"Step{stepNo} module muste be {moduleName}"); } continue; } //check linked recipe string unCheckModuleName = "SHU,TRS,SUB,EIS"; if (!unCheckModuleName.Contains(strModuleName)) { string ovenModuleName = "CPL,HHP,LHP,CHP,TCP"; if (ovenModuleName.Contains(strModuleName)) strModuleName = "Oven"; string linkRecipeName = nodeSteps[i].Attributes["RecipeName"].Value; if (string.IsNullOrEmpty(linkRecipeName)) { reasons.Add($"Step{stepNo} link recipe is empty."); } else { string[] subRecipeNames = linkRecipeName.Split(','); foreach (var item in subRecipeNames) { string subRecipeName = string.Empty; string[] subRecipeNameStrings = item.Split(':'); if (subRecipeNameStrings.Length > 1) { subRecipeName = subRecipeNameStrings[1]; } else { subRecipeName = subRecipeNameStrings[0]; } if (!CheckRecipe($"{_chamberId}\\{strModuleName}", subRecipeName, out List subReasons)) { reasons.Add($"Step{stepNo} linked recipe check fail."); } } } } } //check system reicpe string strSystemReicpeName = nodeConfig.Attributes["SystemRecipe"]?.Value; if (!string.IsNullOrEmpty(strSystemReicpeName)) { if (!CheckRecipe($"{_chamberId}\\System", strSystemReicpeName, out List subReasons)) { reasons.Add($"Linked system recipe check fail."); } } else { reasons.Add($"Must link system recipe."); } } void CheckSpinRecipe(XmlNode nodeConfig, XmlNodeList nodeSteps, bool checkPumpRecipe, out List reasons) { reasons = new List(); if (nodeSteps.Count <= 0) { reasons.Add("steps count is 0."); return; } List loopStartStepsNo = new List(); List loopEndStepsNo = new List(); bool hasDispense = false; List arm1HasMove = new List(); List arm2HasMove = new List(); for (int i = 0; i < nodeSteps.Count; i++) { int stepNo = i + 1; if (nodeSteps[i].Attributes["Loop"].Value.Contains("Start")) { loopStartStepsNo.Add(stepNo); } if (nodeSteps[i].Attributes["Loop"].Value.Contains("End")) { loopEndStepsNo.Add(stepNo); } string strDispense = nodeSteps[i].Attributes["Dispense"].Value; if (strDispense.Contains("Resist")) { hasDispense = true; } //check dispens if (!string.IsNullOrEmpty(strDispense)) { bool bDispenseHasError = false; string[] strDispenseValues = strDispense.Split(','); string strFirstDispenseValue = strDispenseValues[0]; foreach (var item in strDispenseValues) { if (strFirstDispenseValue.Split(' ')[0] != item.Split(' ')[0]) bDispenseHasError = true; } if (bDispenseHasError) reasons.Add($"Step{stepNo} dispense must select same module."); } if (i > 0) { string arm1CurrentPosition = nodeSteps[i].Attributes["Arm1"].Value.Split(',')[2].Split(':')[1]; string arm1PreviousPosition = nodeSteps[i - 1].Attributes["Arm1"].Value.Split(',')[2].Split(':')[1]; if (!string.IsNullOrEmpty(arm1CurrentPosition)) { if (arm1CurrentPosition.Equals(arm1PreviousPosition)) arm1HasMove.Add(false); else arm1HasMove.Add(true); } string arm2CurrentPosition = nodeSteps[i].Attributes["Arm2"].Value.Split(',')[2].Split(':')[1]; string arm2PreviousPosition = nodeSteps[i - 1].Attributes["Arm2"].Value.Split(',')[2].Split(':')[1]; if (!string.IsNullOrEmpty(arm2CurrentPosition)) { if (arm2CurrentPosition.Equals(arm2PreviousPosition)) arm2HasMove.Add(false); else arm2HasMove.Add(true); } } } //check loop if (loopStartStepsNo.Count != loopEndStepsNo.Count) //判断个数 { reasons.Add("loop set is incorrect"); } //check pump recipe if (checkPumpRecipe && hasDispense) { string pumpRecipeName = nodeConfig.Attributes["COTPumpRecipe"]?.Value; if (string.IsNullOrEmpty(pumpRecipeName)) reasons.Add("pump recipe is null"); else { if (!CheckRecipe($"{_chamberId}\\Pump", pumpRecipeName, out List subReasons)) { reasons.Add($"Linked pump recipe check fail."); } } } //check arm move for (int i = 0; i < arm1HasMove.Count; i++) { if (arm1HasMove[i] && arm2HasMove[i])//同时移动 reasons.Add($"step{i + 2} arm1 and arm2 move at the same time"); } } void CheckADHRecipe(XmlNodeList nodeSteps, out List reasons) { reasons = new List(); if (nodeSteps.Count <= 0) { reasons.Add("steps count is 0."); return; } for (int i = 0; i < nodeSteps.Count; i++) { int stepNo = i + 1; //check dispense if (!nodeSteps[i].Attributes["ProcessPosition"].Value.Equals("Process") && !string.IsNullOrEmpty(nodeSteps[i].Attributes["Dispense"].Value)) { reasons.Add($"Step{stepNo} only position is process can select dispense."); } //check plate temp if (nodeSteps[i].Attributes["ProcessPosition"].Value.Equals("Process") && string.IsNullOrEmpty(nodeSteps[i].Attributes["PlateTemp"].Value)) { reasons.Add($"Step{stepNo} must set plate temp."); } //check alrm double.TryParse(nodeSteps[i].Attributes["AlarmMax"].Value, out double alarmMax); double.TryParse(nodeSteps[i].Attributes["AlarmMin"].Value, out double alarmMin); double.TryParse(nodeSteps[i].Attributes["WarnMax"].Value, out double warnMax); double.TryParse(nodeSteps[i].Attributes["WarnMin"].Value, out double warnMin); bool bRightRange = false; if (alarmMax == 0 && alarmMin == 0 && warnMax == 0 && warnMin == 0) continue; if (alarmMax == 0 && alarmMin == 0) { bRightRange = warnMax > warnMin; if (!bRightRange) { reasons.Add($"Step{stepNo} warnMax>warnMin?"); } } else if (warnMax == 0 && warnMax == 0) { bRightRange = alarmMax > alarmMin; if (!bRightRange) { reasons.Add($"Step{stepNo} alarmMax>alarmMin?"); } } else { bRightRange = alarmMax > warnMax && warnMax > warnMin && warnMin > alarmMin; if (!bRightRange) { reasons.Add($"Step{stepNo} alarmMax>warnMax>warnMin>alarmMin?"); } } } } void CheckOvenRecipe(XmlNodeList nodeSteps, out List reasons) { reasons = new List(); if (nodeSteps.Count <= 0) { reasons.Add("steps count is 0."); return; } for (int i = 0; i < nodeSteps.Count; i++) { int stepNo = i + 1; //check plate temp if (nodeSteps[i].Attributes["ProcessPosition"].Value.Equals("Heat") && string.IsNullOrEmpty(nodeSteps[i].Attributes["PlateTemp"].Value)) { reasons.Add($"Step{stepNo} must set plate temp."); } //check alrm double.TryParse(nodeSteps[i].Attributes["AlarmMax"].Value, out double alarmMax); double.TryParse(nodeSteps[i].Attributes["AlarmMin"].Value, out double alarmMin); double.TryParse(nodeSteps[i].Attributes["WarnMax"].Value, out double warnMax); double.TryParse(nodeSteps[i].Attributes["WarnMin"].Value, out double warnMin); bool bRightRange = false; if (alarmMax == 0 && alarmMin == 0 && warnMax == 0 && warnMin == 0) continue; if (alarmMax == 0 && alarmMin == 0) { bRightRange = warnMax > warnMin; if (!bRightRange) { reasons.Add($"Step{stepNo} warnMax>warnMin?"); } } else if (warnMax == 0 && warnMax == 0) { bRightRange = alarmMax > alarmMin; if (!bRightRange) { reasons.Add($"Step{stepNo} alarmMax>alarmMin?"); } } else { bRightRange = alarmMax > warnMax && warnMax > warnMin && warnMin > alarmMin; if (!bRightRange) { reasons.Add($"Step{stepNo} alarmMax>warnMax>warnMin>alarmMin?"); } } } } void CheckDummyRecipe(XmlNodeList nodeSteps, out List reasons) { reasons = new List(); if (nodeSteps.Count <= 0) { reasons.Add("steps count is 0."); return; } int enableItemCount = 0; for (int i = 0; i < nodeSteps.Count; i++) { int stepNo = i + 1; bool IsEnable = false; bool.TryParse(nodeSteps[i].Attributes["IsEnable"].Value, out IsEnable); if (IsEnable)//有效才检查 { enableItemCount++;//有效Item加1 //check item invalid string strRegularSequence = nodeSteps[i].Attributes["RegularSequence"]?.Value; if (string.IsNullOrEmpty(strRegularSequence)) reasons.Add($"Step{stepNo} RegularSequence is null"); string strWaferCount = nodeSteps[i].Attributes["WaferCount"]?.Value; string strRegularTime = nodeSteps[i].Attributes["RegularTime"]?.Value; if (string.IsNullOrEmpty(strWaferCount) && string.IsNullOrEmpty(strRegularTime)) reasons.Add($"Step{stepNo} WaferCount and RegularTime is null"); } } //check enbabled item count if (enableItemCount <= 0) { reasons.Add("invalaied item count is 0."); return; } } /// /// This method will be invoked by two places: /// (1) Load a recipe from server to GUI for editing (do not need validation when loading, do validation when saving); /// (2) Load a recipe from recipe engine to run process(always do a validation before run recipe); /// /// /// indicate whether a recipe format validation is needed or not /// public string LoadRecipe(string chamberId, string recipeName, bool needValidation) { string rcp = string.Empty; try { using (StreamReader fs = new StreamReader(GenerateRecipeFilePath(chamberId, recipeName))) { rcp = fs.ReadToEnd(); fs.Close(); } //if (needValidation) //{ // List reason; // if (!ValidateRecipe(chamberId, recipeName, rcp, out reason)) // { // rcp = string.Empty; // LOG.Write("校验recipe file 出错, " + string.Join(",", reason.ToArray())); // } //} } catch (Exception ex) { LOG.Write(ex, $"load recipe file failed, {recipeName}"); rcp = string.Empty; } return rcp; } /// /// Get recipe list /// /// /// /// public IEnumerable GetRecipes(string chamberId, bool includingUsedRecipe) { return _rcpContext.GetRecipes(chamberId, includingUsedRecipe); } /// /// Get recipe list in xml format /// /// /// /// public string GetXmlRecipeList(string chamberId, bool includingUsedRecipe) { XmlDocument doc = new XmlDocument(); var baseFolderPath = getRecipeDirPath(chamberId); DirectoryInfo curFolderInfo = new DirectoryInfo(baseFolderPath); doc.AppendChild(GenerateRecipeList(chamberId, curFolderInfo, doc, includingUsedRecipe)); return doc.OuterXml; } public void SaveRecipeHistory(string chamberId, string recipeName, string recipeContent, bool needSaveAs = true) { try { if (!string.IsNullOrEmpty(recipeName) && needSaveAs) { string newRecipeName = string.Format("HistoryRecipe\\{0}\\{1}", DateTime.Now.ToString("yyyyMM"), recipeName); SaveRecipe(chamberId, newRecipeName, recipeContent, true, false); LOG.Write(string.Format("{0}通知TM保存工艺程序{1}", chamberId, recipeName)); } } catch (Exception ex) { LOG.Write(ex, string.Format("保存{0}工艺程序{1}发生错误", chamberId, recipeName)); } } /// /// generate recipe list information in current directory /// /// /// /// /// XmlElement GenerateRecipeList(string chamberId, DirectoryInfo currentDir, XmlDocument doc, bool includingUsedRecipe) { int trimLength = getRecipeDirPath(chamberId).Length; XmlElement folderEle = doc.CreateElement("Folder"); folderEle.SetAttribute("Name", currentDir.FullName.Substring(trimLength)); DirectoryInfo[] dirInfos = currentDir.GetDirectories(); foreach (DirectoryInfo dirInfo in dirInfos) { if (!includingUsedRecipe && dirInfo.Name == "HistoryRecipe") continue; folderEle.AppendChild(GenerateRecipeList(chamberId, dirInfo, doc, includingUsedRecipe)); } FileInfo[] fileInfos = currentDir.GetFiles("*.rcp"); foreach (FileInfo fileInfo in fileInfos) { XmlElement fileNd = doc.CreateElement("File"); string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ; fileStr = fileStr.Substring(0, fileStr.LastIndexOf(".")); fileNd.SetAttribute("Name", fileStr); folderEle.AppendChild(fileNd); } return folderEle; } XmlElement GeneratelRestoreRecipeList(string chamberId, DirectoryInfo currentDir, XmlDocument doc, bool includingUsedRecipe) { int trimLength = getRecipeBackupDirPath(chamberId).Length; XmlElement folderEle = doc.CreateElement("Folder"); var name = currentDir.FullName.Substring(trimLength); folderEle.SetAttribute("Name", name); DirectoryInfo[] dirInfos = currentDir.GetDirectories(); foreach (DirectoryInfo dirInfo in dirInfos) { if (!includingUsedRecipe && dirInfo.Name == "HistoryRecipe") continue; folderEle.AppendChild(GeneratelRestoreRecipeList(chamberId, dirInfo, doc, includingUsedRecipe)); } FileInfo[] fileInfos = currentDir.GetFiles("*.rcp"); foreach (FileInfo fileInfo in fileInfos) { XmlElement fileNd = doc.CreateElement("File"); string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ; fileStr = fileStr.Substring(0, fileStr.LastIndexOf(".")); fileNd.SetAttribute("Name", fileStr); folderEle.AppendChild(fileNd); } return folderEle; } /// /// Delete a recipe by recipe name /// /// /// /// public bool DeleteRecipe(string chamberId, string recipeName) { try { //File.Delete(GenerateRecipeFilePath(chamberId, recipeName)); FileSystem.DeleteFile(GenerateRecipeFilePath(chamberId, recipeName), UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin); EventInfo(string.Format(Resources.RecipeFileManager_DeleteRecipe_RecipeFile0DeleteSucceeded, recipeName)); } catch (Exception ex) { LOG.Write(ex, "删除recipe file 出错"); EventWarning(string.Format(Resources.RecipeFileManager_DeleteRecipe_RecipeFile0DeleteFailed, recipeName)); return false; } return true; } /// /// Rename recipe /// /// /// /// /// public bool RenameRecipe(string chamId, string oldName, string newName) { try { if (File.Exists(GenerateRecipeFilePath(chamId, newName))) { EventWarning(string.Format(Resources.RecipeFileManager_RenameRecipe_RecipeFile0FileExisted, oldName)); return false; } else { File.Move(GenerateRecipeFilePath(chamId, oldName), GenerateRecipeFilePath(chamId, newName)); EventInfo(string.Format(Resources.RecipeFileManager_RenameRecipe_RecipeFile0Renamed, oldName, newName)); } } catch (Exception ex) { LOG.Write(ex, "重命名recipe file 出错"); EventWarning(string.Format(Resources.RecipeFileManager_RenameRecipe_RecipeFile0RenameFailed, oldName, newName)); return false; } return true; } private static string ovenModuleName = "CPL,HHP,LHP,CHP,TCP"; private string[] ovenModuleNames = ovenModuleName.Split(','); private void UpdateCheckResult(string recipeName) { var xmlRecipe = new XmlDocument(); using (StreamReader fs = new StreamReader(recipeName)) { string recipeContent = fs.ReadToEnd(); fs.Close(); xmlRecipe.LoadXml(recipeContent); } XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableRecipeData")[0]; nodeConfig.Attributes["CheckResult"].Value = string.Empty; XmlTextWriter writer = new XmlTextWriter(recipeName, Encoding.UTF8); writer.Formatting = Formatting.Indented; xmlRecipe.Save(writer); writer.Close(); } public bool BackupRecipe(string fileOriginalPath, string fileDestinationPath, bool isSaveLinkRecipe, List recipeNames) { try { string filePath = getRecipeBackupDirPath(fileOriginalPath); foreach (var item in recipeNames) { string sourceFilePath = GenerateRecipeFilePath(fileOriginalPath, item); string destFilePath = GenerateBackupRecipeFilePath(fileDestinationPath, item); if (File.Exists(sourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(destFilePath)); if (!di.Exists) di.Create(); File.Copy(sourceFilePath, destFilePath, true); UpdateCheckResult(destFilePath); } if (isSaveLinkRecipe) { string recipeContent = LoadRecipe(fileOriginalPath, item, false); var xmlRecipe = new XmlDocument(); try { string chamberType = fileOriginalPath.Split('\\')[0]; string processType = fileOriginalPath.Split('\\')[1]; if (string.IsNullOrEmpty(recipeContent)) continue; xmlRecipe.LoadXml(recipeContent); XmlNodeList nodeSteps = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; switch (processType) { case "WaferFlow": string strSystemReicpeName = nodeConfig.Attributes["SystemRecipe"]?.Value; if (!string.IsNullOrEmpty(strSystemReicpeName)) { if (CheckRecipe($"{_chamberId}\\System", strSystemReicpeName, out List subReasons)) { string subSourceFilePath = GenerateRecipeFilePath($"{_chamberId}\\System", strSystemReicpeName); string subDestFilePath = GenerateBackupRecipeFilePath($"{fileDestinationPath.Split('\\')[0]}\\System", strSystemReicpeName); DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); UpdateCheckResult(subDestFilePath); } } foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string strModuleName = nodestep.Attributes["ModuleName"]?.Value; if (string.IsNullOrEmpty(strModuleName)) { continue; } else { string[] temp = strModuleName.Split(',')[0].Split(' '); if (temp.Length > 1) strModuleName = temp[1]; } var linkRecipeName = nodestep.Attributes["RecipeName"].Value; if (!string.IsNullOrEmpty(linkRecipeName)) { string[] subRecipeNames = linkRecipeName.Split(','); foreach (var subitem in subRecipeNames) { string subRecipeName = string.Empty; string[] subRecipeNameStrings = subitem.Split(':'); if (subRecipeNameStrings.Length > 1) { subRecipeName = subRecipeNameStrings[1]; } else { subRecipeName = subRecipeNameStrings[0]; } if (ovenModuleName.Contains(strModuleName)) { strModuleName = "Oven"; } string subSourceFilePath = GenerateRecipeFilePath($"{_chamberId}\\{strModuleName}", subRecipeName); string subDestFilePath = GenerateBackupRecipeFilePath($"{fileDestinationPath.Split('\\')[0]}\\{strModuleName}", subRecipeName); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); UpdateCheckResult(subDestFilePath); } if (strModuleName == "COT") { string subCotPath = GenerateRecipeFilePath($"{ _chamberId}\\{strModuleName}", subRecipeName); var subXmlRecipe = new XmlDocument(); string subRecipeContent = LoadRecipe($"{ _chamberId}\\{strModuleName}", subRecipeName, false); if (string.IsNullOrEmpty(subRecipeContent)) continue; subXmlRecipe.LoadXml(subRecipeContent); XmlNode subNodeConfig = subXmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; string subPumpRecipeName = subNodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(subPumpRecipeName)) { string subPumpSourceFilePath = GenerateRecipeFilePath($"{_chamberId}\\Pump", subPumpRecipeName); string subPumpDestFilePath = GenerateBackupRecipeFilePath($"{fileDestinationPath.Split('\\')[0]}\\Pump", subPumpRecipeName); if (File.Exists(subPumpSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subPumpDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subPumpSourceFilePath, subPumpDestFilePath, true); UpdateCheckResult(subPumpDestFilePath); } } } } } } break; case "COT": case "DEV": string pumpRecipeName = nodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(pumpRecipeName)) { string subSourceFilePath = GenerateRecipeFilePath($"{_chamberId}\\Pump", pumpRecipeName); string subDestFilePath = GenerateBackupRecipeFilePath($"{fileDestinationPath.Split('\\')[0]}\\Pump", pumpRecipeName); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); UpdateCheckResult(subDestFilePath); } } break; case "Dummy": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string regularSequence = nodestep.Attributes["RegularSequence"]?.Value; string preSequence = nodestep.Attributes["PreSequence"]?.Value; if (!string.IsNullOrEmpty(regularSequence)) { string[] regularSequences = regularSequence.Split(';'); foreach (var subItem in regularSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(subItem, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) { string subSourceFilePath = GenerateRecipeFilePath($"{_chamberId}\\Pump", pumpRecipe); string subDestFilePath = GenerateBackupRecipeFilePath($"{fileDestinationPath.Split('\\')[0]}\\Pump", pumpRecipe); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); UpdateCheckResult(subDestFilePath); } } } } if (!string.IsNullOrEmpty(preSequence)) { string[] preSequences = preSequence.Split(';'); foreach (var subItem in preSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(item, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) { string subSourceFilePath = GenerateRecipeFilePath($"{_chamberId}\\Pump", pumpRecipe); string subDestFilePath = GenerateBackupRecipeFilePath($"{fileDestinationPath.Split('\\')[0]}\\Pump", pumpRecipe); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); UpdateCheckResult(subDestFilePath); } } } } } break; case "Wash": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string sequence = nodestep.Attributes["Sequence"]?.Value; if (string.IsNullOrEmpty(sequence)) { continue; } var subSequences = sequence.Split(';'); foreach (var subSeq in subSequences) { if (string.IsNullOrEmpty(subSeq)) { continue; } var pumpRecipe = GetKeyValue(subSeq, "PumpRecipe"); if (!string.IsNullOrEmpty(subSeq)) { string subSourceFilePath = GenerateRecipeFilePath($"{_chamberId}\\Pump", pumpRecipe); string subDestFilePath = GenerateBackupRecipeFilePath($"{fileDestinationPath.Split('\\')[0]}\\Pump", pumpRecipe); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); UpdateCheckResult(subDestFilePath); } } } } break; case "ADH": case "Oven": break; } } catch (Exception ex) { LOG.Write(ex); continue; } } } } catch (Exception ex) { LOG.Write(ex, "Backup Recipe file error"); } return true; } public bool CheckBackRecipeIsLinkRecipe(string fileOriginalPath, List recipeNames) { string chamberType = fileOriginalPath.Split('\\')[0]; string processType = fileOriginalPath.Split('\\')[1]; foreach (var item in recipeNames) { string recipeContent = LoadRecipe(fileOriginalPath, item, false); var xmlRecipe = new XmlDocument(); try { if (string.IsNullOrEmpty(recipeContent)) continue; xmlRecipe.LoadXml(recipeContent); XmlNodeList nodeSteps = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; switch (processType) { case "WaferFlow": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string strModuleName = nodestep.Attributes["ModuleName"]?.Value; if (string.IsNullOrEmpty(strModuleName)) { continue; } var linkRecipeName = nodestep.Attributes["RecipeName"].Value; if (string.IsNullOrEmpty(linkRecipeName)) { continue; } else { return true; } } string strSystemReicpeName = nodeConfig.Attributes["SystemRecipe"]?.Value; if (!string.IsNullOrEmpty(strSystemReicpeName)) { return true; } break; case "COT": case "DEV": string pumpRecipeName = nodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(pumpRecipeName)) { return true; } break; case "Dummy": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string regularSequence = nodestep.Attributes["RegularSequence"]?.Value; string preSequence = nodestep.Attributes["PreSequence"]?.Value; if (!string.IsNullOrEmpty(regularSequence)) { string[] regularSequences = regularSequence.Split(';'); foreach (var subItem in regularSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(subItem, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) return true; } } if (!string.IsNullOrEmpty(preSequence)) { string[] preSequences = preSequence.Split(';'); foreach (var subItem in preSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(subItem, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) return true; } } } break; case "Wash": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string sequence = nodestep.Attributes["Sequence"]?.Value; if (string.IsNullOrEmpty(sequence)) { continue; } var subSequences = sequence.Split(';'); foreach (var subSeq in subSequences) { if (string.IsNullOrEmpty(subSeq)) { continue; } var pumpRecipe = GetKeyValue(subSeq, "PumpRecipe"); if (!string.IsNullOrEmpty(subSeq)) { return true; } } } break; case "ADH": case "Oven": break; } } catch (Exception ex) { LOG.Write(ex); return false; } } return false; } private static string GetKeyValue(string args, string name) { string indexString = $"{name}="; string subString = args.Substring(args.IndexOf(indexString) + indexString.Length); int endIndex = subString.IndexOf(','); if (endIndex > 0) return subString.Substring(0, endIndex); else return subString; } public string GetXmlRestoreRecipeList(string chamberId, bool includingUsedRecipe) { XmlDocument doc = new XmlDocument(); var baseFolderPath = getRecipeBackupDirPath(chamberId); DirectoryInfo curFolderInfo = new DirectoryInfo(baseFolderPath); doc.AppendChild(GeneratelRestoreRecipeList(chamberId, curFolderInfo, doc, includingUsedRecipe)); return doc.OuterXml; } public List RestoreRecipeFolderList() { List folderList = new List(); var recipeBackupPath = PathManager.GetRecipeBackupDir(); DirectoryInfo directoryInfo = new DirectoryInfo(recipeBackupPath); DirectoryInfo[] directoryInfos = directoryInfo.GetDirectories(); foreach (var item in directoryInfos) { folderList.Add(item.Name); } return folderList; } public string LoadRestoreRecipe(string chamberId, string recipeName, bool needValidation) { string rcp = string.Empty; try { using (StreamReader fs = new StreamReader(GenerateBackupRecipeFilePath(chamberId, recipeName))) { rcp = fs.ReadToEnd(); fs.Close(); } } catch (Exception ex) { LOG.Write(ex, $"load recipe file failed, {recipeName}"); rcp = string.Empty; } return rcp; } public bool SigRestoreRecipe(string chamId, List recipeNames) { try { string filePath = getRecipeBackupDirPath(chamId); foreach (var item in recipeNames) { string strdest = chamId; string destFilePath = GenerateRecipeFilePath(strdest, item); string sourceFilePath = GenerateBackupRecipeFilePath(chamId, item); if (item.Contains("\\")) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(destFilePath)); if (!di.Exists) di.Create(); } File.Copy(sourceFilePath, destFilePath, true); } } catch (Exception ex) { LOG.Write(ex, "Backup Recipe file error"); } return true; } private static Dictionary> CreateRestoreDirectory = new Dictionary>(); private string RestoreDestFileCheck(string chamId, string recipeName) { string newRecipeName = recipeName; //有文件夹的处理方式 if (recipeName.Contains("\\")) { int index = 1; while (true) { int firstIndex = recipeName.IndexOf("\\"); string firstStr = recipeName.Substring(0, firstIndex); string tempRecipeDirectory = ""; string lastStr = recipeName.Substring(firstIndex + 1, recipeName.Length - firstStr.Length - 1); if (firstStr.Contains("(") && firstStr.Contains(")") && (firstStr.IndexOf("(") < firstStr.IndexOf(")")) && (firstStr.IndexOf(")") == firstStr.Length - 1)) { var tempFirstStr = firstStr.Remove(firstStr.IndexOf("("), firstStr.IndexOf(")")); newRecipeName = $"{tempFirstStr}({index}){lastStr}"; tempRecipeDirectory = $"{tempFirstStr}({index})"; } else { newRecipeName = $"{firstStr}({index})\\{lastStr}"; tempRecipeDirectory = $"{firstStr}({index})"; } var fileName = getRecipeDirPath(chamId) + newRecipeName + ".rcp"; DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(fileName)); if (CreateRestoreDirectory.ContainsKey(chamId) && CreateRestoreDirectory[chamId].Contains(tempRecipeDirectory)) { break; } else if (di.Exists) { index++; } else { if (!CreateRestoreDirectory.ContainsKey(chamId)) { List recipeDicectory = new List(); recipeDicectory.Add(tempRecipeDirectory); CreateRestoreDirectory.Add(chamId, recipeDicectory); } else { CreateRestoreDirectory[chamId].Add(tempRecipeDirectory); } di.Create(); break; } } } //直接文件的处理方式 else { int index = 1; while (true) { if (recipeName.Contains("(") && recipeName.Contains(")") && (recipeName.IndexOf("(") < recipeName.IndexOf(")")) && (recipeName.IndexOf(")") == recipeName.Length - 1)) { var tempFirstStr = recipeName.Remove(recipeName.IndexOf("("), recipeName.IndexOf(")")); newRecipeName = $"{tempFirstStr}({index})"; } else { newRecipeName = $"{recipeName}({index})"; break; } } } return getRecipeDirPath(chamId) + newRecipeName + ".rcp"; } public bool RestoreRecipe(string chamId, bool isSaveLink, List recipeNames) { try { string filePath = getRecipeBackupDirPath(chamId); CreateRestoreDirectory.Clear(); foreach (var item in recipeNames) { string strdest = chamId.Remove(5, 14); //string destFilePath = GenerateRecipeFilePath(strdest, item); string destFilePath = RestoreDestFileCheck(strdest, item); string sourceFilePath = GenerateBackupRecipeFilePath(chamId, item); if (File.Exists(sourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(destFilePath)); if (!di.Exists) di.Create(); File.Copy(sourceFilePath, destFilePath, true); } if (isSaveLink) { string recipeContent = LoadRestoreRecipe(chamId, item, false); var xmlRecipe = new XmlDocument(); try { string chamberType = chamId.Split('\\')[0]; string processType = chamId.Split('\\')[1]; if (string.IsNullOrEmpty(recipeContent)) continue; xmlRecipe.LoadXml(recipeContent); XmlNodeList nodeSteps = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; switch (processType) { case "WaferFlow": string strSystemReicpeName = nodeConfig.Attributes["SystemRecipe"]?.Value; if (!string.IsNullOrEmpty(strSystemReicpeName)) { string subSourceFilePath = GenerateBackupRecipeFilePath($"{chamId.Split('\\')[0]}\\System", strSystemReicpeName); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\System", strSystemReicpeName); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string strModuleName = nodestep.Attributes["ModuleName"]?.Value; if (string.IsNullOrEmpty(strModuleName)) { continue; } else { string[] temp = strModuleName.Split(',')[0].Split(' '); if (temp.Length > 1) strModuleName = temp[1]; } var linkRecipeName = nodestep.Attributes["RecipeName"].Value; if (string.IsNullOrEmpty(linkRecipeName)) { continue; } string[] subRecipeNames = linkRecipeName.Split(','); foreach (var subitem in subRecipeNames) { string subRecipeName = string.Empty; string[] subRecipeNameStrings = subitem.Split(':'); if (subRecipeNameStrings.Length > 1) { subRecipeName = subRecipeNameStrings[1]; } else { subRecipeName = subRecipeNameStrings[0]; } if (ovenModuleName.Contains(strModuleName)) { strModuleName = "Oven"; } string subSourceFilePath = GenerateBackupRecipeFilePath($"{chamId.Split('\\')[0]}\\{strModuleName}", subRecipeName); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\{strModuleName}", subRecipeName); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } if (strModuleName == "COT") { string subCotPath = GenerateBackupRecipeFilePath($"{ _chamberId}\\{strModuleName}", subRecipeName); var subXmlRecipe = new XmlDocument(); string subRecipeContent = LoadRecipe($"{ _chamberId}\\{strModuleName}", subRecipeName, false); if (string.IsNullOrEmpty(subRecipeContent)) continue; subXmlRecipe.LoadXml(subRecipeContent); XmlNode subNodeConfig = subXmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; string subPumpRecipeName = subNodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(subPumpRecipeName)) { string subPumpSourceFilePath = GenerateBackupRecipeFilePath($"{chamId.Split('\\')[0]}\\Pump", subPumpRecipeName); string subPumpDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", subPumpRecipeName); if (File.Exists(subPumpSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subPumpDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subPumpSourceFilePath, subPumpDestFilePath, true); } } } } } break; case "COT": case "DEV": string pumpRecipeName = nodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(pumpRecipeName)) { string subSourceFilePath = GenerateBackupRecipeFilePath($"{chamId.Split('\\')[0]}\\Pump", pumpRecipeName); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", pumpRecipeName); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } break; case "Dummy": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string regularSequence = nodestep.Attributes["RegularSequence"]?.Value; string preSequence = nodestep.Attributes["PreSequence"]?.Value; if (!string.IsNullOrEmpty(regularSequence)) { string[] regularSequences = regularSequence.Split(';'); foreach (var subItem in regularSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(subItem, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) { string subSourceFilePath = GenerateBackupRecipeFilePath($"{chamId.Split('\\')[0]}\\Pump", pumpRecipe); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", pumpRecipe); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } } } if (!string.IsNullOrEmpty(preSequence)) { string[] preSequences = preSequence.Split(';'); foreach (var subItem in preSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(item, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) { string subSourceFilePath = GenerateBackupRecipeFilePath($"{chamId.Split('\\')[0]}\\Pump", pumpRecipe); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", pumpRecipe); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } } } } break; case "Wash": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string sequence = nodestep.Attributes["Sequence"]?.Value; if (string.IsNullOrEmpty(sequence)) { continue; } var subSequences = sequence.Split(';'); foreach (var subSeq in subSequences) { if (string.IsNullOrEmpty(subSeq)) { continue; } var pumpRecipe = GetKeyValue(subSeq, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) { string subSourceFilePath = GenerateBackupRecipeFilePath($"{chamId.Split('\\')[0]}\\Pump", pumpRecipe); string subDestFilePath = RestoreDestFileCheck($"{_chamberId}\\Pump", pumpRecipe); if (File.Exists(subSourceFilePath)) { DirectoryInfo di = new DirectoryInfo(Path.GetDirectoryName(subDestFilePath)); if (!di.Exists) di.Create(); File.Copy(subSourceFilePath, subDestFilePath, true); } } } } break; case "ADH": case "Oven": break; } } catch (Exception ex) { LOG.Write(ex); continue; } } } } catch (Exception ex) { LOG.Write(ex, "Backup Recipe file error"); } return true; } public bool CheckRestoreRecipeIsLinkRecipe(string fileOriginalPath, List recipeNames) { string chamberType = fileOriginalPath.Split('\\')[0]; string processType = fileOriginalPath.Split('\\')[1]; foreach (var item in recipeNames) { string recipeContent = LoadRestoreRecipe(fileOriginalPath, item, false); var xmlRecipe = new XmlDocument(); try { if (string.IsNullOrEmpty(recipeContent)) continue; xmlRecipe.LoadXml(recipeContent); XmlNodeList nodeSteps = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Module[@Name='{processType}']/Step"); XmlNode nodeConfig = xmlRecipe.SelectNodes($"Aitex/TableRecipeData/Config")[0]; switch (processType) { case "WaferFlow": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string strModuleName = nodestep.Attributes["ModuleName"]?.Value; if (string.IsNullOrEmpty(strModuleName)) { continue; } var linkRecipeName = nodestep.Attributes["RecipeName"].Value; if (string.IsNullOrEmpty(linkRecipeName)) { continue; } else { return true; } } string strSystemReicpeName = nodeConfig.Attributes["SystemRecipe"]?.Value; if (!string.IsNullOrEmpty(strSystemReicpeName)) { return true; } break; case "COT": case "DEV": string pumpRecipeName = nodeConfig.Attributes["COTPumpRecipe"]?.Value; if (!string.IsNullOrEmpty(pumpRecipeName)) { return true; } break; case "Dummy": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string regularSequence = nodestep.Attributes["RegularSequence"]?.Value; string preSequence = nodestep.Attributes["PreSequence"]?.Value; if (!string.IsNullOrEmpty(regularSequence)) { string[] regularSequences = regularSequence.Split(';'); foreach (var subItem in regularSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(subItem, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) return true; } } if (!string.IsNullOrEmpty(preSequence)) { string[] preSequences = preSequence.Split(';'); foreach (var subItem in preSequences) { if (string.IsNullOrEmpty(subItem)) continue; var pumpRecipe = GetKeyValue(subItem, "PumpRecipe"); if (!string.IsNullOrEmpty(pumpRecipe)) return true; } } } break; case "Wash": foreach (var step in nodeSteps) { XmlElement nodestep = step as XmlElement; string sequence = nodestep.Attributes["Sequence"]?.Value; if (string.IsNullOrEmpty(sequence)) { continue; } var subSequences = sequence.Split(';'); foreach (var subSeq in subSequences) { if (string.IsNullOrEmpty(subSeq)) { continue; } var pumpRecipe = GetKeyValue(subSeq, "PumpRecipe"); if (!string.IsNullOrEmpty(subSeq)) { return true; } } } break; case "ADH": case "Oven": break; } } catch (Exception ex) { LOG.Write(ex); return false; } } return false; } private void EventInfo(string message) { _rcpContext.PostInfoEvent(message); } private void EventWarning(string message) { _rcpContext.PostWarningEvent(message); } private void EventAlarm(string message) { _rcpContext.PostAlarmEvent(message); } private void InfoDialog(string message) { _rcpContext.PostInfoDialogMessage(message); } private void WarningDialog(string message) { _rcpContext.PostWarningDialogMessage(message); } //private void AlarmDialog(string message) //{ // _rcpContext.PostAlarmDialogMessage(message); //} private void EventDialog(string message, List reason) { string msg = message; foreach (var r in reason) { msg += "\r\n" + r; } _rcpContext.PostDialogEvent(msg); } /// /// get recipe's file path /// /// /// private string GenerateRecipeFilePath(string chamId, string recipeName) { return getRecipeDirPath(chamId) + recipeName + ".rcp"; } private string GenerateBackupRecipeFilePath(string chamId, string recipeName) { return getRecipeBackupDirPath(chamId) + recipeName + ".rcp"; } private string GenerateSequenceFilePath(string chamId, string recipeName) { return getRecipeDirPath(chamId) + recipeName + ".seq"; } /// /// get recipe's dir path /// /// /// private string getRecipeDirPath(string chamId) { var dir = string.Format("{0}{1}\\", PathManager.GetRecipeDir(), chamId); DirectoryInfo di = new DirectoryInfo(dir); if (!di.Exists) di.Create(); return dir; } /// /// get recipe's dir path /// /// /// private string getRecipeBackupDirPath(string chamId) { var dir = string.Format("{0}{1}\\", PathManager.GetRecipeBackupDir(), chamId); DirectoryInfo di = new DirectoryInfo(dir); if (!di.Exists) di.Create(); return dir; } /// /// delete a recipe folder /// /// /// /// public bool DeleteFolder(string chamId, string folderName) { try { Directory.Delete(getRecipeDirPath(chamId) + folderName, true); EventInfo(string.Format(Resources.RecipeFileManager_DeleteFolder_RecipeFolder0DeleteSucceeded, folderName)); } catch (Exception ex) { LOG.Write(ex, "删除recipe folder 出错"); EventAlarm(string.Format("recipe folder {0} delete failed", folderName)); return false; } return true; } /// /// save as recipe content /// /// /// /// /// public bool SaveAsRecipe(string chamId, string recipeName, string recipeContent) { var path = GenerateRecipeFilePath(chamId, recipeName); if (File.Exists(path)) { EventAlarm(string.Format(Resources.RecipeFileManager_SaveAsRecipe_RecipeFile0savefailed, recipeName)); return false; } return SaveRecipe(chamId, recipeName, recipeContent, true, true); } /// /// save recipe content /// /// /// /// /// public bool SaveRecipe(string chamId, string recipeName, string recipeContent, bool clearBarcode, bool notifyUI) { //validate recipe format when saving a recipe file //var reasons1 = new List(); //var reasons2 = new List(); //ValidateRecipe(chamId, recipeName, recipeContent, out reasons1); //CheckRecipe(chamId, recipeContent, out reasons2); //reasons1.AddRange(reasons2); //if (reasons1.Count > 0) //{ // EventDialog(string.Format( Resources.RecipeFileManager_SaveRecipe_SaveRecipeContentError, recipeName), reasons1); //} bool ret = true; try { var path = GenerateRecipeFilePath(chamId, recipeName); FileInfo fi = new FileInfo(path); if (!fi.Directory.Exists) fi.Directory.Create(); XmlDocument xml = new XmlDocument(); xml.LoadXml(recipeContent); XmlTextWriter writer = new XmlTextWriter(path, Encoding.UTF8); writer.Formatting = Formatting.Indented; xml.Save(writer); writer.Close(); if (notifyUI) { InfoDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, recipeName)); } else { EV.PostMessage("System", EventEnum.GeneralInfo, string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, recipeName)); } } catch (Exception ex) { LOG.Write(ex, "保存recipe file 出错"); if (notifyUI) { WarningDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveFailed, recipeName)); } ret = false; } return ret; } /// /// save recipe content /// /// /// /// /// public bool SaveRestoreRecipe(string chamId, string recipeName, string recipeContent, bool clearBarcode, bool notifyUI) { //validate recipe format when saving a recipe file //var reasons1 = new List(); //var reasons2 = new List(); //ValidateRecipe(chamId, recipeName, recipeContent, out reasons1); //CheckRecipe(chamId, recipeContent, out reasons2); //reasons1.AddRange(reasons2); //if (reasons1.Count > 0) //{ // EventDialog(string.Format( Resources.RecipeFileManager_SaveRecipe_SaveRecipeContentError, recipeName), reasons1); //} bool ret = true; try { var path = GenerateBackupRecipeFilePath(chamId, recipeName); FileInfo fi = new FileInfo(path); if (!fi.Directory.Exists) fi.Directory.Create(); XmlDocument xml = new XmlDocument(); xml.LoadXml(recipeContent); XmlTextWriter writer = new XmlTextWriter(path, Encoding.UTF8); writer.Formatting = Formatting.Indented; xml.Save(writer); writer.Close(); if (notifyUI) { InfoDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, recipeName)); } else { EV.PostMessage("System", EventEnum.GeneralInfo, string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveCompleted, recipeName)); } } catch (Exception ex) { LOG.Write(ex, "保存recipe file 出错"); if (notifyUI) { WarningDialog(string.Format(Resources.RecipeFileManager_SaveRecipe_RecipeFile0SaveFailed, recipeName)); } ret = false; } return ret; } /// /// create a new recipe folder /// /// /// /// public bool CreateFolder(string chamId, string folderName) { try { Directory.CreateDirectory(getRecipeDirPath(chamId) + folderName); EventInfo(string.Format(Resources.RecipeFileManager_CreateFolder_RecipeFolder0Created, folderName)); } catch (Exception ex) { LOG.Write(ex, "create recipe folder failed"); EventAlarm(string.Format(Resources.RecipeFileManager_CreateFolder_RecipeFolder0CreateFailed, folderName)); return false; } return true; } /// /// Rename recipe folder name /// /// /// /// /// public bool RenameFolder(string chamId, string oldName, string newName) { try { string oldPath = getRecipeDirPath(chamId) + oldName; string newPath = getRecipeDirPath(chamId) + newName; Directory.Move(oldPath, newPath); EventInfo(string.Format(Resources.RecipeFileManager_RenameFolder_RecipeFolder0renamed, oldName, newName)); } catch (Exception ex) { LOG.Write(ex, "Rename recipe folder failed"); EventAlarm(string.Format(Resources.RecipeFileManager_RenameFolder_RecipeFolder0RenameFailed, oldName, newName)); return false; } return true; } public XmlDocument RecipeDom = new XmlDocument(); private string GetRecipeBody(string chamberId, string nodePath) { if (_rcpContext == null) return string.Empty; string schema = _rcpContext.GetRecipeDefiniton(chamberId); RecipeDom = new XmlDocument(); RecipeDom.LoadXml(schema); XmlNode node = RecipeDom.SelectSingleNode(nodePath); return node.OuterXml; } public string RecipeChamberType { get; set; } public string RecipeVersion { get; set; } public Dictionary> GetGroupRecipeTemplate() { try { XmlNode nodeRoot = RecipeDom.SelectSingleNode("Aitex/TableRecipeFormat"); RecipeChamberType = nodeRoot.Attributes["RecipeChamberType"].Value; RecipeVersion = nodeRoot.Attributes["RecipeVersion"].Value; } catch (Exception ex) { LOG.Write(ex); return null; } var columns = new Dictionary>(); RecipeTemplateColumnBase col = null; XmlNodeList nodes = RecipeDom.SelectNodes("Aitex/TableRecipeFormat/Catalog/Group"); foreach (XmlNode node in nodes) { var sigcolumns = new ObservableCollection(); XmlNodeList childNodes = node.SelectNodes("Step"); foreach (XmlNode step in childNodes) { //step number if (step.Attributes["ControlName"].Value == "StepNo") { col = new RecipeTemplateColumnBase() { DisplayName = "Step", ControlName = "StepNo", }; sigcolumns.Add(col); continue; } switch (step.Attributes["InputType"].Value) { case "TextInput": col = new RecipeTemplateColumnBase() { ValueType = "TextInput", ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, IsEnable = !bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; sigcolumns.Add(col); break; case "NumInput": col = new RecipeTemplateColumnBase() { ValueType = "NumInput", ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, InputMode = step.Attributes["InputMode"].Value, Minimun = double.Parse(step.Attributes["Min"].Value), Maximun = double.Parse(step.Attributes["Max"].Value), IsEnable = !bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; sigcolumns.Add(col); break; case "DoubleInput": col = new RecipeTemplateColumnBase() { ValueType = "DoubleInput", ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, InputMode = step.Attributes["InputMode"].Value, Minimun = double.Parse(step.Attributes["Min"].Value), Maximun = double.Parse(step.Attributes["Max"].Value), IsEnable = !bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; sigcolumns.Add(col); break; case "EditableSelection": col = new RecipeTemplateColumnBase() { ValueType = "EditableSelection", ModuleName = step.Attributes["ModuleName"].Value, Default = step.Attributes["Default"] != null ? step.Attributes["Default"].Value : "", ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, IsEnable = !bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; XmlNodeList items = step.SelectNodes("Item"); foreach (XmlNode item in items) { Option opt = new Option(); opt.ControlName = item.Attributes["ControlName"].Value; opt.DisplayName = item.Attributes["DisplayName"].Value; ((RecipeTemplateColumnBase)col).Options.Add(opt); } sigcolumns.Add(col); break; case "ReadOnlySelection": case "LoopSelection": col = new RecipeTemplateColumnBase() { ValueType = "LoopSelection", IsReadOnly = bool.Parse(step.Attributes["ReadOnly"] != null ? step.Attributes["ReadOnly"].Value : "false"), ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; XmlNodeList options = step.SelectNodes("Item"); foreach (XmlNode item in options) { Option opt = new Option(); opt.ControlName = item.Attributes["ControlName"].Value; opt.DisplayName = item.Attributes["DisplayName"].Value; ((RecipeTemplateColumnBase)col).Options.Add(opt); } sigcolumns.Add(col); break; case "PopSetting": col = new RecipeTemplateColumnBase() { ValueType = "LoopSelection", ModuleName = step.Attributes["ModuleName"].Value, ControlName = step.Attributes["ControlName"].Value, DisplayName = step.Attributes["DisplayName"].Value, EnableConfig = step.Attributes["EnableConfig"] != null && Convert.ToBoolean(step.Attributes["EnableConfig"].Value), EnableTolerance = step.Attributes["EnableTolerance"] != null && Convert.ToBoolean(step.Attributes["EnableTolerance"].Value), }; sigcolumns.Add(col); break; } } columns.Add(node.Attributes["DisplayName"].Value, sigcolumns); } return columns; } /// /// get reactor's recipe format define file /// /// /// public string GetRecipeFormatXml(string chamberId) { var rtn = GetRecipeBody(chamberId, "/Aitex/TableRecipeFormat"); return rtn; } /// /// get reactor's template recipe file /// /// /// public string GetRecipeTemplate(string chamberId) { if (_rcpContext != null) return _rcpContext.GetRecipeTemplate(chamberId); return GetRecipeBody(chamberId, "/Aitex/TableRecipeData"); } /// /// get reactor's template recipe file /// /// /// public string GetRecipeSchema(string chamberId) { if (_rcpContext == null) return string.Empty; string schema = _rcpContext.GetRecipeDefiniton(chamberId); XmlDocument dom = new XmlDocument(); dom.LoadXml(schema); XmlNode node = dom.SelectSingleNode("/Aitex/TableRecipeSchema"); return node.InnerXml; } public string GetRecipeByBarcode(string chamberId, string barcode) { try { string recipePath = PathManager.GetRecipeDir() + chamberId + "\\"; var di = new DirectoryInfo(recipePath); var fis = di.GetFiles("*.rcp", System.IO.SearchOption.AllDirectories); XmlDocument xml = new XmlDocument(); foreach (var fi in fis) { string str = fi.FullName.Substring(recipePath.Length); if (!str.Contains("HistoryRecipe\\")) { xml.Load(fi.FullName); if (xml.SelectSingleNode(string.Format("/TableRecipeData[@Barcode='{0}']", barcode)) != null) { return str.Substring(0, str.LastIndexOf('.')); } } } return string.Empty; } catch (Exception ex) { LOG.Write(ex); return string.Empty; } } public List ExpertLayoutRecipeParse(string chamberId, string recipeFile) { var layoutRecipe = new List(); string content = LoadRecipe(chamberId, recipeFile, false); if (string.IsNullOrEmpty(content)) { //reason = $"{recipeFile} is not a valid recipe file"; return layoutRecipe; } try { XmlDocument rcpDataDoc = new XmlDocument(); rcpDataDoc.LoadXml(content); XmlNode nodeModule; nodeModule = rcpDataDoc.SelectSingleNode("/Aitex/TableRecipeData/Module/Step[@Name='Expert']"); if (nodeModule == null) { return layoutRecipe; } else { Dictionary recipeData = new Dictionary(); XmlElement stepNode = nodeModule as XmlElement; //遍历Step节点 foreach (XmlAttribute att in stepNode.Attributes) { if (att.Name != "Name") { if (att.Value.ToLower() == "xd") { layoutRecipe.Add("XD"); } else if (att.Value.ToLower() == "t") { layoutRecipe.Add("T"); } else { layoutRecipe.Add(""); } } } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } public List LayoutExpertRecipeParse(/*string chamberId, */string recipeContent, string slotCount, string cassetteSlotCount) { var layoutRecipe = new List(); try { XmlDocument rcpDataDoc = new XmlDocument(); rcpDataDoc.LoadXml(recipeContent); XmlNode nodeModule; nodeModule = rcpDataDoc.SelectSingleNode("/Aitex/TableRecipeData/Module/Step[@Name='Normal']"); if (nodeModule == null) { //reason = "Recipe file does not contains step content for Normal"; return layoutRecipe; } else { Dictionary recipeData = new Dictionary(); XmlElement stepNode = nodeModule as XmlElement; //遍历Step节点 foreach (XmlAttribute att in stepNode.Attributes) { if (att.Name != "Name") { recipeData[att.Name] = att.Value; } } // 获取SlotCount int iSlotCount = 0; int.TryParse(slotCount, out iSlotCount); // 获取CassetteSlotCount; int iCassetteSlotCount = 0; int.TryParse(cassetteSlotCount, out iCassetteSlotCount); // 先往List里面添加SlotcCount数量的空值,后续再往里面insert具体的值 for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } // 获取DummyUpperSlot int iDummyUpperSlot; iDummyUpperSlot = 0; if (recipeData.ContainsKey("DummyUpperSlot")) { int.TryParse(recipeData["DummyUpperSlot"], out iDummyUpperSlot); } string strProductPos, strXDSlotNo, strDummySlotNo; strProductPos = string.Empty; strXDSlotNo = string.Empty; strDummySlotNo = string.Empty; if (recipeData.ContainsKey("MonitorSlotNo")) { strDummySlotNo = recipeData["MonitorSlotNo"]; } if (recipeData.ContainsKey("ProductSlotNo")) { strXDSlotNo = recipeData["ProductSlotNo"]; } layoutRecipe = XDSlot(iSlotCount, iCassetteSlotCount, strXDSlotNo, strDummySlotNo, iDummyUpperSlot); } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } public List LayoutRecipeParse(/*string chamberId, */string recipeContent, string slotCount, string cassetteSlotCount) { var layoutRecipe = new List(); //string content = loadrecipe(chamberid, recipefile, false); //if (string.isnullorempty(content)) //{ // reason = $"{recipefile} is not a valid recipe file"; // return layoutrecipe; //} try { XmlDocument rcpDataDoc = new XmlDocument(); rcpDataDoc.LoadXml(recipeContent); XmlNode nodeModule; nodeModule = rcpDataDoc.SelectSingleNode("/Aitex/TableRecipeData/Module/Step[@Name='Normal']"); if (nodeModule == null) { //reason = "Recipe file does not contains step content for Normal"; return layoutRecipe; } else { Dictionary recipeData = new Dictionary(); XmlElement stepNode = nodeModule as XmlElement; //遍历Step节点 foreach (XmlAttribute att in stepNode.Attributes) { if (att.Name != "Name") { recipeData[att.Name] = att.Value; } } // 获取SlotCount int iSlotCount = 0; int.TryParse(slotCount, out iSlotCount); // 获取CassetteSlotCount; int iCassetteSlotCount = 0; int.TryParse(cassetteSlotCount, out iCassetteSlotCount); // 先往List里面添加SlotcCount数量的空值,后续再往里面insert具体的值 for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } // 获取DummyUpperSlot int iDummyUpperSlot; iDummyUpperSlot = 0; //if (recipeData.ContainsKey("DummyUpperSlot")) //{ // int.TryParse(recipeData["DummyUpperSlot"], out iDummyUpperSlot); // if (iDummyUpperSlot == 0) // { // return layoutRecipe; // } //} //else //{ // return layoutRecipe; //} //// insert Upper Dummy //for (int i = 0; i < iDummyUpperSlot; i++) //{ // layoutRecipe[i] = "Dummy"; //} //// 获取DummyLowerSlot int iDummyLowerSlot; iDummyLowerSlot = 0; //if (recipeData.ContainsKey("DummyLowerSlot")) //{ // int.TryParse(recipeData["DummyLowerSlot"], out iDummyLowerSlot); // if (iDummyLowerSlot == 0) // { // return layoutRecipe; // } //} //else //{ // return layoutRecipe; //} // insert Lower Dummy //for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) //{ // layoutRecipe[i] = "Dummy"; //} string strProductPos, strProductSlotNo, strMonitor1Pos, strMonitor1SlotNo, strMonitor2SlotNo, strSDDummySlotNo, strFDDummySlotNo; strProductPos = string.Empty; strProductSlotNo = string.Empty; strMonitor1Pos = string.Empty; strMonitor1SlotNo = string.Empty; strMonitor2SlotNo = string.Empty; strSDDummySlotNo = string.Empty; strFDDummySlotNo = string.Empty; // 获取配置 if (recipeData.ContainsKey("ProductPosition")) { strProductPos = recipeData["ProductPosition"]; } if (recipeData.ContainsKey("ProductSlotNo")) { strProductSlotNo = recipeData["ProductSlotNo"]; } if (recipeData.ContainsKey("MonitorPosition")) { strMonitor1Pos = recipeData["MonitorPosition"]; } if (recipeData.ContainsKey("Monitor1SlotNo")) { strMonitor1SlotNo = recipeData["Monitor1SlotNo"]; } if (recipeData.ContainsKey("Monitor2SlotNo")) { strMonitor2SlotNo = recipeData["Monitor2SlotNo"]; } if (recipeData.ContainsKey("SDDummySlotNo")) { strSDDummySlotNo = recipeData["SDDummySlotNo"]; } if (recipeData.ContainsKey("FDDummySlotNo")) { strFDDummySlotNo = recipeData["FDDummySlotNo"]; } // insert Production and Monitor and ExtraDummy if (strProductPos == "Auto") { if (strMonitor1Pos == "Auto") { layoutRecipe = ProductAutoMonitorAuto(iSlotCount, iCassetteSlotCount, iDummyUpperSlot, iDummyLowerSlot); } else if (strMonitor1Pos == "Slot") { layoutRecipe = ProductAutoMonitorSlot(iSlotCount, iCassetteSlotCount, iDummyUpperSlot, iDummyLowerSlot, strProductSlotNo, strSDDummySlotNo, strMonitor1SlotNo, strMonitor2SlotNo); } else { //reason = "MonitorPosition is invalid"; return layoutRecipe; } } else if (strProductPos == "Slot") { if (strMonitor1Pos == "Auto") { layoutRecipe = ProductSlotMonitorAuto(iSlotCount, iCassetteSlotCount, iDummyUpperSlot, iDummyLowerSlot, strSDDummySlotNo, strProductSlotNo); } else if (strMonitor1Pos == "Slot") { layoutRecipe = ProductSlotMonitorSlot(iSlotCount, iCassetteSlotCount, iDummyUpperSlot, iDummyLowerSlot, strProductSlotNo, strSDDummySlotNo, strMonitor1SlotNo, strMonitor2SlotNo, strFDDummySlotNo); } else { //reason = "MonitorPosition is invalid"; return layoutRecipe; } } else { //reason = "ProductPosition is invalid"; return layoutRecipe; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductAutoMonitorAuto(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { //// insert Upper Dummy //for (int i = 0; i < iDummyUpperSlot; i++) //{ // layoutRecipe[i] = "Dummy"; //} //// insert Lower Dummy //for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) //{ // layoutRecipe[i] = "Dummy"; //} layoutRecipe[iDummyUpperSlot] = "M1"; layoutRecipe[iSlotCount - iDummyLowerSlot - 1] = "M1"; int iCount = 1; int cassetteMaxCount = SC.ContainsItem("System.CassetteMaxCount") ? SC.GetValue("System.CassetteMaxCount") : 6; int iPCount = 0; for (int i = iDummyUpperSlot + 1; i < iSlotCount - iDummyLowerSlot - 1; i++) { //if (iPCount >= cassetteMaxCount * iCassetteSlotCount) // break; if (iCount > iCassetteSlotCount && (iSlotCount - iDummyLowerSlot - 1 - i > iCassetteSlotCount)) { layoutRecipe[i] = "M1"; iCount = 1; } else { layoutRecipe[i] = "PD"; iCount++; iPCount++; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductAutoMonitorSlot(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strProductSlotNo, string strSDSlotNo, string strMonitor1SlotNo, string strMonitor2SlotNo) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy //for (int i = 0; i < iDummyUpperSlot; i++) //{ // layoutRecipe[i] = "Dummy"; //} //// insert Lower Dummy //for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) //{ // layoutRecipe[i] = "Dummy"; //} var dummySlotList = GetLayoutProductionMonitorSlot(strSDSlotNo); foreach (var item in dummySlotList) { int iPos = 0; int.TryParse(item, out iPos); iPos--; layoutRecipe[iPos] = "SD"; } var monitor1SlotList = new List(); monitor1SlotList = GetLayoutProductionMonitorSlot(strMonitor1SlotNo); var monitor1SlotNo = new List(); foreach (string str in monitor1SlotList) { int iPos = 0; int.TryParse(str, out iPos); iPos--; if (!monitor1SlotNo.Contains(iPos)) { monitor1SlotNo.Add(iPos); } } monitor1SlotNo.Sort(); // insert Monitor List monitorNo = new List(); foreach (int vm in monitor1SlotNo) { //if (layoutRecipe[vm] != "Dummy") //{ layoutRecipe[vm] = "M1"; //} } int cassetteMaxCount = SC.ContainsItem("System.CassetteMaxCount") ? SC.GetValue("System.CassetteMaxCount") : 6; int iCount = 0; var productSlotList = new List(); productSlotList = GetLayoutProductionMonitorSlot(strProductSlotNo); var productSlotNo = new List(); foreach (string str in productSlotList) { int iPos = 0; int.TryParse(str, out iPos); iPos--; if (!productSlotNo.Contains(iPos)) { productSlotNo.Add(iPos); } } productSlotNo.Sort(); foreach (int vm in productSlotNo) { //if (layoutRecipe[vm] != "Dummy") //{ layoutRecipe[vm] = "PD"; //} } // insert Production //for (int i = iDummyUpperSlot; i < iSlotCount - iDummyLowerSlot; i++) //{ // //if (iCount >= cassetteMaxCount * iCassetteSlotCount) // // break; // if (layoutRecipe[i] == "") // { // layoutRecipe[i] = "Production"; // iCount++; // } //} } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductSlotMonitorAuto(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strDummySlotNo, string strProductSlotNo) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { //// insert Upper Dummy //for (int i = 0; i < iDummyUpperSlot; i++) //{ // layoutRecipe[i] = "Dummy"; //} //// insert Lower Dummy //for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) //{ // layoutRecipe[i] = "Dummy"; //} var dummySlotList = GetLayoutProductionMonitorSlot(strDummySlotNo); foreach (var item in dummySlotList) { int iPos = 0; int.TryParse(item, out iPos); iPos--; layoutRecipe[iPos] = "SD"; } var productSlotList = new List(); productSlotList = GetLayoutProductionMonitorSlot(strProductSlotNo); var productSloNo = new List(); foreach (string str in productSlotList) { int iPos = 0; int.TryParse(str, out iPos); iPos--; if (!productSloNo.Contains(iPos)) { productSloNo.Add(iPos); } } productSloNo.Sort(); // insert Production foreach (int vm in productSloNo) { if (layoutRecipe[vm] == "" && vm >= iDummyUpperSlot && vm <= iSlotCount - iDummyLowerSlot - 1) { layoutRecipe[vm] = "PD"; } } layoutRecipe[iDummyUpperSlot] = "M1"; layoutRecipe[iSlotCount - iDummyLowerSlot - 1] = "M1"; int iCount = 1; for (int i = iDummyUpperSlot + 1; i < iSlotCount - iDummyLowerSlot - 1; i++) { if (iCount > iCassetteSlotCount && (iSlotCount - iDummyLowerSlot - 1 - i > iCassetteSlotCount)) { layoutRecipe[i] = "M1"; iCount = 1; } else { iCount++; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductSlotMonitorSlot(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strProductSlotNo, string strSDDummySlotNo, string strMonitor1SlotNo, string strMonitor2SlotNo, string strFDDummySlotNo) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { var sddummySlotList = GetLayoutProductionMonitorSlot(strSDDummySlotNo); foreach (var item in sddummySlotList) { int iPos = 0; int.TryParse(item, out iPos); iPos--; layoutRecipe[iPos] = "SD"; } var fddummySlotList = GetLayoutProductionMonitorSlot(strFDDummySlotNo); foreach (var item in fddummySlotList) { int iPos = 0; int.TryParse(item, out iPos); iPos--; layoutRecipe[iPos] = "FD"; } var productSlotNo = new List(); productSlotNo = GetLayoutProductionMonitorSlot(strProductSlotNo); var monitor1SlotNo = new List(); monitor1SlotNo = GetLayoutProductionMonitorSlot(strMonitor1SlotNo); var monitor2SlotNo = new List(); monitor2SlotNo = GetLayoutProductionMonitorSlot(strMonitor2SlotNo); // insert Production foreach (string str in productSlotNo) { int iPos = 0; int.TryParse(str, out iPos); layoutRecipe[iPos - 1] = "PD"; } // insert Monitor foreach (string str in monitor1SlotNo) { int iPos = 0; int.TryParse(str, out iPos); layoutRecipe[iPos - 1] = "M1"; } foreach (string str in monitor2SlotNo) { int iPos = 0; int.TryParse(str, out iPos); layoutRecipe[iPos - 1] = "M2"; } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductAutoMonitorBetweenCassetteStandardPitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strMonitorBetweenCasseteNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var monitorBetweenCassetteNo = new List(); monitorBetweenCassetteNo = GetLayoutProductionMonitorSlot(strMonitorBetweenCasseteNo); // insert Monitor int iIndex, iMonitorCount = 7; iIndex = iDummyUpperSlot; for (int i = 0; i < iMonitorCount; i++) { iIndex = iDummyUpperSlot + i * iCassetteSlotCount + i; if (iIndex < iSlotCount - iDummyLowerSlot - 1) { if (monitorBetweenCassetteNo[i] == "ON") { layoutRecipe[iIndex] = "M1"; } } else { if (monitorBetweenCassetteNo[i] == "ON") { iIndex = iSlotCount - iDummyLowerSlot - 1; layoutRecipe[iIndex] = "M1"; } } } // insert Production int iFirstMonitorIndex = 0; for (int i = iDummyUpperSlot; i < iSlotCount; i++) { if (layoutRecipe[i] == "M1") { iFirstMonitorIndex = i; break; } } // Search Up for (int i = iFirstMonitorIndex; i >= iDummyUpperSlot; i--) { if (layoutRecipe[i] == "") { layoutRecipe[i] = "PD"; } else { break; } } // Search Down for (int i = iFirstMonitorIndex; i <= iSlotCount - iDummyLowerSlot - 1; i++) { if (layoutRecipe[i] == "") { layoutRecipe[i] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductAutoMonitorBetweenCassetteDoublePitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strMonitorBetweenCasseteNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var monitorBetweenCassetteNo = new List(); monitorBetweenCassetteNo = GetLayoutProductionMonitorSlot(strMonitorBetweenCasseteNo); // insert Monitor int iIndex, iMonitorCount = 7; iIndex = iDummyUpperSlot; for (int i = 0; i < iMonitorCount; i += 2) { iIndex = iDummyUpperSlot + 1 + i * iCassetteSlotCount * 2 + i * 2; if (iIndex < iSlotCount - iDummyLowerSlot - 2) { if (monitorBetweenCassetteNo[i] == "ON") { layoutRecipe[iIndex] = "M1"; } } else { if (monitorBetweenCassetteNo[i] == "ON") { iIndex = iSlotCount - iDummyLowerSlot - 2; layoutRecipe[iIndex] = "M1"; } } } // insert Production int iFirstMonitorIndex = 0; for (int i = iDummyUpperSlot; i < iSlotCount; i++) { if (layoutRecipe[i] == "M1") { iFirstMonitorIndex = i; break; } } // search Up for (int i = iFirstMonitorIndex; i >= iDummyUpperSlot + 1; i -= 2) { if (layoutRecipe[i] == "" && layoutRecipe[i - 1] == "") { layoutRecipe[i] = "PD"; } else { break; } } // serach Down for (int i = iFirstMonitorIndex; i <= iSlotCount - iDummyLowerSlot - 2; i += 2) { if (layoutRecipe[i] == "" && layoutRecipe[i + 1] == "") { layoutRecipe[i] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductAutoMonitorBetweenCassetteTriplePitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strMonitorBetweenCasseteNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var monitorBetweenCassetteNo = new List(); monitorBetweenCassetteNo = GetLayoutProductionMonitorSlot(strMonitorBetweenCasseteNo); // insert Monitor int iIndex, iMonitorCount = 7; iIndex = iDummyUpperSlot; for (int i = 0; i < iMonitorCount; i += 3) { iIndex = iDummyUpperSlot + 2 + i * iCassetteSlotCount * 3 + i * 3; if (iIndex < iSlotCount - iDummyLowerSlot - 3) { if (monitorBetweenCassetteNo[i] == "ON") { layoutRecipe[iIndex] = "M1"; } } else { if (monitorBetweenCassetteNo[i] == "ON") { iIndex = iSlotCount - iDummyLowerSlot - 3; layoutRecipe[iIndex] = "M1"; } } } // insert Production int iFirstMonitorIndex = 0; for (int i = iDummyUpperSlot; i < iSlotCount; i++) { if (layoutRecipe[i] == "M1") { iFirstMonitorIndex = i; break; } } // search Up for (int i = iFirstMonitorIndex; i >= iDummyUpperSlot + 2; i -= 3) { if (layoutRecipe[i] == "" && layoutRecipe[i - 1] == "" && layoutRecipe[i - 2] == "") { layoutRecipe[i] = "PD"; } else { break; } } // serach Down for (int i = iFirstMonitorIndex; i <= iSlotCount - iDummyLowerSlot - 3; i += 3) { if (layoutRecipe[i] == "" && layoutRecipe[i + 1] == "" && layoutRecipe[i + 2] == "") { layoutRecipe[i] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductAutoMonitorSlotStandardPitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strMonitorSlotNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var monitorSlotList = new List(); monitorSlotList = GetLayoutProductionMonitorSlot(strMonitorSlotNo); var monitorSlotNo = new List(); foreach (string str in monitorSlotList) { int iPos = 0; int.TryParse(str, out iPos); iPos--; if (!monitorSlotNo.Contains(iPos)) { monitorSlotNo.Add(iPos); } } monitorSlotNo.Sort(); // insert Monitor List monitorNo = new List(); foreach (int vm in monitorSlotNo) { if (layoutRecipe[vm] != "SD") { layoutRecipe[vm] = "M1"; } } // insert Production int iFirstMonitorIndex = 0; for (int i = iDummyUpperSlot; i < iSlotCount; i++) { if (layoutRecipe[i] == "M1") { iFirstMonitorIndex = i; break; } } for (int i = iDummyUpperSlot; i < iFirstMonitorIndex; i++) { if (layoutRecipe[i] == "") { layoutRecipe[i] = "PD"; } else { break; } } for (int i = iFirstMonitorIndex; i <= iSlotCount - iDummyLowerSlot - 1; i++) { if (layoutRecipe[i] == "") { layoutRecipe[i] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductAutoMonitorSlotDoublePitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strMonitorSlotNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var monitorSlotList = new List(); monitorSlotList = GetLayoutProductionMonitorSlot(strMonitorSlotNo); var monitorSlotNo = new List(); foreach (string str in monitorSlotList) { int iPos = 0; int.TryParse(str, out iPos); iPos--; if (!monitorSlotNo.Contains(iPos)) { monitorSlotNo.Add(iPos); } } monitorSlotNo.Sort(); // insert Monitor List monitorNo = new List(); foreach (int vm in monitorSlotNo) { if (layoutRecipe[vm] != "SD" && vm >= iDummyUpperSlot + 1 && vm <= iSlotCount - iDummyLowerSlot - 2) { layoutRecipe[vm] = "M1"; } } // insert Production int iFirstMonitorIndex = 0; for (int i = iDummyUpperSlot; i < iSlotCount; i++) { if (layoutRecipe[i] == "M1") { iFirstMonitorIndex = i; break; } } for (int i = iDummyUpperSlot + 1; i < iFirstMonitorIndex; i += 2) { if (layoutRecipe[i] == "" && layoutRecipe[i + 1] == "") { layoutRecipe[i] = "PD"; } else { break; } } for (int i = iFirstMonitorIndex; i <= iSlotCount - iDummyLowerSlot - 2; i += 2) { if (layoutRecipe[i] == "" && layoutRecipe[i + 1] == "") { layoutRecipe[i] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductAutoMonitorSlotTriplePitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strMonitorSlotNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var monitorSlotList = new List(); monitorSlotList = GetLayoutProductionMonitorSlot(strMonitorSlotNo); var monitorSlotNo = new List(); foreach (string str in monitorSlotList) { int iPos = 0; int.TryParse(str, out iPos); iPos--; if (!monitorSlotNo.Contains(iPos)) { monitorSlotNo.Add(iPos); } } monitorSlotNo.Sort(); // insert Monitor List monitorNo = new List(); foreach (int vm in monitorSlotNo) { if (layoutRecipe[vm] != "SD" && vm >= iDummyUpperSlot + 2 && vm <= iSlotCount - iDummyLowerSlot - 3) { layoutRecipe[vm] = "M1"; } } // insert Production int iFirstMonitorIndex = 0; for (int i = iDummyUpperSlot; i < iSlotCount; i++) { if (layoutRecipe[i] == "M1") { iFirstMonitorIndex = i; break; } } for (int i = iDummyUpperSlot + 2; i < iFirstMonitorIndex; i += 3) { if (layoutRecipe[i] == "" && layoutRecipe[i + 1] == "" && layoutRecipe[i + 2] == "") { layoutRecipe[i] = "PD"; } else { break; } } for (int i = iFirstMonitorIndex; i <= iSlotCount - iDummyLowerSlot - 3; i += 3) { if (layoutRecipe[i] == "" && layoutRecipe[i + 1] == "" && layoutRecipe[i + 2] == "") { layoutRecipe[i] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductSlotMonitorBetweenCassetteStandardPitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strProductSlotNo, string strMonitorBetweenCasseteNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var productSlotList = new List(); productSlotList = GetLayoutProductionMonitorSlot(strProductSlotNo); var productSloNo = new List(); foreach (string str in productSlotList) { int iPos = 0; int.TryParse(str, out iPos); iPos--; if (!productSloNo.Contains(iPos)) { productSloNo.Add(iPos); } } productSloNo.Sort(); var monitorBetweenCassetteNo = new List(); monitorBetweenCassetteNo = GetLayoutProductionMonitorSlot(strMonitorBetweenCasseteNo); // insert Monitor int iIndex, iMonitorCount = 7; iIndex = iDummyUpperSlot; for (int i = 0; i < iMonitorCount; i++) { iIndex = iDummyUpperSlot + i * iCassetteSlotCount + i; if (iIndex < iSlotCount - iDummyLowerSlot - 1) { if (monitorBetweenCassetteNo[i] == "ON") { layoutRecipe[iIndex] = "M1"; } } else { if (monitorBetweenCassetteNo[i] == "ON") { iIndex = iSlotCount - iDummyLowerSlot - 1; layoutRecipe[iIndex] = "M1"; } } } // insert Production foreach (int vm in productSloNo) { if (layoutRecipe[vm] == "" && vm >= iDummyUpperSlot && vm <= iSlotCount - iDummyLowerSlot - 1) { layoutRecipe[vm] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductSlotMonitorBetweenCassetteDoublePitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strProductSlotNo, string strMonitorBetweenCasseteNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var productSlotList = new List(); productSlotList = GetLayoutProductionMonitorSlot(strProductSlotNo); var productSloNo = new List(); foreach (string str in productSlotList) { int iPos = 0; int.TryParse(str, out iPos); iPos--; if (!productSloNo.Contains(iPos)) { productSloNo.Add(iPos); } } productSloNo.Sort(); var monitorBetweenCassetteNo = new List(); monitorBetweenCassetteNo = GetLayoutProductionMonitorSlot(strMonitorBetweenCasseteNo); // insert Monitor int iIndex, iMonitorCount = 7; iIndex = iDummyUpperSlot; for (int i = 0; i < iMonitorCount; i += 2) { iIndex = iDummyUpperSlot + 1 + i * iCassetteSlotCount * 2 + i * 2; if (iIndex < iSlotCount - iDummyLowerSlot - 2) { if (monitorBetweenCassetteNo[i] == "ON") { layoutRecipe[iIndex] = "M1"; } } else { if (monitorBetweenCassetteNo[i] == "ON") { iIndex = iSlotCount - iDummyLowerSlot - 2; layoutRecipe[iIndex] = "M1"; } } } // insert Production foreach (int vm in productSloNo) { if (layoutRecipe[vm] == "" && layoutRecipe[vm - 1] == "" && layoutRecipe[vm + 1] == "" && vm >= iDummyUpperSlot + 1 && vm <= iSlotCount - iDummyLowerSlot - 2) { layoutRecipe[vm] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductSlotMonitorBetweenCassetteTriplePitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strProductSlotNo, string strMonitorBetweenCasseteNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var productSlotList = new List(); productSlotList = GetLayoutProductionMonitorSlot(strProductSlotNo); var productSloNo = new List(); foreach (string str in productSlotList) { int iPos = 0; int.TryParse(str, out iPos); iPos--; if (!productSloNo.Contains(iPos)) { productSloNo.Add(iPos); } } productSloNo.Sort(); var monitorBetweenCassetteNo = new List(); monitorBetweenCassetteNo = GetLayoutProductionMonitorSlot(strMonitorBetweenCasseteNo); // insert Monitor int iIndex, iMonitorCount = 7; iIndex = iDummyUpperSlot; for (int i = 0; i < iMonitorCount; i += 3) { iIndex = iDummyUpperSlot + 2 + i * iCassetteSlotCount * 3 + i * 3; if (iIndex < iSlotCount - iDummyLowerSlot - 3) { if (monitorBetweenCassetteNo[i] == "ON") { layoutRecipe[iIndex] = "M1"; } } else { if (monitorBetweenCassetteNo[i] == "ON") { iIndex = iSlotCount - iDummyLowerSlot - 3; layoutRecipe[iIndex] = "M1"; } } } // insert Production foreach (int vm in productSloNo) { if (layoutRecipe[vm] == "" && layoutRecipe[vm - 1] == "" && layoutRecipe[vm - 2] == "" && layoutRecipe[vm + 1] == "" && layoutRecipe[vm + 2] == "" && vm >= iDummyUpperSlot + 2 && vm <= iSlotCount - iDummyLowerSlot - 3) { layoutRecipe[vm] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductSlotMonitorSlotStandardPitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strProductSlotNo, string strMonitorSlotNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var productSlotNo = new List(); productSlotNo = GetLayoutProductionMonitorSlot(strProductSlotNo); var monitorSlotNo = new List(); monitorSlotNo = GetLayoutProductionMonitorSlot(strMonitorSlotNo); // insert Production foreach (string str in productSlotNo) { int iPos = 0; int.TryParse(str, out iPos); if (layoutRecipe[iPos - 1] != "SD") { layoutRecipe[iPos - 1] = "PD"; } } // insert Monitor foreach (string str in monitorSlotNo) { int iPos = 0; int.TryParse(str, out iPos); if (layoutRecipe[iPos - 1] != "SD") { layoutRecipe[iPos - 1] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductSlotMonitorSlotDoublePitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strProductSlotNo, string strMonitorSlotNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var productSlotNo = new List(); productSlotNo = GetLayoutProductionMonitorSlot(strProductSlotNo); var monitorSlotNo = new List(); monitorSlotNo = GetLayoutProductionMonitorSlot(strMonitorSlotNo); // insert Production foreach (string str in productSlotNo) { int iPos = 0; int.TryParse(str, out iPos); if (layoutRecipe[iPos - 2] == string.Empty && layoutRecipe[iPos - 1] != "SD" && layoutRecipe[iPos] == string.Empty) { layoutRecipe[iPos - 1] = "PD"; } } // insert Monitor foreach (string str in monitorSlotNo) { int iPos = 0; int.TryParse(str, out iPos); if (layoutRecipe[iPos - 2] == string.Empty && layoutRecipe[iPos - 1] != "SD" && layoutRecipe[iPos] == string.Empty) { layoutRecipe[iPos - 1] = "PD"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List ProductSlotMonitorSlotTriplePitch(int iSlotCount, int iCassetteSlotCount, int iDummyUpperSlot, int iDummyLowerSlot, string strProductSlotNo, string strMonitorSlotNo, string strBoatRule) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { // insert Upper Dummy for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "SD"; } // insert Lower Dummy for (int i = iSlotCount - 1; i >= iSlotCount - iDummyLowerSlot; i--) { layoutRecipe[i] = "SD"; } var productSlotNo = new List(); productSlotNo = GetLayoutProductionMonitorSlot(strProductSlotNo); var monitorSlotNo = new List(); monitorSlotNo = GetLayoutProductionMonitorSlot(strMonitorSlotNo); // insert Production foreach (string str in productSlotNo) { int iPos = 0; int.TryParse(str, out iPos); if (layoutRecipe[iPos - 3] == string.Empty && layoutRecipe[iPos - 2] == string.Empty && layoutRecipe[iPos - 1] != "Dummy" && layoutRecipe[iPos] == string.Empty && layoutRecipe[iPos + 1] == string.Empty) { layoutRecipe[iPos - 1] = "PD"; } } // insert Monitor foreach (string str in monitorSlotNo) { int iPos = 0; int.TryParse(str, out iPos); if (layoutRecipe[iPos - 3] == string.Empty && layoutRecipe[iPos - 2] == string.Empty && layoutRecipe[iPos - 1] != "Dummy" && layoutRecipe[iPos] == string.Empty && layoutRecipe[iPos + 1] == string.Empty) { layoutRecipe[iPos - 1] = "M1"; } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } private List GetLayoutProductionMonitorSlot(string strParam) { var slot = new List(); if (strParam == string.Empty) { return slot; } slot = strParam.Split(',').ToList(); return slot; } private List XDSlot(int iSlotCount, int iCassetteSlotCount, string strXDSlotNo, string strDummySlotNo, int iDummyUpperSlot) { var layoutRecipe = new List(); for (int i = 0; i < iSlotCount; i++) { layoutRecipe.Add(string.Empty); } try { if (iDummyUpperSlot > 0) { for (int i = 0; i < iDummyUpperSlot; i++) { layoutRecipe[i] = "XD"; } } else { var TSlotNo = new List(); TSlotNo = GetLayoutProductionMonitorSlot(strXDSlotNo); var XDSlotNo = new List(); XDSlotNo = GetLayoutProductionMonitorSlot(strDummySlotNo); // insert Production foreach (string str in TSlotNo) { int iPos = 0; int.TryParse(str, out iPos); if (layoutRecipe[iPos - 1] != "XD") { layoutRecipe[iPos - 1] = "T"; } } foreach (string str in XDSlotNo) { int iPos = 0; int.TryParse(str, out iPos); if (layoutRecipe[iPos - 1] != "T") { layoutRecipe[iPos - 1] = "XD"; } } } } catch (Exception ex) { LOG.Write(ex); return layoutRecipe; } return layoutRecipe; } #region Sequence private string GetSequenceConfig(string nodePath) { if (_seqContext == null) return string.Empty; string schema = _seqContext.GetConfigXml(); XmlDocument dom = new XmlDocument(); dom.LoadXml(schema); XmlNode node = dom.SelectSingleNode(nodePath); return node.OuterXml; } public string GetWaferFlowRecipe(string recipeName, bool needValidation) { string seq = string.Empty; try { using (StreamReader fs = new StreamReader(GenerateRecipeFilePath($"{SC.GetStringValue("System.Recipe.RecipeChamberType")}\\{WaferFlowFolder}", recipeName))) { seq = fs.ReadToEnd(); fs.Close(); } if (needValidation && !_seqContext.Validation(seq)) { EV.PostWarningLog(SourceModule, $"Read {recipeName} failed, validation failed"); seq = string.Empty; } } catch (Exception ex) { LOG.Write(ex); EV.PostWarningLog(SourceModule, $"Read {recipeName} failed, " + ex.Message); seq = string.Empty; } return seq; } public string GetSequence(string sequenceName, bool needValidation) { string seq = string.Empty; try { using (StreamReader fs = new StreamReader(GenerateSequenceFilePath(SequenceFolder, sequenceName))) { seq = fs.ReadToEnd(); fs.Close(); } if (needValidation && !_seqContext.Validation(seq)) { EV.PostWarningLog(SourceModule, $"Read {sequenceName} failed, validation failed"); seq = string.Empty; } } catch (Exception ex) { LOG.Write(ex); EV.PostWarningLog(SourceModule, $"Read {sequenceName} failed, " + ex.Message); seq = string.Empty; } return seq; } public List GetSequenceNameList() { var result = new List(); try { string recipePath = PathManager.GetRecipeDir() + SequenceFolder + "\\"; var di = new DirectoryInfo(recipePath); var fis = di.GetFiles("*.seq", System.IO.SearchOption.AllDirectories); foreach (var fi in fis) { string str = fi.FullName.Substring(recipePath.Length); str = str.Substring(0, str.LastIndexOf('.')); result.Add(str); } } catch (Exception ex) { LOG.Write(ex); EV.PostWarningLog(SourceModule, "Get sequence list failed, " + ex.Message); } return result; } public bool DeleteSequence(string sequenceName) { try { File.Delete(GenerateSequenceFilePath(SequenceFolder, sequenceName)); EV.PostInfoLog(SourceModule, $"sequence {sequenceName} deleted"); } catch (Exception ex) { LOG.Write(ex); EV.PostWarningLog(SourceModule, $"delete {sequenceName} failed, " + ex.Message); return false; } return true; } public bool SaveSequence(string sequenceName, string sequenceContent, bool notifyUI) { bool ret = true; try { var path = GenerateSequenceFilePath(SequenceFolder, sequenceName); FileInfo fi = new FileInfo(path); if (!fi.Directory.Exists) { fi.Directory.Create(); } XmlDocument xml = new XmlDocument(); xml.LoadXml(sequenceContent); XmlTextWriter writer = new XmlTextWriter(path, null); writer.Formatting = Formatting.Indented; xml.Save(writer); writer.Close(); if (notifyUI) { EV.PostPopDialogMessage(EventLevel.Information, "Save Complete", $"Sequence {sequenceName} saved "); } else { EV.PostInfoLog(SourceModule, $"Sequence {sequenceName} saved "); } } catch (Exception ex) { LOG.Write(ex); EV.PostWarningLog(SourceModule, $"save sequence {sequenceName} failed, " + ex.Message); if (notifyUI) { EV.PostPopDialogMessage(EventLevel.Alarm, "Save Error", $"save sequence {sequenceName} failed, " + ex.Message); } ret = false; } return ret; } public bool SaveAsSequence(string sequenceName, string sequenceContent) { var path = GenerateSequenceFilePath(SequenceFolder, sequenceName); if (File.Exists(path)) { EV.PostWarningLog(SourceModule, $"save sequence {sequenceName} failed, already exist"); return false; } return SaveSequence(sequenceName, sequenceContent, false); } public bool RenameSequence(string oldName, string newName) { try { if (File.Exists(GenerateSequenceFilePath(SequenceFolder, newName))) { EV.PostWarningLog(SourceModule, $"{newName} already exist, rename failed"); return false; } else { File.Move(GenerateSequenceFilePath(SequenceFolder, oldName), GenerateSequenceFilePath(SequenceFolder, newName)); EV.PostInfoLog(SourceModule, $"sequence {oldName} renamed to {newName}"); } } catch (Exception ex) { LOG.Write(ex); EV.PostWarningLog(SourceModule, $"rename {oldName} failed, " + ex.Message); return false; } return true; } public string GetSequenceFormatXml() { return GetSequenceConfig("/Aitex/TableSequenceFormat"); } internal bool DeleteSequenceFolder(string folderName) { try { Directory.Delete(PathManager.GetRecipeDir() + SequenceFolder + "\\" + folderName, true); EV.PostInfoLog(SourceModule, "Folder " + folderName + "deleted"); } catch (Exception ex) { LOG.Write(ex, "delete sequence folder exception"); EV.PostWarningLog(SourceModule, $"can not delete folder {folderName}, {ex.Message}"); return false; } return true; } internal bool CreateSequenceFolder(string folderName) { try { Directory.CreateDirectory(PathManager.GetRecipeDir() + SequenceFolder + "\\" + folderName); EV.PostInfoLog(SourceModule, "Folder " + folderName + "created"); } catch (Exception ex) { LOG.Write(ex, "sequence folder create exception"); EV.PostWarningLog(SourceModule, $"can not create folder {folderName}, {ex.Message}"); return false; } return true; } internal bool RenameSequenceFolder(string oldName, string newName) { try { string oldPath = PathManager.GetRecipeDir() + SequenceFolder + "\\" + oldName; string newPath = PathManager.GetRecipeDir() + SequenceFolder + "\\" + newName; Directory.Move(oldPath, newPath); EV.PostInfoLog(SourceModule, $"rename folder from {oldName} to {newName}"); } catch (Exception ex) { LOG.Write(ex, "rename sequence folder failed"); EV.PostWarningLog(SourceModule, $"can not rename folder {oldName}, {ex.Message}"); return false; } return true; } public string GetXmlSequenceList(string chamberId) { XmlDocument doc = new XmlDocument(); DirectoryInfo curFolderInfo = new DirectoryInfo(PathManager.GetRecipeDir() + SequenceFolder + "\\"); doc.AppendChild(GenerateSequenceList(chamberId, curFolderInfo, doc)); return doc.OuterXml; } XmlElement GenerateSequenceList(string chamberId, DirectoryInfo currentDir, XmlDocument doc) { int trimLength = (PathManager.GetRecipeDir() + SequenceFolder + "\\").Length; XmlElement folderEle = doc.CreateElement("Folder"); folderEle.SetAttribute("Name", currentDir.FullName.Substring(trimLength)); DirectoryInfo[] dirInfos = currentDir.GetDirectories(); foreach (DirectoryInfo dirInfo in dirInfos) { folderEle.AppendChild(GenerateSequenceList(chamberId, dirInfo, doc)); } FileInfo[] fileInfos = currentDir.GetFiles("*.seq"); foreach (FileInfo fileInfo in fileInfos) { XmlElement fileNd = doc.CreateElement("File"); string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ; fileStr = fileStr.Substring(0, fileStr.LastIndexOf(".")); fileNd.SetAttribute("Name", fileStr); folderEle.AppendChild(fileNd); } return folderEle; } #endregion public List GetFileNodeParameterListByPath(string chamberId) { List files = new List(); var baseFolderPath = getRecipeDirPath(chamberId); DirectoryInfo curFolderInfo = new DirectoryInfo(baseFolderPath); FileNodeItem nodeItem = new FileNodeItem(); nodeItem.IsFile = false; GenerateFileNodeParameterList(chamberId, curFolderInfo, nodeItem); files.Add(nodeItem); return files; } FileNodeItem GenerateFileNodeParameterList(string chamberId, DirectoryInfo currentDir, FileNodeItem nodeItem) { int trimLength = getRecipeDirPath(chamberId).Length; DirectoryInfo[] dirInfos = currentDir.GetDirectories(); foreach (DirectoryInfo dirInfo in dirInfos) { FileNodeItem subFileNodeItem = new FileNodeItem(); subFileNodeItem.IsFile = false; subFileNodeItem.PrefixPath = chamberId; subFileNodeItem.Name = dirInfo.Name; var fullStr = dirInfo.FullName.Substring(dirInfo.FullName.IndexOf(chamberId), dirInfo.FullName.Length - dirInfo.FullName.IndexOf(chamberId)); subFileNodeItem.FullPath = fullStr;// $"{chamberId}\\{dirInfo.Name}"; nodeItem.Files.Add(subFileNodeItem); GenerateFileNodeParameterList(chamberId, dirInfo, subFileNodeItem); } FileInfo[] fileInfos = currentDir.GetFiles("*.rcp"); foreach (FileInfo fileInfo in fileInfos) { string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ; FileNodeItem subNodeItem = new FileNodeItem(); subNodeItem.Name = fileInfo.Name.Replace(".rcp", ""); if (!string.IsNullOrEmpty(currentDir.Name) && (currentDir.FullName.IndexOf(chamberId)+ chamberId.Length + 1 != currentDir.FullName.Length)) { subNodeItem.FullPath = $"{currentDir.Name}\\{subNodeItem.Name}"; } else { subNodeItem.FullPath = subNodeItem.Name; } subNodeItem.PrefixPath = chamberId; subNodeItem.IsFile = true; ReadFileSetFileNode(chamberId, subNodeItem.FullPath, subNodeItem); nodeItem.Files.Add(subNodeItem); } return nodeItem; } public string LoadRecipeByFullPathForFA(string fullPath) { string rcp = string.Empty; try { var dir = string.Format("{0}{1}.rcp", PathManager.GetRecipeDir(), fullPath); //_IsURecipe = false; using (StreamReader fs = new StreamReader(dir)) { rcp = fs.ReadToEnd(); fs.Close(); } } catch (Exception ex) { try { using (StreamReader fs = new StreamReader(fullPath)) { rcp = fs.ReadToEnd(); fs.Close(); //_IsURecipe = true; } } catch { LOG.Write(ex, $"load recipe file failed, {fullPath}"); rcp = string.Empty; }; } return rcp; } List GenerateRecipeNameList(string chamberId, DirectoryInfo currentDir, XmlDocument doc, bool includingUsedRecipe) { int trimLength = getRecipeDirPath(chamberId).Length; XmlElement folderEle = doc.CreateElement("Folder"); folderEle.SetAttribute("Name", currentDir.FullName.Substring(trimLength)); List namelist = new List(); DirectoryInfo[] dirInfos = currentDir.GetDirectories(); foreach (DirectoryInfo dirInfo in dirInfos) { if (!includingUsedRecipe && dirInfo.Name == "HistoryRecipe") continue; folderEle.AppendChild(GenerateRecipeList(chamberId, dirInfo, doc, includingUsedRecipe)); FileInfo[] tempFileInfos = dirInfo.GetFiles("*.rcp"); foreach (FileInfo fileInfo in tempFileInfos) { XmlElement fileNd = doc.CreateElement("File"); string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ; fileStr = fileStr.Substring(0, fileStr.LastIndexOf(".")); namelist.Add(chamberId + "\\" + fileStr); } } FileInfo[] fileInfos = currentDir.GetFiles("*.rcp"); foreach (FileInfo fileInfo in fileInfos) { XmlElement fileNd = doc.CreateElement("File"); string fileStr = fileInfo.FullName.Substring(trimLength).TrimStart(new char[] { '\\' }); ; fileStr = fileStr.Substring(0, fileStr.LastIndexOf(".")); namelist.Add(chamberId + "\\" + fileStr); } return namelist; } public List GetXmlRecipeNmaeList(string chamberId, bool includingUsedRecipe) { XmlDocument doc = new XmlDocument(); var baseFolderPath = getRecipeDirPath(chamberId); DirectoryInfo curFolderInfo = new DirectoryInfo(baseFolderPath); return GenerateRecipeNameList(chamberId, curFolderInfo, doc, includingUsedRecipe); } private void ReadFileSetFileNode(string chamberId, string fileName, FileNodeItem fileNodeItem) { string content = LoadRecipe(chamberId, fileName, false); if ( string.IsNullOrEmpty(content)) { return; } XmlDocument _doc = new XmlDocument(); _doc.LoadXml(content); XmlElement nodeData = _doc.SelectSingleNode($"Aitex/TableRecipeData") as XmlElement; fileNodeItem.Creator = nodeData.GetAttribute("CreatedBy"); fileNodeItem.Description = nodeData.GetAttribute("Description"); fileNodeItem.CreatTime = nodeData.GetAttribute("CreationTime"); fileNodeItem.ReviseTime = nodeData.GetAttribute("LastRevisionTime"); fileNodeItem.Revisor = nodeData.GetAttribute("LastRevisedBy"); fileNodeItem.Permission = nodeData.GetAttribute("Permission"); fileNodeItem.Level = nodeData.GetAttribute("Level"); fileNodeItem.IsChecked = nodeData.GetAttribute("CheckResult") == "Correct"; } } }