diff --git a/Adaptation/.vscode/settings.json b/Adaptation/.vscode/settings.json index 2c955b8..f8fc527 100644 --- a/Adaptation/.vscode/settings.json +++ b/Adaptation/.vscode/settings.json @@ -11,15 +11,20 @@ "ISMTP", "JOBID", "linc", + "lsid", "messa", "messv", "NOPAUSE", "PDFC", "PDSF", "PPID", + "RESIMAPCDE", "SCHED", "SQLMID", + "srpadmin", + "substr", "SUSCEPTOR", + "targ", "TIBCO", "Wafr" ], @@ -40,7 +45,8 @@ "titleBar.activeBackground": "#3d9973", "titleBar.activeForeground": "#e7e7e7", "titleBar.inactiveBackground": "#3d997399", - "titleBar.inactiveForeground": "#e7e7e799" + "titleBar.inactiveForeground": "#e7e7e799", + "commandCenter.border": "#e7e7e799" }, "peacock.color": "#3d9973", "cSpell.enabled": true diff --git a/Adaptation/FileHandlers/TIBCO/FileRead.cs b/Adaptation/FileHandlers/TIBCO/FileRead.cs index 9c8b9e7..0326e64 100644 --- a/Adaptation/FileHandlers/TIBCO/FileRead.cs +++ b/Adaptation/FileHandlers/TIBCO/FileRead.cs @@ -25,6 +25,7 @@ public class FileRead : Shared.FileRead, IFileRead throw new Exception(cellInstanceConnectionName); if (!_IsDuplicator) throw new Exception(cellInstanceConnectionName); + string metrologyFileShare = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, "Metrology.FileShare"); string lsl2SQLConnectionString = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, "ConnectionString.LSL2SQL"); ModelObjectParameterDefinition[] tibcoParameters = GetProperties(cellInstanceConnectionName, modelObjectParameters, "TIBCO."); string tibcoParameterChannel = GetPropertyValue(cellInstanceConnectionName, tibcoParameters, "TIBCO.IFX_CHANNEL"); @@ -32,9 +33,11 @@ public class FileRead : Shared.FileRead, IFileRead string tibcoParameterSubjectPrefix = GetPropertyValue(cellInstanceConnectionName, tibcoParameters, "TIBCO.IFX_SUBJECT_PREFIX"); string tibcoParameterConfigurationLocation = GetPropertyValue(cellInstanceConnectionName, tibcoParameters, "TIBCO.IFX_CONFIGURATION_LOCATION"); string tibcoParameterConfigurationLocationCopy = GetPropertyValue(cellInstanceConnectionName, tibcoParameters, "TIBCO.IFX_CONFIGURATION_LOCATION_LOCAL_COPY"); + if (!Directory.Exists(metrologyFileShare)) + throw new Exception($"Unable to access file-share <{metrologyFileShare}>"); if (_IsEAFHosted) { - Transport.Main.Initialize(smtp, cellInstanceName, fileConnectorConfiguration, lsl2SQLConnectionString); + Transport.Main.Initialize(smtp, cellInstanceName, fileConnectorConfiguration, lsl2SQLConnectionString, metrologyFileShare); if (!string.IsNullOrEmpty(fileConnectorConfiguration.SourceFileLocation)) _ = Transport.Main.Setup(useSleep: true, setIfxTransport: true, tibcoParameterChannel, tibcoParameterSubjectPrefix, tibcoParameterConfigurationLocation, tibcoParameterConfigurationLocationCopy, tibcoParameterSubject); else diff --git a/Adaptation/FileHandlers/TIBCO/Transport/Job.cs b/Adaptation/FileHandlers/TIBCO/Transport/Job.cs index 9d1bc7c..b7b5cc7 100644 --- a/Adaptation/FileHandlers/TIBCO/Transport/Job.cs +++ b/Adaptation/FileHandlers/TIBCO/Transport/Job.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data.SqlClient; +using System.IO; using System.Linq; using System.Text; using System.Text.Json; @@ -13,6 +14,7 @@ public class Job public string AutomationMode { get; } public string BasicType { get; } + public string EpiLayer { get; } public string Equipment { get; } public string JobName { get; } public string LotName { get; } @@ -28,17 +30,19 @@ public class Job public DateTime DateTime { get; } public List Items { get; } - public Job(string lsl2SQLConnectionString, string mid) + public Job(string lsl2SQLConnectionString, string metrologyFileShare, string mid) { + const int zero = 0; Items = new List(); - if (string.IsNullOrEmpty(mid) || mid[0] != '{' || mid[mid.Length - 1] != '}' || !mid.Contains("\"Si\"")) + if (string.IsNullOrEmpty(mid) || mid[zero] != '{' || mid[mid.Length - 1] != '}' || !mid.Contains("\"Si\"")) IsAreaSi = false; else { + int rds; string psn; - int rds = 0; string lotName; string reactor; + string epiLayer; string basicType; const string hyphen = "-"; Input input = JsonSerializer.Deserialize(mid); @@ -49,62 +53,22 @@ public class Job DateTime = DateTime.Now; else DateTime = new DateTime(sequence); - string[] segments = Regex.Split(input.MID, @"[^0-9']"); - if (segments.Length < 3 || (segments.Length > 1 && !int.TryParse(segments[1], out rds))) - { - psn = string.Empty; - reactor = string.Empty; - } - else if (rds is < 100000 or > 100000000) - { - psn = string.Empty; - reactor = string.Empty; - } + if (input.MID.Length is not 2 and not 3) + (psn, rds, reactor) = Get(input); else - { - psn = segments[2]; - reactor = segments[0]; - } + (psn, rds, reactor) = Get(metrologyFileShare, input); AutomationMode = string.Concat(DateTime.Ticks, ".", input.MesEntity); Equipment = input.MesEntity; JobName = DateTime.Ticks.ToString(); - if (rds is < 100000 or > 100000000) + if (!IsValid(rds)) + (basicType, epiLayer, lotName, psn, reactor) = Get(lsl2SQLConnectionString, psn, rds, reactor); + else { basicType = hyphen; lotName = input.MID; + epiLayer = "1"; } - else - { - lotName = rds.ToString(); - string json = GetRunJson(lsl2SQLConnectionString, rds); - if (string.IsNullOrEmpty(json)) - basicType = hyphen; - else - { - Run[] runs; - try - { runs = JsonSerializer.Deserialize(json); } - catch (Exception) - { runs = Array.Empty(); } - if (!runs.Any()) - basicType = hyphen; - else - { - if (string.IsNullOrEmpty(reactor)) - reactor = runs[0].REACTOR.ToString(); - if (string.IsNullOrEmpty(psn)) - psn = runs[0].PS_NO; - string loadLockSide = runs[0].LOAD_LOCK_SIDE; - string loadLockSideFull = loadLockSide switch - { - "L" => "Left", - "R" => "Right", - _ => loadLockSide, - }; - basicType = $"{loadLockSideFull} - {runs[0].REACTOR_TYPE}"; - } - } - } + EpiLayer = epiLayer; BasicType = basicType; LotName = lotName; PackageName = hyphen; //WAFER_ID WaferLot @@ -118,70 +82,129 @@ public class Job } } + private static bool IsValid(int rds) => rds is < 100000 or > 100000000; + + private static (string, int, string) Get(Input input) + { + int rds; + string psn; + string reactor; + const int zero = 0; + string[] segments = Regex.Split(input.MID, @"[^0-9']"); + if (segments.Length < 3) + rds = 0; + else + _ = int.TryParse(segments[1], out rds); + if (IsValid(rds)) + { + psn = string.Empty; + reactor = string.Empty; + } + else + { + psn = segments[2]; + reactor = segments[zero]; + } + return new(psn, rds, reactor); + } + + private static (string, int, string) Get(string metrologyFileShare, Input input) + { + int rds = 0; + string psn; + string reactor; + string[] lines; + string moveFile; + psn = string.Empty; + reactor = string.Empty; + string usedDirectory = Path.Combine(metrologyFileShare, "Used"); + if (!Directory.Exists(metrologyFileShare)) + throw new Exception($"Unable to access file-share <{metrologyFileShare}>"); + if (!Directory.Exists(usedDirectory)) + _ = Directory.CreateDirectory(usedDirectory); + string[] files = Directory.GetFiles(metrologyFileShare, $"*-{input.MID}.rsv", SearchOption.TopDirectoryOnly); + foreach (string file in files.OrderByDescending(l => new FileInfo(l).LastWriteTime)) + { + lines = File.ReadAllLines(file); + foreach (string line in lines) + { + if (string.IsNullOrEmpty(line)) + continue; + if (!int.TryParse(line, out rds) || IsValid(rds)) + continue; + break; + } + if (rds != 0) + { + moveFile = Path.Combine(usedDirectory, Path.GetFileName(file)); + if (File.Exists(moveFile)) + File.Delete(file); + else + File.Move(file, moveFile); + break; + } + } + return new(psn, rds, reactor); + } + private static string GetRunJson(string lsl2SQLConnectionString, int rds) { string result; object scalar = null; StringBuilder sql = new(); - _ = sql.Append(" SELECT "). - Append(" RDS_NO, "). - Append(" WO_NO, "). - Append(" WO_STEP, "). - Append(" CASS_NO, "). - Append(" REACTOR, "). - Append(" VER_WFR_CNT, "). - Append(" LOAD_WFR_CNT, "). - Append(" ENTER_BY, "). - Append(" ENTER_DTM, "). - Append(" VER_SIG, "). - Append(" VER_SIG_DTM, "). - Append(" PRE_SIG, "). - Append(" PRE_SIG_DTM, "). - Append(" LOAD_SIG, "). - Append(" LOAD_SIG_DTM, "). - Append(" WFR_SIG, "). - Append(" WFR_SIG_DTM, "). - Append(" UNLOAD_SIG, "). - Append(" UNLOAD_SIG_DTM, "). - Append(" POST_SIG, "). - Append(" POST_SIG_DTM, "). - Append(" FINAL_SIG, "). - Append(" FINAL_SIG_DTM, "). - Append(" SCHED_DT, "). - Append(" REACT_IDLE_TIME, "). - Append(" SHIFT, "). - Append(" LOAD_LOCK_SIDE, "). - Append(" ADE_READ, "). - Append(" INJECTORS, "). - Append(" TUBE_ID, "). - Append(" TUBE_GRADE, "). - Append(" SUSCEPTOR_ID, "). - Append(" SUPP_INST, "). - Append(" SUPP_ENTRY_ID, "). - Append(" SUPP_ENTRY_DTM, "). - Append(" SUPP_SIG, "). - Append(" SUPP_SIG_DTM, "). - Append(" REACT_ACT_ESC_DTM, "). - Append(" SCHED_WFR_QTY, "). - Append(" CURR_WFR_CNT, "). - Append(" CURR_WFR_CNT_REJ, "). - Append(" CUST_NAME, "). - Append(" CUST_NO, "). - Append(" LOT_NO, "). - Append(" PART_NO, "). - Append(" PS_NO, "). - Append(" REACTOR_TYPE, "). - Append(" RECIPE_NAME, "). - Append(" RECIPE_NO, "). - Append(" SPEC_TYPE, "). - Append(" WFR_UNLOAD_DAYS, "). - Append(" WFR_UNLOAD_NIGHTS, "). - Append(" WFR_UNLOAD_QTY, "). - Append(" CASS_ID_SAP, "). - Append(" REACT_TOOL_ID "). - Append(" FROM [LSL2SQL].[dbo].[REACT_RUN] "). - Append(" WHERE RDS_NO = '").Append(rds).Append("' "). - Append(" FOR JSON PATH "); + _ = sql.Append(" select "). + Append(" qa.rds_no "). + Append(" , qa.max_rds_layer_keys_mv_no "). + Append(" , qa.max_part_no "). + Append(" , substring(max_part_no, 0, len(max_part_no)) max_part_no_substr_0 "). + Append(" , substring(max_part_no, 1, len(max_part_no)) max_part_no_substr_1 "). + Append(" , rr.part_no "). + Append(" , rr.reactor "). + Append(" , rr.ps_no "). + Append(" , rr.load_lock_side "). + Append(" , rr.reactor_type "). + Append(" , rr.recipe_name "). + Append(" , rr.recipe_no "). + Append(" , rr.spec_type "). + Append(" , react_tool_id "). + Append(" , epi_layer "). + Append(" , epi_step "). + Append(" , epi_step_lsid "). + Append(" , epi_dopant "). + Append(" , epi_thick_min "). + Append(" , epi_thick_max "). + Append(" , epi_thick_targ "). + Append(" , epi_res_min "). + Append(" , epi_res_max "). + Append(" , epi_res_targ "). + Append(" from ( "). + Append(" select top (1000) "). + Append(" rds_no "). + Append(" , ( "). + Append(" select max(mv_no) "). + Append(" from lsl2sql.dbo.rds_rds_layer_keys "). + Append(" where seq = rds_no "). + Append(" ) max_rds_layer_keys_mv_no "). + Append(" , case when part_no != '' "). + Append(" then part_no "). + Append(" else "). + Append(" ( "). + Append(" select max(part_no) "). + Append(" from lsl2sql.dbo.react_run b "). + Append(" where b.ps_no = qa.ps_no "). + Append(" ) "). + Append(" end max_part_no "). + Append(" from lsl2sql.dbo.react_run qa "). + Append(" where rds_no = '").Append(rds).Append("' "). + Append(" ) as qa "). + Append(" inner join lsl2sql.dbo.react_run rr "). + Append(" on qa.rds_no = rr.rds_no "). + Append(" left join lsl2sql.dbo.epi_part_layer_spec es "). + Append(" on max_part_no = epi_pn "). + Append(" or substring(max_part_no, 0, len(max_part_no)) = epi_pn "). + Append(" or substring(max_part_no, 1, len(max_part_no)) = epi_pn "). + Append(" order by epi_layer "). + Append(" for json path "); try { using SqlConnection sqlConnection = new(lsl2SQLConnectionString); @@ -199,4 +222,63 @@ public class Job return result; } + private static (string, string, string, string, string) Get(string lsl2SQLConnectionString, string psn, int rds, string reactor) + { + string lotName; + string epiLayer; + string basicType; + const int zero = 0; + const string hyphen = "-"; + lotName = rds.ToString(); + string json = GetRunJson(lsl2SQLConnectionString, rds); + if (string.IsNullOrEmpty(json)) + { + epiLayer = "1"; + basicType = hyphen; + } + else + { + Run[] runs; + try + { runs = JsonSerializer.Deserialize(json); } + catch (Exception) + { runs = Array.Empty(); } + if (!runs.Any()) + { + epiLayer = "1"; + basicType = hyphen; + } + else + { + if (string.IsNullOrEmpty(reactor)) + reactor = runs[zero].Reactor.ToString(); + if (string.IsNullOrEmpty(psn)) + psn = runs[zero].PSN; + string loadLockSide = runs[zero].LoadLockSide; + string loadLockSideFull = loadLockSide switch + { + "L" => "Left", + "R" => "Right", + _ => loadLockSide, + }; + basicType = $"{loadLockSideFull} - {runs[zero].ReactorType}"; + int maxRdsLayerKeysMvNo = runs[zero].MaxRdsLayerKeysMvNo; + if (maxRdsLayerKeysMvNo == 1) + epiLayer = "1"; + else + { + epiLayer = runs[zero].EpiLayer; + foreach (Run run in runs) + { + if (run.EpiThickMin is null || run.EpiThickMax is null) + continue; + if (run.EpiResMin is null || run.EpiResMax is null) + continue; + } + } + } + } + return new(basicType, epiLayer, lotName, psn, reactor); + } + } \ No newline at end of file diff --git a/Adaptation/FileHandlers/TIBCO/Transport/Main.cs b/Adaptation/FileHandlers/TIBCO/Transport/Main.cs index b7c2415..6ab9b95 100644 --- a/Adaptation/FileHandlers/TIBCO/Transport/Main.cs +++ b/Adaptation/FileHandlers/TIBCO/Transport/Main.cs @@ -15,15 +15,17 @@ internal partial class Main private static ISMTP _SMTP; private static object _IfxTransport; private static string _CellInstanceName; + private static string _MetrologyFileShare; private static string _LSL2SQLConnectionString; private static string _TibcoParameterSubjectPrefix; private static FileConnectorConfiguration _FileConnectorConfiguration; - internal static void Initialize(ISMTP smtp, string cellInstanceName, FileConnectorConfiguration fileConnectorConfiguration, string lsl2SQLConnectionString) + internal static void Initialize(ISMTP smtp, string cellInstanceName, FileConnectorConfiguration fileConnectorConfiguration, string lsl2SQLConnectionString, string metrologyFileShare) { _SMTP = smtp; _IfxTransport = null; _CellInstanceName = cellInstanceName; + _MetrologyFileShare = metrologyFileShare; _TibcoParameterSubjectPrefix = string.Empty; _LSL2SQLConnectionString = lsl2SQLConnectionString; _FileConnectorConfiguration = fileConnectorConfiguration; @@ -125,18 +127,18 @@ internal partial class Main jobDoc.Add("LastUpdateUser", "-"); jobDoc.Add(nameof(Job.ProcessType), job.ProcessType); //Key.Process_JobId jobDoc.Add(nameof(Job.StateModel), job.StateModel); - jobDoc.Add("Status", "-"); + jobDoc.Add("Status", "-"); //Key.Info lotDoc.Add(nameof(Job.BasicType), job.BasicType); //Key.BasicType lotDoc.Add("IsActive", true); lotDoc.Add(nameof(Job.LotName), job.LotName); //Key.MID - lotDoc.Add("LotState", "-"); + lotDoc.Add("LotState", "-"); //Key.Layer2 lotDoc.Add(nameof(Job.PackageName), job.PackageName); //Key.WaferId lotDoc.Add(nameof(Job.ProcessSpecName), job.ProcessSpecName); //Key.Chamber lotDoc.Add(nameof(Job.ProductName), job.ProductName); //Key.Product lotDoc.Add(nameof(Job.Qty), job.Qty); lotDoc.Add("Qty2", "-"); //Key.Sequence recipeDoc.Add(nameof(Job.RecipeName), job.RecipeName); //Key.PPID - lotDoc.Add("SpecName", "-"); //Key.Info + lotDoc.Add("SpecName", job.EpiLayer); //Key.Layer foreach (Item item in job.Items) { itemDoc = new IfxDoc(); @@ -182,7 +184,7 @@ internal partial class Main if (!subject.Contains(_TibcoParameterSubjectPrefix)) throw new Exception("Invalid Subject"); mid = GetJobsMID(envelopeDocument); - Job job = new(_LSL2SQLConnectionString, mid); + Job job = new(_LSL2SQLConnectionString, _MetrologyFileShare, mid); if (job.IsAreaSi) { IfxDoc sendReply = GetJobsReply(job); diff --git a/Adaptation/FileHandlers/TIBCO/Transport/Run.cs b/Adaptation/FileHandlers/TIBCO/Transport/Run.cs index d7134b5..8ccba14 100644 --- a/Adaptation/FileHandlers/TIBCO/Transport/Run.cs +++ b/Adaptation/FileHandlers/TIBCO/Transport/Run.cs @@ -1,68 +1,80 @@ +using System.Text.Json.Serialization; + namespace Adaptation.FileHandlers.TIBCO.Transport; public class Run { - public long RDS_NO { get; set; } - public long WO_NO { get; set; } - public int WO_STEP { get; set; } - public int CASS_NO { get; set; } - public int REACTOR { get; set; } - public int VER_WFR_CNT { get; set; } - public int LOAD_WFR_CNT { get; set; } - public string ENTER_BY { get; set; } - public string ENTER_DTM { get; set; } - public string VER_SIG { get; set; } - public string VER_SIG_DTM { get; set; } - public string PRE_SIG { get; set; } - public string PRE_SIG_DTM { get; set; } - public string LOAD_SIG { get; set; } - public string LOAD_SIG_DTM { get; set; } - public string WFR_SIG { get; set; } - public string WFR_SIG_DTM { get; set; } - public string UNLOAD_SIG { get; set; } - public string UNLOAD_SIG_DTM { get; set; } - public string POST_SIG { get; set; } - public string POST_SIG_DTM { get; set; } - public string FINAL_SIG { get; set; } - public string FINAL_SIG_DTM { get; set; } - public string SCHED_DT { get; set; } - // public string SPECIAL_INST { get; set; } - public double REACT_IDLE_TIME { get; set; } - public int SHIFT { get; set; } - public string LOAD_LOCK_SIDE { get; set; } - public string ADE_READ { get; set; } - public string INJECTORS { get; set; } - public string TUBE_ID { get; set; } - public int TUBE_GRADE { get; set; } - public string SUSCEPTOR_ID { get; set; } - public string SUPP_INST { get; set; } - public string SUPP_ENTRY_ID { get; set; } - public string SUPP_ENTRY_DTM { get; set; } - public string SUPP_SIG { get; set; } - public string SUPP_SIG_DTM { get; set; } - public string REACT_ACT_ESC_DTM { get; set; } - public int SCHED_WFR_QTY { get; set; } - // public string VER_COMMENT { get; set; } - // public string LOAD_COMMENT { get; set; } - // public string UNLOAD_COMMENT { get; set; } - // public string FINAL_COMMENT { get; set; } - public int CURR_WFR_CNT { get; set; } - public int CURR_WFR_CNT_REJ { get; set; } - public string CUST_CAPTIVE { get; set; } - public string CUST_NAME { get; set; } - public string CUST_NO { get; set; } - public string LOT_NO { get; set; } - public string PART_NO { get; set; } - public string PS_NO { get; set; } - public string REACTOR_TYPE { get; set; } - public string RECIPE_NAME { get; set; } - public int RECIPE_NO { get; set; } - public string SPEC_TYPE { get; set; } - public int WFR_UNLOAD_DAYS { get; set; } - public int WFR_UNLOAD_NIGHTS { get; set; } - public int WFR_UNLOAD_QTY { get; set; } - public string CASS_ID_SAP { get; set; } - public string REACT_TOOL_ID { get; set; } + [JsonPropertyName("rds_no")] + public int RdsNo { get; set; } + + [JsonPropertyName("max_rds_layer_keys_mv_no")] + public int MaxRdsLayerKeysMvNo { get; set; } + + [JsonPropertyName("max_part_no")] + public string MaxPartNo { get; set; } + + [JsonPropertyName("max_part_no_substr_0")] + public string MaxPartNoSubstr0 { get; set; } + + [JsonPropertyName("max_part_no_substr_1")] + public string MaxPartNoSubstr1 { get; set; } + + [JsonPropertyName("part_no")] + public string PartNo { get; set; } + + [JsonPropertyName("reactor")] + public int Reactor { get; set; } + + [JsonPropertyName("ps_no")] + public string PSN { get; set; } + + [JsonPropertyName("load_lock_side")] + public string LoadLockSide { get; set; } + + [JsonPropertyName("reactor_type")] + public string ReactorType { get; set; } + + [JsonPropertyName("recipe_name")] + public string RecipeName { get; set; } + + [JsonPropertyName("recipe_no")] + public int RecipeNo { get; set; } + + [JsonPropertyName("spec_type")] + public string SpecType { get; set; } + + [JsonPropertyName("react_tool_id")] + public string ReactToolId { get; set; } + + [JsonPropertyName("epi_layer")] + public string EpiLayer { get; set; } + + [JsonPropertyName("epi_step")] + public int? EpiStep { get; set; } + + [JsonPropertyName("epi_step_lsid")] + public string EpiStepLsid { get; set; } + + [JsonPropertyName("epi_dopant")] + public string EpiDopant { get; set; } + + [JsonPropertyName("epi_thick_min")] + public double? EpiThickMin { get; set; } + + [JsonPropertyName("epi_thick_max")] + public double? EpiThickMax { get; set; } + + [JsonPropertyName("epi_thick_targ")] + public double? EpiThickTarg { get; set; } + + [JsonPropertyName("epi_res_min")] + public double? EpiResMin { get; set; } + + [JsonPropertyName("epi_res_max")] + public double? EpiResMax { get; set; } + + [JsonPropertyName("epi_res_targ")] + public double? EpiResTarg { get; set; } } \ No newline at end of file diff --git a/Adaptation/FileHandlers/txt/ProcessData.cs b/Adaptation/FileHandlers/txt/ProcessData.cs index 9fbefac..754cbec 100644 --- a/Adaptation/FileHandlers/txt/ProcessData.cs +++ b/Adaptation/FileHandlers/txt/ProcessData.cs @@ -478,8 +478,11 @@ public class ProcessData : IProcessData } else { + employee = string.Empty; // Remove illegal characters \/:*?"<>| found in the Lot. lot = Regex.Replace(text, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0]; + if (lot.StartsWith("1T") || lot.StartsWith("1t")) + lot = lot.Substring(2); string[] segments = lot.Split('-'); if (segments.Length == 0) reactor = defaultReactor; @@ -497,11 +500,7 @@ public class ProcessData : IProcessData if (segments.Length <= 2) psn = defaultPSN; else - psn = segments[2]; - if (segments.Length <= 3) - employee = string.Empty; - else - employee = segments[3]; + psn = segments[2].Split('.')[0]; } result = new(employee, lot, psn, rds, reactor); return result; diff --git a/Adaptation/Infineon/Monitoring/MonA/ExtWebClient.cs b/Adaptation/Infineon/Monitoring/MonA/ExtWebClient.cs new file mode 100644 index 0000000..7e1ffe0 --- /dev/null +++ b/Adaptation/Infineon/Monitoring/MonA/ExtWebClient.cs @@ -0,0 +1,20 @@ +using System; +using System.Net; + +namespace Infineon.Monitoring.MonA; + +#nullable disable +#pragma warning disable SYSLIB0014 + +public class ExtWebClient : WebClient +{ + protected override WebRequest GetWebRequest(Uri address) + { + WebRequest webRequest = base.GetWebRequest(address); + if (webRequest != null) + webRequest.PreAuthenticate = PreAuthenticate; + return webRequest; + } + + public bool PreAuthenticate { get; set; } +} \ No newline at end of file diff --git a/Adaptation/Infineon/Monitoring/MonA/IMonIn.cs b/Adaptation/Infineon/Monitoring/MonA/IMonIn.cs new file mode 100644 index 0000000..6552d47 --- /dev/null +++ b/Adaptation/Infineon/Monitoring/MonA/IMonIn.cs @@ -0,0 +1,167 @@ +using System; + +namespace Infineon.Monitoring.MonA; + +public interface IMonIn +{ + string SendStatus(string site, string resource, string stateName, State state); + + string SendStatus( + string site, + DateTime timeStamp, + string resource, + string stateName, + State state); + + string SendStatus( + string site, + string resource, + string stateName, + State state, + string description); + + string SendStatus( + string site, + DateTime timeStamp, + string resource, + string stateName, + State state, + string description); + + string SendStatus( + string site, + string resource, + string subresource, + string stateName, + State state); + + string SendStatus( + string site, + DateTime timeStamp, + string resource, + string subresource, + string stateName, + State state); + + string SendStatus( + string site, + string resource, + string subresource, + string stateName, + State state, + string description); + + string SendStatus( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string stateName, + State state, + string description); + + string SendPerformanceMessage( + string site, + string resource, + string performanceName, + double value); + + string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string performanceName, + double value); + + string SendPerformanceMessage( + string site, + string resource, + string performanceName, + double value, + string description); + + string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string performanceName, + double value, + string description); + + string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string performanceName, + double value, + int? interval); + + string SendPerformanceMessage( + string site, + string resource, + DateTime? timeStamp, + string performanceName, + double value, + string unit); + + string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string performanceName, + double value, + string unit, + int? interval); + + string SendPerformanceMessage( + string site, + string resource, + string subresource, + string performanceName, + double value); + + string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string performanceName, + double value); + + string SendPerformanceMessage( + string site, + string resource, + string subresource, + string performanceName, + double value, + string description); + + string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string performanceName, + double value, + int? interval); + + string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string performanceName, + double value, + string unit); + + string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string performanceName, + double value, + string description, + string unit, + int? interval); +} \ No newline at end of file diff --git a/Adaptation/Infineon/Monitoring/MonA/MonIn.cs b/Adaptation/Infineon/Monitoring/MonA/MonIn.cs new file mode 100644 index 0000000..e9ffce8 --- /dev/null +++ b/Adaptation/Infineon/Monitoring/MonA/MonIn.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Text; + +namespace Infineon.Monitoring.MonA; + +public class MonIn : IMonIn, IDisposable +{ + private static readonly DateTime _Utc1970DateTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + public const string MonInUrl = "http://moninhttp.{0}.infineon.com/input/text"; + private static readonly Dictionary _Instances = new(); + private readonly ExtWebClient _WebClient; + private readonly string _MonInUrl; + private static CultureInfo _CultureInfo; + + public static MonIn GetInstance(string url = "http://moninhttp.{0}.infineon.com/input/text") + { + MonIn instance; + if (_Instances.ContainsKey(url)) + { + instance = _Instances[url]; + } + else + { + lock (_Instances) + { + if (!_Instances.ContainsKey(url)) + { + instance = new MonIn(url); + _Instances.Add(url, instance); + } + else + instance = _Instances[url]; + } + } + return instance; + } + + private MonIn(string url) + { + _WebClient = new ExtWebClient(); + _WebClient.Headers[HttpRequestHeader.ContentType] = "application/text"; + _WebClient.Encoding = Encoding.UTF8; + _CultureInfo = new CultureInfo("en-US"); + _MonInUrl = url; + } + + public void SetBasicAuthentication(string username, string password) + { + _WebClient.PreAuthenticate = true; + _WebClient.Headers[HttpRequestHeader.Authorization] = "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(username + ":" + password)); + } + + public string SendStatus(string site, string resource, string stateName, State state) => SendStatus(site, new DateTime?(), resource, string.Empty, stateName, state, string.Empty); + + public string SendStatus( + string site, + DateTime timeStamp, + string resource, + string stateName, + State state) => SendStatus(site, new DateTime?(timeStamp), resource, string.Empty, stateName, state, string.Empty); + + public string SendStatus( + string site, + string resource, + string stateName, + State state, + string description) => SendStatus(site, new DateTime?(), resource, string.Empty, stateName, state, description); + + public string SendStatus( + string site, + DateTime timeStamp, + string resource, + string stateName, + State state, + string description) => SendStatus(site, new DateTime?(timeStamp), resource, string.Empty, stateName, state, description); + + public string SendStatus( + string site, + string resource, + string subresource, + string stateName, + State state) => SendStatus(site, new DateTime?(), resource, subresource, stateName, state, string.Empty); + + public string SendStatus( + string site, + DateTime timeStamp, + string resource, + string subresource, + string stateName, + State state) => SendStatus(site, new DateTime?(timeStamp), resource, subresource, stateName, state, string.Empty); + + public string SendStatus( + string site, + string resource, + string subresource, + string stateName, + State state, + string description) => SendStatus(site, new DateTime?(), resource, subresource, stateName, state, description); + + public string SendStatus( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string stateName, + State state, + string description) + { + string statusMessage = CreateStatusMessage(site, timeStamp, resource, subresource, stateName, state.ToString(), description); + lock (_WebClient) + return _WebClient.UploadString(string.Format(_MonInUrl, site), statusMessage); + } + + public string SendPerformanceMessage( + string site, + string resource, + string performanceName, + double value) => SendPerformanceMessage(site, new DateTime?(), resource, string.Empty, performanceName, value, string.Empty, string.Empty, new int?()); + + public string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string performanceName, + double value) => SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, string.Empty, string.Empty, new int?()); + + public string SendPerformanceMessage( + string site, + string resource, + string performanceName, + double value, + string description) => SendPerformanceMessage(site, new DateTime?(), resource, string.Empty, performanceName, value, description, string.Empty, new int?()); + + public string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string performanceName, + double value, + string description) => SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, description, string.Empty, new int?()); + + public string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string performanceName, + double value, + int? interval) => SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, string.Empty, string.Empty, interval); + + public string SendPerformanceMessage( + string site, + string resource, + DateTime? timeStamp, + string performanceName, + double value, + string unit) => SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, string.Empty, unit, new int?()); + + public string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string performanceName, + double value, + string unit, + int? interval) => SendPerformanceMessage(site, timeStamp, resource, string.Empty, performanceName, value, string.Empty, unit, interval); + + public string SendPerformanceMessage( + string site, + string resource, + string subresource, + string performanceName, + double value) => SendPerformanceMessage(site, new DateTime?(), resource, subresource, performanceName, value, string.Empty, string.Empty, new int?()); + + public string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string performanceName, + double value) => SendPerformanceMessage(site, timeStamp, resource, subresource, performanceName, value, string.Empty, string.Empty, new int?()); + + public string SendPerformanceMessage( + string site, + string resource, + string subresource, + string performanceName, + double value, + string description) => SendPerformanceMessage(site, new DateTime?(), resource, subresource, performanceName, value, description, string.Empty, new int?()); + + public string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string performanceName, + double value, + int? interval) => SendPerformanceMessage(site, timeStamp, resource, subresource, performanceName, value, string.Empty, string.Empty, interval); + + public string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string performanceName, + double value, + string unit) => SendPerformanceMessage(site, timeStamp, resource, subresource, performanceName, value, string.Empty, unit, new int?()); + + public string SendPerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string performanceName, + double value, + string description, + string unit, + int? interval) + { + string performanceMessage = CreatePerformanceMessage(site, timeStamp, resource, subresource, performanceName, value, description, unit, interval); + lock (_WebClient) + return _WebClient.UploadString(string.Format(_MonInUrl, site), performanceMessage); + } + + private static string CreateStatusMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string stateName, + string state, + string description) + { + StringBuilder stringBuilder = new(); + if (string.IsNullOrEmpty(subresource)) + _ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" {4} \n{5}", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), stateName.Trim(), state.Trim(), description.Trim()); + else + _ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" \"{4}\" {5} \n{6}", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), subresource.Trim(), stateName.Trim(), state.Trim(), description.Trim()); + return stringBuilder.ToString(); + } + + private static string CreatePerformanceMessage( + string site, + DateTime? timeStamp, + string resource, + string subresource, + string performanceName, + double value, + string description, + string unit, + int? interval) + { + StringBuilder stringBuilder = new(); + if (string.IsNullOrEmpty(subresource)) + { + if (unit.Equals(string.Empty) && !interval.HasValue) + _ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" {4} \n{5}", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), performanceName.Trim(), value, description.Trim()); + else + _ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" {4} {5} {{interval={6}, unit={7}}}\n", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), performanceName.Trim(), value, description.Trim(), interval.HasValue ? interval.Value.ToString() : (object)string.Empty, unit.Trim()); + } + else if (unit.Equals(string.Empty) && !interval.HasValue) + _ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" \"{4}\" {5} \n{6}", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), subresource.Trim(), performanceName.Trim(), value, description.Trim()); + else + _ = stringBuilder.AppendFormat(_CultureInfo, "> {0} {1} \"{2}\" \"{3}\" \"{4}\" {5} {6} {{interval={7}, unit={8}}}\n", site.Trim(), timeStamp.HasValue ? GetDateTimeNowAsPosix(timeStamp.Value) : (object)"now", resource.Trim(), subresource.Trim(), performanceName.Trim(), value, description.Trim(), interval.HasValue ? interval.Value.ToString() : (object)string.Empty, unit.Trim()); + return stringBuilder.ToString(); + } + + private static string GetDateTimeNowAsPosix(DateTime timeStamp) + { + if (timeStamp > DateTime.Now) + timeStamp = DateTime.Now; + return ((int)timeStamp.ToUniversalTime().Subtract(_Utc1970DateTime).TotalSeconds).ToString(CultureInfo.InvariantCulture); + } + + public void Dispose() + { + KeyValuePair keyValuePair = new(); + foreach (KeyValuePair instance in _Instances) + { + if (instance.Value == this) + { + keyValuePair = instance; + break; + } + } + _ = _Instances.Remove(keyValuePair.Key); + _WebClient?.Dispose(); + } + +} \ No newline at end of file diff --git a/Adaptation/Infineon/Monitoring/MonA/State.cs b/Adaptation/Infineon/Monitoring/MonA/State.cs new file mode 100644 index 0000000..d6bface --- /dev/null +++ b/Adaptation/Infineon/Monitoring/MonA/State.cs @@ -0,0 +1,11 @@ +namespace Infineon.Monitoring.MonA; + +public enum State +{ + Up, + Ok, + Warning, + Critical, + Down, + Unknown, +} \ No newline at end of file diff --git a/Adaptation/MET08DDUPSP1TBI.Tests.csproj b/Adaptation/MET08DDUPSP1TBI.Tests.csproj index aed9446..25c1f97 100644 --- a/Adaptation/MET08DDUPSP1TBI.Tests.csproj +++ b/Adaptation/MET08DDUPSP1TBI.Tests.csproj @@ -15,6 +15,7 @@ trx + XPlat Code Coverage ../../../../MET08DDUPSP1TBI/05_TestResults/TestResults @@ -62,7 +63,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/Adaptation/_Tests/Shared/AdaptationTesting.cs b/Adaptation/_Tests/Shared/AdaptationTesting.cs index dc062a1..7e7c8cc 100644 --- a/Adaptation/_Tests/Shared/AdaptationTesting.cs +++ b/Adaptation/_Tests/Shared/AdaptationTesting.cs @@ -1250,12 +1250,13 @@ public class AdaptationTesting : ISMTP if (!fileRead.IsDuplicator) { Assert.IsFalse(string.IsNullOrEmpty(extractResult?.Item1)); - Assert.IsTrue(extractResult.Item3.Length > 0, "extractResult Array Length check!"); + Assert.IsNotNull(extractResult.Item3); Assert.IsNotNull(extractResult.Item4); if (!validatePDSF) _ = GetLogisticsColumnsAndBody(fileRead, logistics, extractResult, new(string.Empty, Array.Empty(), Array.Empty())); else { + Assert.IsTrue(extractResult.Item3.Length > 0, "extractResult Array Length check!"); Tuple pdsf = GetLogisticsColumnsAndBody(variables[2], variables[4]); Tuple pdsfNew = GetLogisticsColumnsAndBody(fileRead, logistics, extractResult, pdsf); CompareSave(variables[5], pdsf, pdsfNew); diff --git a/Adaptation/_Tests/Static/Job.cs b/Adaptation/_Tests/Static/Job.cs new file mode 100644 index 0000000..999435f --- /dev/null +++ b/Adaptation/_Tests/Static/Job.cs @@ -0,0 +1,63 @@ +using Adaptation._Tests.Shared; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Diagnostics; +using System.Reflection; + +namespace Adaptation._Tests.Static; + +[TestClass] +public class Job : LoggingUnitTesting, IDisposable +{ + +#pragma warning disable CA2254 +#pragma warning disable IDE0060 + + internal static Job LoggingUnitTesting { get; private set; } + + public Job() : base(testContext: null, declaringType: null) + { + if (LoggingUnitTesting is null) + throw new Exception(); + } + + public Job(TestContext testContext) : base(testContext, new StackFrame().GetMethod().DeclaringType) + { + } + + [ClassInitialize] + public static void ClassInitialize(TestContext testContext) + { + if (LoggingUnitTesting is null) + LoggingUnitTesting = new Job(testContext); + } + + [ClassCleanup()] + public static void ClassCleanup() + { + if (LoggingUnitTesting.Logger is not null) + LoggingUnitTesting.Logger.LogInformation("Cleanup"); + if (LoggingUnitTesting is not null) + LoggingUnitTesting.Dispose(); + } + +#if true + [Ignore] +#endif + [TestMethod] + public void TestJob() + { + FileHandlers.TIBCO.Transport.Job job; + MethodBase methodBase = new StackFrame().GetMethod(); + LoggingUnitTesting.Logger.LogInformation(string.Concat(methodBase.Name, " - Getting configuration")); + string conn = "Data Source=10.95.128.28\\PROD1,53959;Initial Catalog=LSL2SQL;Persist Security Info=True;User ID=srpadmin;Password=;"; + job = new(conn, string.Empty, "00-544481-0000"); + Assert.IsTrue(string.IsNullOrEmpty(job.LotName)); + job = new(conn, string.Empty, "{\"Area\": \"Si\", \"EquipmentType\": \"MET08RESIMAPCDE\", \"MesEntity\": \"CDE4\", \"Sequence\": \"123456789\", \"MID\": \"-544481-\", \"Recipe\": \"Recipe\"}"); + Assert.IsTrue(job.LotName == "544481"); + Assert.IsTrue(job.EpiLayer == "1"); + LoggingUnitTesting.Logger.LogInformation(string.Concat(methodBase.Name, " - Exit")); + } + +} \ No newline at end of file diff --git a/Adaptation/_Tests/Static/txt.cs b/Adaptation/_Tests/Static/txt.cs index c444471..5b04560 100644 --- a/Adaptation/_Tests/Static/txt.cs +++ b/Adaptation/_Tests/Static/txt.cs @@ -56,11 +56,21 @@ public class TXT : LoggingUnitTesting, IDisposable Assert.IsTrue(descriptor.Reactor is "00"); Assert.IsTrue(descriptor.RDS is "123456"); Assert.IsTrue(descriptor.PSN is "0000"); + descriptor = FileHandlers.txt.ProcessData.GetDescriptor("1T123456"); + Assert.IsTrue(descriptor.Reactor is "00"); + Assert.IsTrue(descriptor.RDS is "123456"); + Assert.IsTrue(descriptor.PSN is "0000"); descriptor = FileHandlers.txt.ProcessData.GetDescriptor("MP"); Assert.IsTrue(descriptor.Reactor is "00"); Assert.IsTrue(descriptor.RDS is "000000"); Assert.IsTrue(descriptor.PSN is "0000"); Assert.IsTrue(descriptor.Employee is "MP"); + descriptor = FileHandlers.txt.ProcessData.GetDescriptor("12-123456-1234.2-1"); + Assert.IsTrue(descriptor.Reactor is "12"); + Assert.IsTrue(descriptor.RDS is "123456"); + Assert.IsTrue(descriptor.PSN is "1234"); + // Assert.IsTrue(descriptor.Layer is "2"); + // Assert.IsTrue(descriptor.Zone is "1"); LoggingUnitTesting.Logger.LogInformation(string.Concat(methodBase.Name, " - Exit")); } diff --git a/MET08DDUPSP1TBI.csproj b/MET08DDUPSP1TBI.csproj index 4bbc8d9..f57e82f 100644 --- a/MET08DDUPSP1TBI.csproj +++ b/MET08DDUPSP1TBI.csproj @@ -127,6 +127,12 @@ + + Component + + + +