From d07755c3a02e49bb99f3f90d47a8cef9ce46fb70 Mon Sep 17 00:00:00 2001 From: "phares@iscn5cg20977xq" Date: Mon, 15 Sep 2025 11:37:05 -0700 Subject: [PATCH] Refactor QS408M and PDSF File Handlers - Updated Detail class to include JsonSourceGenerationOptions and JsonSerializable attributes for source generation. - Modified ProcessData class to utilize source generation context for Description deserialization. - Renamed RowSourceGenerationContext to QS408MRowSourceGenerationContext for clarity. - Updated Run class to use QS408MRunSourceGenerationContext for serialization. - Enhanced Description class with source generation attributes. - Refactored FileRead class to use source generation context for Description deserialization. - Added new methods in ProcessDataStandardFormat for JSON element array extraction. - Introduced new PDSF file handler classes: Body, Constant, FileRead, Footer, Header, Row, Run, and Site. - Implemented logic for parsing and handling PDSF data structures. - Added unit tests for PDSF processing to ensure functionality. --- Adaptation/.vscode/launch.json | 39 +--- .../CellInstanceConnectionName.cs | 1 + .../FileHandlers/OpenInsight/FileRead.cs | 12 +- .../FileHandlers/OpenInsight/FromIQS.cs | 60 +----- .../OpenInsightMetrologyViewer/FileRead.cs | 11 +- .../OpenInsightMetrologyViewer/WSRequest.cs | 11 +- .../FileRead.cs | 11 +- Adaptation/FileHandlers/Processed/FileRead.cs | 17 +- Adaptation/FileHandlers/QS408M/Description.cs | 101 ++++++---- Adaptation/FileHandlers/QS408M/Detail.cs | 18 +- Adaptation/FileHandlers/QS408M/ProcessData.cs | 3 +- Adaptation/FileHandlers/QS408M/Row.cs | 2 +- Adaptation/FileHandlers/QS408M/Run.cs | 4 +- Adaptation/FileHandlers/pdsf/Body.cs | 80 ++++++++ Adaptation/FileHandlers/pdsf/Constant.cs | 21 ++ Adaptation/FileHandlers/pdsf/FileRead.cs | 130 ++++++++++++ Adaptation/FileHandlers/pdsf/Footer.cs | 36 ++++ Adaptation/FileHandlers/pdsf/Header.cs | 106 ++++++++++ Adaptation/FileHandlers/pdsf/Row.cs | 63 ++++++ Adaptation/FileHandlers/pdsf/Run.cs | 190 ++++++++++++++++++ Adaptation/FileHandlers/pdsf/Site.cs | 36 ++++ Adaptation/Shared/Duplicator/Description.cs | 13 ++ Adaptation/Shared/FileRead.cs | 6 +- .../Shared/ProcessDataStandardFormat.cs | 31 +++ .../Production/v2.60.0/BIORAD2.cs | 15 +- .../Production/v2.60.0/BIORAD3.cs | 2 - .../Extract/Production/v2.60.0/BIORAD2.cs | 40 ++-- .../Extract/Production/v2.60.0/BIORAD3.cs | 6 - MET08THFTIRQS408M.csproj | 8 + 29 files changed, 869 insertions(+), 204 deletions(-) create mode 100644 Adaptation/FileHandlers/pdsf/Body.cs create mode 100644 Adaptation/FileHandlers/pdsf/Constant.cs create mode 100644 Adaptation/FileHandlers/pdsf/FileRead.cs create mode 100644 Adaptation/FileHandlers/pdsf/Footer.cs create mode 100644 Adaptation/FileHandlers/pdsf/Header.cs create mode 100644 Adaptation/FileHandlers/pdsf/Row.cs create mode 100644 Adaptation/FileHandlers/pdsf/Run.cs create mode 100644 Adaptation/FileHandlers/pdsf/Site.cs diff --git a/Adaptation/.vscode/launch.json b/Adaptation/.vscode/launch.json index f8bf7e8..47404cf 100644 --- a/Adaptation/.vscode/launch.json +++ b/Adaptation/.vscode/launch.json @@ -1,43 +1,10 @@ { "configurations": [ - { - "mode": "debug", - "name": "Go launch file", - "program": "${file}", - "request": "launch", - "type": "go" - }, - { - "name": "node Launch Current Opened File", - "program": "${file}", - "request": "launch", - "type": "node" - }, - { - "cwd": "${workspaceFolder}", - "internalConsoleOptions": "neverOpen", - "name": "Debug File", - "program": "${file}", - "request": "launch", - "stopOnEntry": false, - "type": "bun", - "watchMode": false - }, - { - "cwd": "${workspaceFolder}", - "internalConsoleOptions": "neverOpen", - "name": "Run File", - "noDebug": true, - "program": "${file}", - "request": "launch", - "type": "bun", - "watchMode": false - }, { "name": ".NET Core Attach", - "processId": 32760, + "type": "coreclr", "request": "attach", - "type": "coreclr" + "processId": 2688 } ] -} \ No newline at end of file +} diff --git a/Adaptation/FileHandlers/CellInstanceConnectionName.cs b/Adaptation/FileHandlers/CellInstanceConnectionName.cs index 0133bbe..ef3707e 100644 --- a/Adaptation/FileHandlers/CellInstanceConnectionName.cs +++ b/Adaptation/FileHandlers/CellInstanceConnectionName.cs @@ -21,6 +21,7 @@ public class CellInstanceConnectionName nameof(OpenInsight) => new OpenInsight.FileRead(smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null), nameof(OpenInsightMetrologyViewer) => new OpenInsightMetrologyViewer.FileRead(smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null), nameof(OpenInsightMetrologyViewerAttachments) => new OpenInsightMetrologyViewerAttachments.FileRead(smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null), + nameof(pdsf) => new pdsf.FileRead(smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null), nameof(Processed) => new Processed.FileRead(smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null), nameof(QS408M) => new QS408M.FileRead(smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null), nameof(SPaCe) => new SPaCe.FileRead(smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null), diff --git a/Adaptation/FileHandlers/OpenInsight/FileRead.cs b/Adaptation/FileHandlers/OpenInsight/FileRead.cs index ba72c19..d301bb9 100644 --- a/Adaptation/FileHandlers/OpenInsight/FileRead.cs +++ b/Adaptation/FileHandlers/OpenInsight/FileRead.cs @@ -157,7 +157,7 @@ public class FileRead : Shared.FileRead, IFileRead return results.ToString(); } - private void SaveOpenInsightFile(string reportFullPath, DateTime dateTime, ProcessDataStandardFormat processDataStandardFormat, List descriptions, Test[] tests) + private void SaveOpenInsightFile(string reportFullPath, DateTime dateTime, List descriptions, Test[] tests) { string duplicateFile; bool isDummyRun = false; @@ -201,7 +201,7 @@ public class FileRead : Shared.FileRead, IFileRead else duplicateFile = Path.Combine(duplicateDirectory, $"{$"Viewer {subgroupId}".TrimEnd()} {fileName.Replace("Viewer", string.Empty)}"); string weekOfYear = _Calendar.GetWeekOfYear(_Logistics.DateTimeFromSequence, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); - FromIQS.Save(_OpenInsightApiECDirectory, _Logistics, reportFullPath, processDataStandardFormat, descriptions.First(), subgroupId, weekOfYear); + FromIQS.Save(_OpenInsightApiECDirectory, _Logistics, reportFullPath, descriptions.First(), subgroupId, weekOfYear); } if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) { @@ -214,15 +214,15 @@ public class FileRead : Shared.FileRead, IFileRead private Tuple> GetExtractResult(string reportFullPath, DateTime dateTime) { Tuple> results; - ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + string[] lines = File.ReadAllLines(reportFullPath); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath, lines); _Logistics = new Logistics(reportFullPath, processDataStandardFormat); SetFileParameterLotIDToLogisticsMID(); - JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); - // List descriptions = GetDuplicatorDescriptions(jsonElements); + JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(reportFullPath, lines, processDataStandardFormat); List descriptions = QS408M.ProcessData.GetDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) - SaveOpenInsightFile(reportFullPath, dateTime, processDataStandardFormat, descriptions, tests); + SaveOpenInsightFile(reportFullPath, dateTime, descriptions, tests); results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/OpenInsight/FromIQS.cs b/Adaptation/FileHandlers/OpenInsight/FromIQS.cs index dda3113..525f018 100644 --- a/Adaptation/FileHandlers/OpenInsight/FromIQS.cs +++ b/Adaptation/FileHandlers/OpenInsight/FromIQS.cs @@ -325,74 +325,18 @@ public class FromIQS return new(result, count, commandText); } - private static string GetJson(Logistics logistics, ProcessDataStandardFormat processDataStandardFormat, QS408M.Description description) + internal static void Save(string openInsightApiECDirectory, Logistics logistics, string reportFullPath, QS408M.Description description, long? subGroupId, string weekOfYear) { - string result; - StringBuilder stringBuilder = new(); - var @object = new - { - description.MesEntity, - description.Employee, - description.Layer, - description.PSN, - description.RDS, - description.Reactor, - description.Recipe, - description.Zone, - logistics.DateTimeFromSequence.Ticks - }; - string[] pair; - string safeValue; - string[] segments; - string serializerValue; - foreach (string line in processDataStandardFormat.Logistics) - { - segments = line.Split('\t'); - if (segments.Length < 2) - continue; - segments = segments[1].Split(';'); - _ = stringBuilder.Append('{'); - foreach (string segment in segments) - { - pair = segment.Split('='); - if (pair.Length != 2 || pair[0].Length < 3) - continue; - serializerValue = JsonSerializer.Serialize(pair[1]); - safeValue = serializerValue.Substring(1, serializerValue.Length - 2); - _ = stringBuilder.Append('"').Append(pair[0].Substring(2)).Append('"').Append(':').Append('"').Append(safeValue).Append('"').Append(','); - } - if (stringBuilder.Length > 0) - _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); - _ = stringBuilder.Append('}').Append(','); - } - if (stringBuilder.Length > 0) - _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); - _ = stringBuilder.Append(']').Append('}'); - _ = stringBuilder.Insert(0, ",\"Logistics\":["); - string json = JsonSerializer.Serialize(@object); - _ = stringBuilder.Insert(0, json.Substring(0, json.Length - 1)); - JsonElement? jsonElement = JsonSerializer.Deserialize(stringBuilder.ToString()); - result = jsonElement is null ? "{}" : JsonSerializer.Serialize(jsonElement, new JsonSerializerOptions { WriteIndented = true }); - return result; - } - - internal static void Save(string openInsightApiECDirectory, Logistics logistics, string reportFullPath, ProcessDataStandardFormat processDataStandardFormat, QS408M.Description description, long? subGroupId, string weekOfYear) - { - string checkFile; string fileName = Path.GetFileName(reportFullPath); - string json = GetJson(logistics, processDataStandardFormat, description); string? ecPathRoot = Path.GetPathRoot(openInsightApiECDirectory); bool ecExists = ecPathRoot is not null && Directory.Exists(ecPathRoot); string weekYear = $"{logistics.DateTimeFromSequence:yyyy}_Week_{weekOfYear}"; string ecDirectory = Path.Combine(openInsightApiECDirectory, weekYear, $"-{description.PSN}", $"-{description.Reactor}", $"-{description.RDS}", $"-{subGroupId}"); if (ecExists && !Directory.Exists(ecDirectory)) _ = Directory.CreateDirectory(ecDirectory); - checkFile = Path.Combine(ecDirectory, fileName); + string checkFile = Path.Combine(ecDirectory, fileName); if (ecExists && !File.Exists(checkFile)) File.Copy(reportFullPath, checkFile); - checkFile = Path.Combine(ecDirectory, $"{logistics.DateTimeFromSequence.Ticks}.json"); - if (ecExists && !File.Exists(checkFile)) - File.WriteAllText(checkFile, json); } private static string GetCommandText(string[] iqsCopyValues) diff --git a/Adaptation/FileHandlers/OpenInsightMetrologyViewer/FileRead.cs b/Adaptation/FileHandlers/OpenInsightMetrologyViewer/FileRead.cs index 650e6df..fb821db 100644 --- a/Adaptation/FileHandlers/OpenInsightMetrologyViewer/FileRead.cs +++ b/Adaptation/FileHandlers/OpenInsightMetrologyViewer/FileRead.cs @@ -110,10 +110,10 @@ public class FileRead : Shared.FileRead, IFileRead return results; } - private void SendData(string reportFullPath, DateTime dateTime, List descriptions) + private void SendData(string reportFullPath, DateTime dateTime, JsonElement[] jsonElements, List descriptions) { string checkDirectory; - WSRequest wsRequest = new(this, _Logistics, descriptions); + WSRequest wsRequest = new(this, _Logistics, jsonElements, descriptions); int weekOfYear = _Calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday); string directory = Path.Combine(_OpenInsightMetrologyViewerFileShare, dateTime.Year.ToString(), $"WW{weekOfYear:00}"); checkDirectory = Path.Combine(directory, _Logistics.Sequence.ToString()); @@ -139,14 +139,15 @@ public class FileRead : Shared.FileRead, IFileRead private Tuple> GetExtractResult(string reportFullPath, DateTime dateTime) { Tuple> results; - ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + string[] lines = File.ReadAllLines(reportFullPath); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath, lines); _Logistics = new Logistics(reportFullPath, processDataStandardFormat); SetFileParameterLotIDToLogisticsMID(); - JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); + JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(reportFullPath, lines, processDataStandardFormat); List descriptions = QS408M.ProcessData.GetDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) - SendData(reportFullPath, dateTime, descriptions); + SendData(reportFullPath, dateTime, jsonElements, descriptions); results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/OpenInsightMetrologyViewer/WSRequest.cs b/Adaptation/FileHandlers/OpenInsightMetrologyViewer/WSRequest.cs index f2a0d04..d990b0d 100644 --- a/Adaptation/FileHandlers/OpenInsightMetrologyViewer/WSRequest.cs +++ b/Adaptation/FileHandlers/OpenInsightMetrologyViewer/WSRequest.cs @@ -4,6 +4,7 @@ using Adaptation.Shared.Properties; using System; using System.Collections.Generic; using System.IO; +using System.Text.Json; namespace Adaptation.FileHandlers.OpenInsightMetrologyViewer; @@ -37,7 +38,7 @@ public class WSRequest [Obsolete("For json")] public WSRequest() { } #pragma warning disable IDE0060 - internal WSRequest(IFileRead fileRead, Logistics logistics, List descriptions, string processDataStandardFormat = null) + internal WSRequest(IFileRead fileRead, Logistics logistics, JsonElement[] jsonElements, List descriptions, string processDataStandardFormat = null) #pragma warning restore IDE0060 { Id = -1; @@ -48,10 +49,10 @@ public class WSRequest Details = new List(); //Header { - Batch = x.Lot; + Batch = x.Lot; // different name Cassette = x.Cassette; Date = x.Date; - Op = x.Employee; + Op = x.Employee; // different name Layer = x.Layer; MeanThickness = x.MeanThickness; PSN = x.PSN; @@ -87,14 +88,14 @@ public class WSRequest } } - internal static long GetHeaderId(IFileRead fileRead, Logistics logistics, string openInsightMetrologyViewerAPI, string openInsightMetrologyViewerFileShare, int weekOfYear, WS.Results results, List descriptions) + internal static long GetHeaderId(IFileRead fileRead, Logistics logistics, string openInsightMetrologyViewerAPI, string openInsightMetrologyViewerFileShare, int weekOfYear, WS.Results results, JsonElement[] jsonElements, List descriptions) { long result; if (results is not null && results.HeaderId is not null) result = results.HeaderId.Value; else { - WSRequest wsRequest = new(fileRead, logistics, descriptions); + WSRequest wsRequest = new(fileRead, logistics, jsonElements, descriptions); string directory = Path.Combine(openInsightMetrologyViewerFileShare, logistics.DateTimeFromSequence.Year.ToString(), $"WW{weekOfYear:00}"); (_, WS.Results wsResults) = WS.SendData(openInsightMetrologyViewerAPI, logistics.Sequence, directory, wsRequest); if (wsResults.Success is null || !wsResults.Success.Value) diff --git a/Adaptation/FileHandlers/OpenInsightMetrologyViewerAttachments/FileRead.cs b/Adaptation/FileHandlers/OpenInsightMetrologyViewerAttachments/FileRead.cs index 63127eb..a01aedb 100644 --- a/Adaptation/FileHandlers/OpenInsightMetrologyViewerAttachments/FileRead.cs +++ b/Adaptation/FileHandlers/OpenInsightMetrologyViewerAttachments/FileRead.cs @@ -135,7 +135,7 @@ public class FileRead : Shared.FileRead, IFileRead return result; } - private void PostOpenInsightMetrologyViewerAttachments(List descriptions) + private void PostOpenInsightMetrologyViewerAttachments(JsonElement[] jsonElements, List descriptions) { Shared.Metrology.WS.Results? results; string jobIdDirectory = Path.Combine(Path.GetDirectoryName(_FileConnectorConfiguration.AlternateTargetFolder) ?? throw new Exception(), _Logistics.JobID); @@ -151,7 +151,7 @@ public class FileRead : Shared.FileRead, IFileRead results = wsResults[0]; } int weekOfYear = _Calendar.GetWeekOfYear(_Logistics.DateTimeFromSequence, CalendarWeekRule.FirstDay, DayOfWeek.Sunday); - long headerId = !_IsEAFHosted ? -1 : OpenInsightMetrologyViewer.WSRequest.GetHeaderId(this, _Logistics, _OpenInsightMetrologyViewerAPI, _OpenInsightMetrologyViewerFileShare, weekOfYear, results, descriptions); + long headerId = !_IsEAFHosted ? -1 : OpenInsightMetrologyViewer.WSRequest.GetHeaderId(this, _Logistics, _OpenInsightMetrologyViewerAPI, _OpenInsightMetrologyViewerFileShare, weekOfYear, results, jsonElements, descriptions); string? headerIdDirectory = GetHeaderIdDirectory(headerId); if (string.IsNullOrEmpty(headerIdDirectory)) throw new Exception($"Didn't find header id directory <{headerId}>"); @@ -163,14 +163,15 @@ public class FileRead : Shared.FileRead, IFileRead if (dateTime == DateTime.MinValue) throw new ArgumentNullException(nameof(dateTime)); Tuple> results; - ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + string[] lines = File.ReadAllLines(reportFullPath); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath, lines); _Logistics = new Logistics(reportFullPath, processDataStandardFormat); SetFileParameterLotIDToLogisticsMID(); - JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); + JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(reportFullPath, lines, processDataStandardFormat); List descriptions = QS408M.ProcessData.GetDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) - PostOpenInsightMetrologyViewerAttachments(descriptions); + PostOpenInsightMetrologyViewerAttachments(jsonElements, descriptions); results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); return results; } diff --git a/Adaptation/FileHandlers/Processed/FileRead.cs b/Adaptation/FileHandlers/Processed/FileRead.cs index 1d9fd26..dad3bb2 100644 --- a/Adaptation/FileHandlers/Processed/FileRead.cs +++ b/Adaptation/FileHandlers/Processed/FileRead.cs @@ -108,7 +108,7 @@ public class FileRead : Shared.FileRead, IFileRead return results; } - private void DirectoryMove(string reportFullPath, DateTime dateTime, List descriptions) + private void DirectoryMove(string reportFullPath, DateTime dateTime, JsonElement[] jsonElements, List descriptions) { if (dateTime == DateTime.MinValue) throw new ArgumentNullException(nameof(dateTime)); @@ -122,7 +122,7 @@ public class FileRead : Shared.FileRead, IFileRead throw new Exception("Didn't find directory by logistics sequence"); if (fileInfo.Exists && fileInfo.LastWriteTime < fileInfo.CreationTime) File.SetLastWriteTime(reportFullPath, fileInfo.CreationTime); - OpenInsightMetrologyViewer.WSRequest wsRequest = new(this, _Logistics, descriptions); + OpenInsightMetrologyViewer.WSRequest wsRequest = new(this, _Logistics, jsonElements, descriptions); JsonSerializerOptions jsonSerializerOptions = new() { WriteIndented = true }; string json = JsonSerializer.Serialize(wsRequest, wsRequest.GetType(), jsonSerializerOptions); string directoryName = $"{Path.GetFileName(matchDirectories[0]).Split(new string[] { logisticsSequence }, StringSplitOptions.None)[0]}{_Logistics.DateTimeFromSequence:yyyy-MM-dd_hh;mm_tt_}{DateTime.Now.Ticks - _Logistics.Sequence}"; @@ -166,23 +166,24 @@ public class FileRead : Shared.FileRead, IFileRead private Tuple> GetExtractResult(string reportFullPath, DateTime dateTime) { Tuple> results; - ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + string[] lines = File.ReadAllLines(reportFullPath); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath, lines); _Logistics = new Logistics(reportFullPath, processDataStandardFormat); SetFileParameterLotIDToLogisticsMID(); - JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); + JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(reportFullPath, lines, processDataStandardFormat); List descriptions = QS408M.ProcessData.GetDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); results = new Tuple>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics), tests, jsonElements, new List()); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) - DirectoryMove(reportFullPath, dateTime, descriptions); + DirectoryMove(reportFullPath, dateTime, jsonElements, descriptions); else if (!_IsEAFHosted) { - OpenInsightMetrologyViewer.WSRequest wsRequest = new(this, _Logistics, descriptions); + OpenInsightMetrologyViewer.WSRequest wsRequest = new(this, _Logistics, jsonElements, descriptions); JsonSerializerOptions jsonSerializerOptions = new() { WriteIndented = true }; - string json = JsonSerializer.Serialize(wsRequest, wsRequest.GetType(), jsonSerializerOptions); + string check = JsonSerializer.Serialize(wsRequest, wsRequest.GetType(), jsonSerializerOptions); string jsonFileName = Path.ChangeExtension(reportFullPath, ".json"); string historicalText = File.ReadAllText(jsonFileName); - if (json != historicalText) + if (check != historicalText) throw new Exception("File doesn't match historical!"); } return results; diff --git a/Adaptation/FileHandlers/QS408M/Description.cs b/Adaptation/FileHandlers/QS408M/Description.cs index 8837a9f..258efa0 100644 --- a/Adaptation/FileHandlers/QS408M/Description.cs +++ b/Adaptation/FileHandlers/QS408M/Description.cs @@ -4,72 +4,73 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; +using System.Text.Json.Serialization; namespace Adaptation.FileHandlers.QS408M; public class Description : IDescription, Shared.Properties.IDescription { - public int Test { get; set; } - public int Count { get; set; } - public int Index { get; set; } + [JsonPropertyName("EventId")] public int Test { get; set; } + [JsonPropertyName("Count")] public int Count { get; set; } + [JsonPropertyName("Index")] public int Index { get; set; } // public string EventName { get; set; } public string NullData { get; set; } public string JobID { get; set; } public string Sequence { get; set; } - public string MesEntity { get; set; } + [JsonPropertyName("MesEntity")] public string MesEntity { get; set; } public string ReportFullPath { get; set; } public string ProcessJobID { get; set; } public string MID { get; set; } // - public string Date { get; set; } - public string Employee { get; set; } + [JsonPropertyName("DateTime")] public string Date { get; set; } + [JsonPropertyName("Operator")] public string Employee { get; set; } public string Lot { get; set; } - public string PSN { get; set; } - public string Reactor { get; set; } - public string Recipe { get; set; } + [JsonPropertyName("PSN")] public string PSN { get; set; } + [JsonPropertyName("Reactor")] public string Reactor { get; set; } + [JsonPropertyName("Recipe")] public string Recipe { get; set; } // - public string Cassette { get; set; } + [JsonPropertyName("Cassette")] public string Cassette { get; set; } public string HeaderUniqueId { get; set; } - public string Layer { get; set; } - public string PassFail { get; set; } - public string Position { get; set; } - public string RDS { get; set; } - public string Title { get; set; } + [JsonPropertyName("Layer")] public string Layer { get; set; } + [JsonPropertyName("PassFail")] public string PassFail { get; set; } + [JsonPropertyName("Position")] public string Position { get; set; } + [JsonPropertyName("RDS")] public string RDS { get; set; } + [JsonPropertyName("Title")] public string Title { get; set; } public string UniqueId { get; set; } - public string Wafer { get; set; } - public string Zone { get; set; } + [JsonPropertyName("Wafer")] public string Wafer { get; set; } + [JsonPropertyName("Zone")] public string Zone { get; set; } // - public string MeanThickness { get; set; } - public string RVThickness { get; set; } - public string StdDev { get; set; } - public string Thickness { get; set; } + [JsonPropertyName("WaferMeanThickness")] public string MeanThickness { get; set; } + [JsonPropertyName("RadialVariationThickness")] public string RVThickness { get; set; } + [JsonPropertyName("StdDev")] public string StdDev { get; set; } + [JsonPropertyName("Thickness")] public string Thickness { get; set; } // - public string Slot { get; set; } - public string ThicknessFourteen3mmEdgeMean { get; set; } - public string ThicknessFourteen3mmEdgePercent { get; set; } - public string ThicknessFourteen5mmEdgeMean { get; set; } - public string ThicknessFourteen5mmEdgePercent { get; set; } - public string ThicknessFourteenCenterMean { get; set; } - public string ThicknessFourteenCriticalPointsAverage { get; set; } - public string ThicknessFourteenCriticalPointsStdDev { get; set; } - public string ThicknessFourteenMeanFrom { get; set; } + [JsonPropertyName("Slot")] public string Slot { get; set; } + [JsonPropertyName("Thickness 14 3mm Edge Mean")] public string ThicknessFourteen3mmEdgeMean { get; set; } + [JsonPropertyName("Thickness 14 3mm Edge % from R/2")] public string ThicknessFourteen3mmEdgePercent { get; set; } + [JsonPropertyName("Thickness 14 5mm Edge Mean")] public string ThicknessFourteen5mmEdgeMean { get; set; } + [JsonPropertyName("Thickness 14 5mm Edge % from R/2")] public string ThicknessFourteen5mmEdgePercent { get; set; } + [JsonPropertyName("Thickness 14 Center Mean")] public string ThicknessFourteenCenterMean { get; set; } + [JsonPropertyName("Thickness 14 Average")] public string ThicknessFourteenCriticalPointsAverage { get; set; } + [JsonPropertyName("Thickness 14 Std Dev")] public string ThicknessFourteenCriticalPointsStdDev { get; set; } + [JsonPropertyName("Thickness 14 R 2/Mean")] public string ThicknessFourteenMeanFrom { get; set; } // - public string Thickness01 { get; set; } - public string Thickness02 { get; set; } - public string Thickness03 { get; set; } - public string Thickness04 { get; set; } - public string Thickness05 { get; set; } - public string Thickness06 { get; set; } - public string Thickness07 { get; set; } - public string Thickness08 { get; set; } - public string Thickness09 { get; set; } - public string Thickness10 { get; set; } - public string Thickness11 { get; set; } - public string Thickness12 { get; set; } - public string Thickness13 { get; set; } - public string Thickness14 { get; set; } + [JsonPropertyName("Thickness01")] public string Thickness01 { get; set; } + [JsonPropertyName("Thickness02")] public string Thickness02 { get; set; } + [JsonPropertyName("Thickness03")] public string Thickness03 { get; set; } + [JsonPropertyName("Thickness04")] public string Thickness04 { get; set; } + [JsonPropertyName("Thickness05")] public string Thickness05 { get; set; } + [JsonPropertyName("Thickness06")] public string Thickness06 { get; set; } + [JsonPropertyName("Thickness07")] public string Thickness07 { get; set; } + [JsonPropertyName("Thickness08")] public string Thickness08 { get; set; } + [JsonPropertyName("Thickness09")] public string Thickness09 { get; set; } + [JsonPropertyName("Thickness10")] public string Thickness10 { get; set; } + [JsonPropertyName("Thickness11")] public string Thickness11 { get; set; } + [JsonPropertyName("Thickness12")] public string Thickness12 { get; set; } + [JsonPropertyName("Thickness13")] public string Thickness13 { get; set; } + [JsonPropertyName("Thickness14")] public string Thickness14 { get; set; } string IDescription.GetEventDescription() => "File Has been read and parsed"; @@ -351,4 +352,16 @@ public class Description : IDescription, Shared.Properties.IDescription internal static string GetDateFormat() => "MM/dd/yyyy hh:mm:ss tt"; +} + +[JsonSourceGenerationOptions(WriteIndented = true, NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] +[JsonSerializable(typeof(Description))] +internal partial class DescriptionSourceGenerationContext : JsonSerializerContext +{ +} + +[JsonSourceGenerationOptions(WriteIndented = true, NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] +[JsonSerializable(typeof(Description[]))] +internal partial class DescriptionArraySourceGenerationContext : JsonSerializerContext +{ } \ No newline at end of file diff --git a/Adaptation/FileHandlers/QS408M/Detail.cs b/Adaptation/FileHandlers/QS408M/Detail.cs index c09e73b..6d464be 100644 --- a/Adaptation/FileHandlers/QS408M/Detail.cs +++ b/Adaptation/FileHandlers/QS408M/Detail.cs @@ -1,13 +1,27 @@ +using System.Text.Json.Serialization; + namespace Adaptation.FileHandlers.QS408M; public class Detail { public string HeaderUniqueId { get; set; } - public string Position { get; set; } - public string Thickness { get; set; } + [JsonPropertyName("Position")] public string Position { get; set; } + [JsonPropertyName("Thickness")] public string Thickness { get; set; } public string UniqueId { get; set; } public override string ToString() => string.Concat(Position, ";", Thickness, ";"); +} + +[JsonSourceGenerationOptions(WriteIndented = true, NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] +[JsonSerializable(typeof(Detail))] +internal partial class DetailSourceGenerationContext : JsonSerializerContext +{ +} + +[JsonSourceGenerationOptions(WriteIndented = true, NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] +[JsonSerializable(typeof(Detail[]))] +internal partial class DetailArraySourceGenerationContext : JsonSerializerContext +{ } \ No newline at end of file diff --git a/Adaptation/FileHandlers/QS408M/ProcessData.cs b/Adaptation/FileHandlers/QS408M/ProcessData.cs index b85dc12..2c98d47 100644 --- a/Adaptation/FileHandlers/QS408M/ProcessData.cs +++ b/Adaptation/FileHandlers/QS408M/ProcessData.cs @@ -304,12 +304,11 @@ public partial class ProcessData : IProcessData { List results = new(); Description? description; - JsonSerializerOptions jsonSerializerOptions = new() { NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString }; foreach (JsonElement jsonElement in jsonElements) { if (jsonElement.ValueKind != JsonValueKind.Object) throw new Exception(); - description = JsonSerializer.Deserialize(jsonElement.ToString(), jsonSerializerOptions); + description = JsonSerializer.Deserialize(jsonElement.ToString(), DescriptionSourceGenerationContext.Default.Description); if (description is null) continue; results.Add(description); diff --git a/Adaptation/FileHandlers/QS408M/Row.cs b/Adaptation/FileHandlers/QS408M/Row.cs index 407578a..3809d52 100644 --- a/Adaptation/FileHandlers/QS408M/Row.cs +++ b/Adaptation/FileHandlers/QS408M/Row.cs @@ -58,6 +58,6 @@ internal class Row [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(Row))] -internal partial class RowSourceGenerationContext : JsonSerializerContext +internal partial class QS408MRowSourceGenerationContext : JsonSerializerContext { } \ No newline at end of file diff --git a/Adaptation/FileHandlers/QS408M/Run.cs b/Adaptation/FileHandlers/QS408M/Run.cs index b3c3950..d67a1b6 100644 --- a/Adaptation/FileHandlers/QS408M/Run.cs +++ b/Adaptation/FileHandlers/QS408M/Run.cs @@ -71,7 +71,7 @@ internal class Run private static void WriteJson(Logistics logistics, List fileInfoCollection, Run result) { FileInfo fileInfo = new($"{logistics.ReportFullPath}.run.json"); - string json = JsonSerializer.Serialize(result, RunSourceGenerationContext.Default.Run); + string json = JsonSerializer.Serialize(result, QS408MRunSourceGenerationContext.Default.Run); File.WriteAllText(fileInfo.FullName, json); File.SetLastWriteTime(fileInfo.FullName, logistics.DateTimeFromSequence); fileInfoCollection.Add(fileInfo); @@ -190,6 +190,6 @@ internal class Run [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(Run))] -internal partial class RunSourceGenerationContext : JsonSerializerContext +internal partial class QS408MRunSourceGenerationContext : JsonSerializerContext { } \ No newline at end of file diff --git a/Adaptation/FileHandlers/pdsf/Body.cs b/Adaptation/FileHandlers/pdsf/Body.cs new file mode 100644 index 0000000..a90d9b8 --- /dev/null +++ b/Adaptation/FileHandlers/pdsf/Body.cs @@ -0,0 +1,80 @@ +namespace Adaptation.FileHandlers.pdsf; + +#nullable enable + +public class Body +{ + + public Body(string waferMeanThickness, string stdDev, string passFail) + { + WaferMeanThickness = waferMeanThickness; + StdDev = stdDev; + PassFail = passFail; + } + + public string WaferMeanThickness { get; } + public string StdDev { get; } + public string PassFail { get; } + + private static bool IsNullOrWhiteSpace(string text) + { + bool flag; + int num = 0; + while (true) + { + if (num >= text.Length) + { + flag = true; + break; + } + else if (char.IsWhiteSpace(text[num])) + { + num++; + } + else + { + flag = false; + break; + } + } + return flag; + } + + internal static string GetToken(string text, int[] i) + { + while (true) + { + if (i[0] >= text.Length || !IsNullOrWhiteSpace(text.Substring(i[0], 1))) + { + break; + } + i[0]++; + } + int num = i[0]; + while (true) + { + if (num >= text.Length || IsNullOrWhiteSpace(text.Substring(num, 1))) + { + break; + } + num++; + } + string str = text.Substring(i[0], num - i[0]); + i[0] = num; + return str.Trim(); + } + + internal static Body? Get(Constant constant, string text, int[] i) + { + Body? result; + i[0] = Run.ScanPast(text, i, constant.MeanThickness); + string meanThickness = Run.GetBefore(text, i, constant.StandardDeviation); + string stdDev = GetToken(text, i); + string passFail = Run.GetToEOL(text, i); + result = new(meanThickness, + stdDev, + passFail); + return result; + } + +} \ No newline at end of file diff --git a/Adaptation/FileHandlers/pdsf/Constant.cs b/Adaptation/FileHandlers/pdsf/Constant.cs new file mode 100644 index 0000000..f544ce9 --- /dev/null +++ b/Adaptation/FileHandlers/pdsf/Constant.cs @@ -0,0 +1,21 @@ +namespace Adaptation.FileHandlers.pdsf; + +internal class Constant +{ + + public string Period { get; } = "."; + public string Slot { get; } = "Slot:"; + public string Semicolon { get; } = ";"; + public string Batch { get; } = "batch:"; + public string TwoSpaces { get; } = " "; + public string Wafer { get; } = "wafer:"; + public string BioRad { get; } = "Bio-Rad"; + public string Recipe { get; } = "Recipe:"; + public string Cassette { get; } = "cassette:"; + public string Operator { get; } = "operator:"; + public string Thickness { get; } = "thickness"; + public string MeanThickness { get; } = "mean thickness ="; + public string StandardDeviation { get; } = ", std. dev ="; + public string WaferFieldIsMissing { get; } = "Wafer field is missing."; + +} \ No newline at end of file diff --git a/Adaptation/FileHandlers/pdsf/FileRead.cs b/Adaptation/FileHandlers/pdsf/FileRead.cs new file mode 100644 index 0000000..f640fe6 --- /dev/null +++ b/Adaptation/FileHandlers/pdsf/FileRead.cs @@ -0,0 +1,130 @@ +using Adaptation.Eaf.Management.ConfigurationData.CellAutomation; +using Adaptation.Ifx.Eaf.EquipmentConnector.File.Configuration; +using Adaptation.Shared; +using Adaptation.Shared.Duplicator; +using Adaptation.Shared.Methods; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; + +namespace Adaptation.FileHandlers.pdsf; + +public class FileRead : Shared.FileRead, IFileRead +{ + + private readonly Header[] _LastHeader; + + public FileRead(ISMTP smtp, Dictionary fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) + { + _MinFileLength = 10; + _NullData = string.Empty; + _Logistics = new(this); + if (_FileParameter is null) + throw new Exception(cellInstanceConnectionName); + if (_ModelObjectParameterDefinitions is null) + throw new Exception(cellInstanceConnectionName); + if (_IsDuplicator) + throw new Exception(cellInstanceConnectionName); + _LastHeader = new Header[] { Header.Get() }; + if (_IsEAFHosted) + NestExistingFiles(_FileConnectorConfiguration); + } + + void IFileRead.Move(Tuple> extractResults, Exception exception) => Move(extractResults); + + void IFileRead.WaitForThread() => WaitForThread(thread: null, threadExceptions: null); + + string IFileRead.GetEventDescription() + { + string result = _Description.GetEventDescription(); + return result; + } + + List IFileRead.GetHeaderNames() + { + List results = _Description.GetHeaderNames(); + return results; + } + + string[] IFileRead.Move(Tuple> extractResults, string to, string from, string resolvedFileLocation, Exception exception) + { + string[] results = Move(extractResults, to, from, resolvedFileLocation, exception); + return results; + } + + JsonProperty[] IFileRead.GetDefault() + { + JsonProperty[] results = _Description.GetDefault(this, _Logistics); + return results; + } + + Dictionary IFileRead.GetDisplayNamesJsonElement() + { + Dictionary results = _Description.GetDisplayNamesJsonElement(this); + return results; + } + + List IFileRead.GetDescriptions(IFileRead fileRead, List tests, IProcessData processData) + { + List results = _Description.GetDescriptions(fileRead, _Logistics, tests, processData); + return results; + } + + Tuple> IFileRead.GetExtractResult(string reportFullPath, string eventName) + { + Tuple> results; + if (string.IsNullOrEmpty(eventName)) + throw new Exception(); + _ReportFullPath = reportFullPath; + DateTime dateTime = DateTime.Now; + results = GetExtractResult(reportFullPath, dateTime); + if (results.Item3 is null) + results = new Tuple>(results.Item1, Array.Empty(), Array.Empty(), results.Item4); + if (results.Item3.Length > 0 && _IsEAFHosted) + WritePDSF(this, results.Item3); + UpdateLastTicksDuration(DateTime.Now.Ticks - dateTime.Ticks); + return results; + } + + Tuple> IFileRead.ReExtract() + { + Tuple> results; + List headerNames = _Description.GetHeaderNames(); + Dictionary keyValuePairs = _Description.GetDisplayNamesJsonElement(this); + results = ReExtract(this, headerNames, keyValuePairs); + return results; + } + +#nullable enable + + private Tuple> GetExtractResult(string reportFullPath, DateTime dateTime) + { + Tuple> results; + string result; + JsonElement[] jsonElements; + Test[] tests = Array.Empty(); + List fileInfoCollection = new(); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + _Logistics = new Logistics(reportFullPath, processDataStandardFormat); + SetFileParameterLotIDToLogisticsMID(); + Run? run = Run.Get(_Logistics, processDataStandardFormat, fileInfoCollection, lastHeader: _LastHeader[0]); + if (run is null) + { + _LastHeader[0] = Header.Get(); + jsonElements = Array.Empty(); + result = string.Concat("A) No Data - ", dateTime.Ticks); + results = new(result, tests, jsonElements, fileInfoCollection); + } + else + { + _LastHeader[0] = run.Header; + result = string.Join(Environment.NewLine, _Logistics.Logistics1); + jsonElements = _IsEAFHosted ? Array.Empty() : ProcessDataStandardFormat.GetArray(processDataStandardFormat); + results = new(result, tests, jsonElements, fileInfoCollection); + } + return results; + } + +} \ No newline at end of file diff --git a/Adaptation/FileHandlers/pdsf/Footer.cs b/Adaptation/FileHandlers/pdsf/Footer.cs new file mode 100644 index 0000000..09a9fdb --- /dev/null +++ b/Adaptation/FileHandlers/pdsf/Footer.cs @@ -0,0 +1,36 @@ +namespace Adaptation.FileHandlers.pdsf; + +#nullable enable + +public class Footer +{ + + public Footer(string line, string radialVariationThickness, string slot) + { + Line = line; + RadialVariationThickness = radialVariationThickness; + Slot = slot; + } + + public string Line { get; } + public string RadialVariationThickness { get; } + public string Slot { get; } + + internal static Footer? Get(Constant constant, string text, int[] i) + { + Footer? result; + _ = Run.GetToEOL(text, i); + _ = Run.GetToEOL(text, i); + string line = Run.GetToEOL(text, i); + i[0] = Run.ScanPast(text, i, constant.Thickness); + string radialVariationThickness = Run.GetToEOL(text, i); + _ = Run.GetToEOL(text, i); + i[0] = Run.ScanPast(text, i, constant.Slot); + string slot = Run.GetBefore(text, i, constant.Semicolon); + result = new(line, + radialVariationThickness, + slot); + return result; + } + +} \ No newline at end of file diff --git a/Adaptation/FileHandlers/pdsf/Header.cs b/Adaptation/FileHandlers/pdsf/Header.cs new file mode 100644 index 0000000..912e95e --- /dev/null +++ b/Adaptation/FileHandlers/pdsf/Header.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.ObjectModel; + +namespace Adaptation.FileHandlers.pdsf; + +#nullable enable + +public class Header +{ + + public Header(string title, string recipe, string dateTime, string @operator, string batch, string cassette, bool usedLast, string wafer) + { + Title = title; + Recipe = recipe; + DateTime = dateTime; + Operator = @operator; + Batch = batch; + Cassette = cassette; + UsedLast = usedLast; + Wafer = wafer; + } + + public string Title { get; } + public string Recipe { get; } + public string DateTime { get; } + public string Operator { get; } + public string Batch { get; } + public string Cassette { get; } + public bool UsedLast { get; } + public string Wafer { get; } + + internal static Header Get() => + new(string.Empty, + string.Empty, + string.Empty, + string.Empty, + string.Empty, + string.Empty, + false, + string.Empty); + + internal static Header? Get(Constant constant, Header lastHeader, string text, int[] i) + { + Header? result; + // occasionally there are multiple blocks of details, get the last one as earlier ones may be aborted runs. + int index = text.LastIndexOf(constant.BioRad); + if (index > -1) + text = text.Substring(index); + if (string.IsNullOrEmpty(text)) + result = null; + else + { + bool usedLast; + string recipe; + string title = Run.GetBefore(text, i, constant.Recipe); + string recipeAndDateTime = Run.GetToEOL(text, i); + if (recipeAndDateTime.Length < constant.TwoSpaces.Length) + recipe = recipeAndDateTime.Trim(); + else if (!recipeAndDateTime.Contains(constant.TwoSpaces)) + recipe = recipeAndDateTime.Substring(0, 25).Trim(); + else + recipe = recipeAndDateTime.Split(new string[] { constant.TwoSpaces }, StringSplitOptions.None)[0].Trim(); + string dateTime = recipeAndDateTime.Substring(recipe.Length).Trim(); + if (dateTime.EndsWith(constant.Period)) + dateTime = dateTime.Remove(dateTime.Length - 1, 1); + i[0] = Run.ScanPast(text, i, constant.Operator); + string @operator = Run.GetBefore(text, i, constant.Batch); + string batch = Run.GetToEOL(text, i); + i[0] = Run.ScanPast(text, i, constant.Cassette); + if (!text.Contains(constant.Cassette)) + title = string.Empty; + string cassette = Run.GetBefore(text, i, constant.Wafer); + if (string.IsNullOrEmpty(batch)) + { + i[0] = 0; + i[0] = Run.ScanPast(text, i, constant.Wafer); + } + string wafer = Run.GetToEOL(text, i); + _ = Run.GetToEOL(text, i); + _ = Run.GetToEOL(text, i); + if (string.IsNullOrEmpty(wafer)) + throw new Exception(constant.WaferFieldIsMissing); + if (!string.IsNullOrEmpty(title)) + usedLast = false; + else + { + title = lastHeader.Title; + recipe = lastHeader.Recipe; + @operator = lastHeader.Operator; + batch = lastHeader.Batch; + cassette = lastHeader.Cassette; + usedLast = true; + } + result = new(title: title, + recipe: recipe, + dateTime: dateTime, + @operator: @operator, + batch: batch, + cassette: cassette, + usedLast: usedLast, + wafer: wafer); + } + return result; + } + +} \ No newline at end of file diff --git a/Adaptation/FileHandlers/pdsf/Row.cs b/Adaptation/FileHandlers/pdsf/Row.cs new file mode 100644 index 0000000..3e09fa7 --- /dev/null +++ b/Adaptation/FileHandlers/pdsf/Row.cs @@ -0,0 +1,63 @@ +using System.Text.Json.Serialization; + +namespace Adaptation.FileHandlers.pdsf; + +#nullable enable + +internal class Row +{ + + public Row(Run run, int i) + { + Index = i; + // + Title = run.Header.Title; + Recipe = run.Header.Recipe; + DateTime = run.Header.DateTime; + Operator = run.Header.Operator; + Batch = run.Header.Batch; + Cassette = run.Header.Cassette; + UsedLast = run.Header.UsedLast; + Wafer = run.Header.Wafer; + // + Position = run.Sites[i].Position; + Thickness = run.Sites[i].Thickness; + // + WaferMeanThickness = run.Body.WaferMeanThickness; + StdDev = run.Body.StdDev; + PassFail = run.Body.PassFail; + // + Line = run.Footer.Line; + RadialVariationThickness = run.Footer.RadialVariationThickness; + Slot = run.Footer.Slot; + } + + public int Index { get; } + // + public string Title { get; } + public string Recipe { get; } + public string DateTime { get; } + public string Operator { get; } + public string Batch { get; } + public string Cassette { get; } + public bool UsedLast { get; } + public string Wafer { get; } + // + public string Position { get; } + public string Thickness { get; } + // + public string WaferMeanThickness { get; } + public string StdDev { get; } + public string PassFail { get; } + // + public string Line { get; } + public string RadialVariationThickness { get; } + public string Slot { get; } + +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(Row))] +internal partial class RowSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Adaptation/FileHandlers/pdsf/Run.cs b/Adaptation/FileHandlers/pdsf/Run.cs new file mode 100644 index 0000000..b2828a2 --- /dev/null +++ b/Adaptation/FileHandlers/pdsf/Run.cs @@ -0,0 +1,190 @@ +using Adaptation.Shared; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Adaptation.FileHandlers.pdsf; + +#nullable enable + +internal class Run +{ + + public Header Header { get; } + public ReadOnlyCollection Sites { get; } + public Body Body { get; } + public Footer Footer { get; } + + public Run(Header header, ReadOnlyCollection sites, Body body, Footer footer) + { + Header = header; + Sites = sites; + Body = body; + Footer = footer; + } + + internal static string GetBefore(string text, int[] i, string search) + { + string str; + string str1; + int num = text.IndexOf(search, i[0]); + if (num <= -1) + { + str = text.Substring(i[0]); + i[0] = text.Length; + str1 = str.Trim(); + } + else + { + str = text.Substring(i[0], num - i[0]); + i[0] = num + search.Length; + str1 = str.Trim(); + } + return str1; + } + + internal static string GetToEOL(string text, int[] i) + { + string result; + if (text.IndexOf("\n", i[0]) > -1) + result = GetBefore(text, i, "\n"); + else + result = GetBefore(text, i, Environment.NewLine); + return result; + } + + internal static int ScanPast(string text, int[] i, string search) + { + int result; + int num = text.IndexOf(search, i[0]); + if (num <= -1) + result = text.Length; + else + result = num + search.Length; + return result; + } + + private static void WriteJson(Logistics logistics, List fileInfoCollection, Run result) + { + FileInfo fileInfo = new($"{logistics.ReportFullPath}.run.json"); + string json = JsonSerializer.Serialize(result, RunSourceGenerationContext.Default.Run); + File.WriteAllText(fileInfo.FullName, json); + File.SetLastWriteTime(fileInfo.FullName, logistics.DateTimeFromSequence); + fileInfoCollection.Add(fileInfo); + } + + private static ReadOnlyCollection GetLines(Logistics logistics, JsonElement[]? jsonElements) + { + List results = new(); + int columns = 0; + StringBuilder stringBuilder = new(); + results.Add($"\"Count\",{jsonElements?.Length}"); + results.Add($"\"{nameof(logistics.Sequence)}\",\"{logistics.Sequence}\""); + results.Add($"\"{nameof(logistics.MesEntity)}\",\"{logistics.MesEntity}\""); + string dateTimeFromSequence = logistics.DateTimeFromSequence.ToString("MM/dd/yyyy hh:mm:ss tt"); + for (int i = 0; i < jsonElements?.Length;) + { + _ = stringBuilder.Append('"').Append(nameof(logistics.DateTimeFromSequence)).Append('"').Append(','); + foreach (JsonProperty jsonProperty in jsonElements[0].EnumerateObject()) + { + columns += 1; + _ = stringBuilder.Append('"').Append(jsonProperty.Name).Append('"').Append(','); + } + break; + } + if (jsonElements?.Length != 0) + _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); + results.Add(stringBuilder.ToString()); + for (int i = 0; i < jsonElements?.Length; i++) + { + _ = stringBuilder.Clear(); + _ = stringBuilder.Append('"').Append(dateTimeFromSequence).Append('"').Append(','); + foreach (JsonProperty jsonProperty in jsonElements[i].EnumerateObject()) + { + if (jsonProperty.Value.ValueKind == JsonValueKind.Object) + _ = stringBuilder.Append(','); + else if (jsonProperty.Value.ValueKind != JsonValueKind.String) + _ = stringBuilder.Append(jsonProperty.Value).Append(','); + else + _ = stringBuilder.Append('"').Append(jsonProperty.Value).Append('"').Append(','); + } + _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); + results.Add(stringBuilder.ToString()); + } + return results.AsReadOnly(); + } + + private static void WriteCommaSeparatedValues(Logistics logistics, Run run) + { + List results = new(); + Row row; + for (int i = 0; i < run.Sites.Count; i++) + { + row = new(run, i); + results.Add(row); + } + string json = JsonSerializer.Serialize(results); + JsonElement[]? jsonElements = JsonSerializer.Deserialize(json); + ReadOnlyCollection lines = GetLines(logistics, jsonElements); + File.WriteAllText($"{logistics.ReportFullPath}.csv", string.Join(Environment.NewLine, lines)); + } + + private static string GetText(ProcessDataStandardFormat processDataStandardFormat) + { + string result; + List results = new(); + int skipColumns = processDataStandardFormat.Columns.Count - 1; + foreach (string line in processDataStandardFormat.Body) + results.Add(string.Join("\t", line.Split('\t').Skip(skipColumns))); + result = string.Join(Environment.NewLine, results); + return result; + } + + internal static Run? Get(Logistics logistics, ProcessDataStandardFormat processDataStandardFormat, List fileInfoCollection, Header lastHeader) + { + Run? result; + Constant constant = new(); + int[] i = new int[] { 0 }; + string text = GetText(processDataStandardFormat); + Header? header = Header.Get(constant, lastHeader, text, i); + if (header is null) + result = null; + else + { + ReadOnlyCollection sites = Site.Get(text, i); + if (sites.Count == 0) + result = null; + else + { + Body? body = Body.Get(constant, text, i); + if (body is null) + result = null; + else + { + Footer? footer = Footer.Get(constant, text, i); + if (footer is null) + result = null; + else + { + result = new(header, sites, body, footer); + WriteJson(logistics, fileInfoCollection, result); + WriteCommaSeparatedValues(logistics, result); + } + } + } + } + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(Run))] +internal partial class RunSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Adaptation/FileHandlers/pdsf/Site.cs b/Adaptation/FileHandlers/pdsf/Site.cs new file mode 100644 index 0000000..e789eb9 --- /dev/null +++ b/Adaptation/FileHandlers/pdsf/Site.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Adaptation.FileHandlers.pdsf; + +public class Site +{ + + public Site(string position, string thickness) + { + Position = position; + Thickness = thickness; + } + + public string Position { get; } + public string Thickness { get; } + + internal static ReadOnlyCollection Get(string text, int[] i) + { + List results = new(); + Site site; + string thickness; + string position = Body.GetToken(text, i); + while (true) + { + if (string.IsNullOrEmpty(position) || !char.IsDigit(position[0])) + break; + thickness = Body.GetToken(text, i); + site = new(position, thickness); + results.Add(site); + position = Body.GetToken(text, i); + } + return results.AsReadOnly(); + } + +} \ No newline at end of file diff --git a/Adaptation/Shared/Duplicator/Description.cs b/Adaptation/Shared/Duplicator/Description.cs index 964612e..d9bb3b8 100644 --- a/Adaptation/Shared/Duplicator/Description.cs +++ b/Adaptation/Shared/Duplicator/Description.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; +using System.Text.Json.Serialization; namespace Adaptation.Shared.Duplicator; @@ -178,4 +179,16 @@ public class Description : IDescription, Properties.IDescription internal static string GetDateFormat() => "MM/dd/yyyy hh:mm:ss tt"; +} + +[JsonSourceGenerationOptions(WriteIndented = true, NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] +[JsonSerializable(typeof(Description))] +internal partial class SharedDescriptionSourceGenerationContext : JsonSerializerContext +{ +} + +[JsonSourceGenerationOptions(WriteIndented = true, NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] +[JsonSerializable(typeof(Description[]))] +internal partial class SharedDescriptionArraySourceGenerationContext : JsonSerializerContext +{ } \ No newline at end of file diff --git a/Adaptation/Shared/FileRead.cs b/Adaptation/Shared/FileRead.cs index 48aacab..aaa6958 100644 --- a/Adaptation/Shared/FileRead.cs +++ b/Adaptation/Shared/FileRead.cs @@ -9,7 +9,6 @@ using System.IO; using System.Linq; using System.Text; using System.Text.Json; -using System.Text.Json.Serialization; using System.Threading; namespace Adaptation.Shared; @@ -447,12 +446,13 @@ public class FileRead : Properties.IFileRead { List results = new(); Duplicator.Description description; - JsonSerializerOptions jsonSerializerOptions = new() { NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString }; foreach (JsonElement jsonElement in jsonElements) { if (jsonElement.ValueKind != JsonValueKind.Object) throw new Exception(); - description = JsonSerializer.Deserialize(jsonElement.ToString(), jsonSerializerOptions); + description = JsonSerializer.Deserialize(jsonElement.ToString(), Duplicator.SharedDescriptionSourceGenerationContext.Default.Description); + if (description is null) + continue; results.Add(description); } return results; diff --git a/Adaptation/Shared/ProcessDataStandardFormat.cs b/Adaptation/Shared/ProcessDataStandardFormat.cs index 92b9f3d..9d48a31 100644 --- a/Adaptation/Shared/ProcessDataStandardFormat.cs +++ b/Adaptation/Shared/ProcessDataStandardFormat.cs @@ -654,6 +654,17 @@ internal class ProcessDataStandardFormat return results; } + internal static JsonElement[] GetArray(string reportFullPath, string[] lines, ProcessDataStandardFormat processDataStandardFormat) + { + JsonElement[] results; + string? json = GetRecordsJson(reportFullPath, lines); + if (string.IsNullOrEmpty(json)) + results = GetArray(processDataStandardFormat); + else + results = JsonSerializer.Deserialize(json, JsonElementCollectionSourceGenerationContext.Default.JsonElementArray) ?? throw new Exception(); + return results; + } + internal static string GetPDSFText(IFileRead fileRead, Logistics logistics, JsonElement[] jsonElements, string logisticsText) { string result; @@ -956,6 +967,26 @@ internal class ProcessDataStandardFormat return result; } + private static string? GetRecordsJson(string reportFullPath, string[] lines) + { + string? result; + bool foundRecords = false; + List results = new(); + lines ??= File.ReadAllLines(reportFullPath); + foreach (string line in lines) + { + if (line.StartsWith("\"Records\"")) + foundRecords = true; + if (!foundRecords) + continue; + if (line == "],") + break; + results.Add(line); + } + result = results.Count == 0 ? null : $"{string.Join(Environment.NewLine, results.Skip(1))}{Environment.NewLine}]"; + return result; + } + } [JsonSourceGenerationOptions(WriteIndented = true)] diff --git a/Adaptation/_Tests/CreateSelfDescription/Production/v2.60.0/BIORAD2.cs b/Adaptation/_Tests/CreateSelfDescription/Production/v2.60.0/BIORAD2.cs index 2e73d08..95449cc 100644 --- a/Adaptation/_Tests/CreateSelfDescription/Production/v2.60.0/BIORAD2.cs +++ b/Adaptation/_Tests/CreateSelfDescription/Production/v2.60.0/BIORAD2.cs @@ -48,9 +48,7 @@ public class BIORAD2 : EAFLoggingUnitTesting EAFLoggingUnitTesting?.Dispose(); } -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD2__QS408M() { @@ -61,5 +59,18 @@ public class BIORAD2 : EAFLoggingUnitTesting EAFLoggingUnitTesting.Logger.LogInformation(string.Concat(methodBase.Name, " - Exit")); } +#if DEBUG + [Ignore] +#endif + [TestMethod] + public void Production__v2_60_0__BIORAD2__pdsf() + { + string check = "*EQP_*.pdsf"; + MethodBase methodBase = new StackFrame().GetMethod(); + EAFLoggingUnitTesting.Logger.LogInformation(string.Concat(methodBase.Name, " - Getting configuration")); + _ = AdaptationTesting.GetWriteConfigurationGetFileRead(methodBase, check, EAFLoggingUnitTesting.AdaptationTesting); + EAFLoggingUnitTesting.Logger.LogInformation(string.Concat(methodBase.Name, " - Exit")); + } + } #endif \ No newline at end of file diff --git a/Adaptation/_Tests/CreateSelfDescription/Production/v2.60.0/BIORAD3.cs b/Adaptation/_Tests/CreateSelfDescription/Production/v2.60.0/BIORAD3.cs index c1a440c..3c07f0b 100644 --- a/Adaptation/_Tests/CreateSelfDescription/Production/v2.60.0/BIORAD3.cs +++ b/Adaptation/_Tests/CreateSelfDescription/Production/v2.60.0/BIORAD3.cs @@ -48,9 +48,7 @@ public class BIORAD3 : EAFLoggingUnitTesting EAFLoggingUnitTesting?.Dispose(); } -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD3__QS408M() { diff --git a/Adaptation/_Tests/Extract/Production/v2.60.0/BIORAD2.cs b/Adaptation/_Tests/Extract/Production/v2.60.0/BIORAD2.cs index e2c3895..7eb6ba5 100644 --- a/Adaptation/_Tests/Extract/Production/v2.60.0/BIORAD2.cs +++ b/Adaptation/_Tests/Extract/Production/v2.60.0/BIORAD2.cs @@ -1,4 +1,5 @@ #if true +using Adaptation._Tests.Shared; using Adaptation.Shared; using Adaptation.Shared.Methods; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -31,15 +32,11 @@ public class BIORAD2 catch (Exception) { } } -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD2__QS408M() => _BIORAD2.Production__v2_60_0__BIORAD2__QS408M(); -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD2__QS408M638185231662401081__NinePoint() { @@ -55,13 +52,11 @@ public class BIORAD2 Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); dateTime = FileHandlers.QS408M.ProcessData.GetDateTime(logistics, tickOffset: 0, dateTimeText: "Tue Nov 10 12:03:56 1970"); Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); - _ = Shared.AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); + _ = AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); NonThrowTryCatch(); } -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD2__QS408M638185291035612698__FourteenPoint() { @@ -77,13 +72,11 @@ public class BIORAD2 Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); dateTime = FileHandlers.QS408M.ProcessData.GetDateTime(logistics, tickOffset: 0, dateTimeText: "Tue Nov 10 12:03:56 1970"); Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); - _ = Shared.AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); + _ = AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); NonThrowTryCatch(); } -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD2__QS408M638206292859940029__EpiPro() { @@ -99,13 +92,11 @@ public class BIORAD2 Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); dateTime = FileHandlers.QS408M.ProcessData.GetDateTime(logistics, tickOffset: 0, dateTimeText: "Tue Nov 10 12:03:56 1970"); Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); - _ = Shared.AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); + _ = AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); NonThrowTryCatch(); } -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD2__QS408M638211310710952565__WMO() { @@ -121,13 +112,11 @@ public class BIORAD2 Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); dateTime = FileHandlers.QS408M.ProcessData.GetDateTime(logistics, tickOffset: 0, dateTimeText: "Tue Nov 10 12:03:56 1970"); Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); - _ = Shared.AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); + _ = AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); NonThrowTryCatch(); } -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD2__QS408M638635290101315251__ADO126448() { @@ -143,7 +132,24 @@ public class BIORAD2 Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); dateTime = FileHandlers.QS408M.ProcessData.GetDateTime(logistics, tickOffset: 0, dateTimeText: "Tue Nov 10 12:03:56 1970"); Assert.AreEqual(logistics.DateTimeFromSequence, dateTime); - _ = Shared.AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); + _ = AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); + NonThrowTryCatch(); + } + +#if DEBUG + [Ignore] +#endif + [TestMethod] + public void Production__v2_60_0__BIORAD2__pdsf638925042012952259__Normal() + { + bool validatePDSF = false; + string check = "*EQP_*.pdsf"; + _BIORAD2.Production__v2_60_0__BIORAD2__pdsf(); + MethodBase methodBase = new StackFrame().GetMethod(); + string[] variables = _BIORAD2.AdaptationTesting.GetVariables(methodBase, check, validatePDSF); + IFileRead fileRead = _BIORAD2.AdaptationTesting.Get(methodBase, sourceFileLocation: variables[2], sourceFileFilter: variables[3], useCyclicalForDescription: false); + Logistics logistics = new(fileRead); + _ = AdaptationTesting.ReExtractCompareUpdatePassDirectory(variables, fileRead, logistics, validatePDSF); NonThrowTryCatch(); } diff --git a/Adaptation/_Tests/Extract/Production/v2.60.0/BIORAD3.cs b/Adaptation/_Tests/Extract/Production/v2.60.0/BIORAD3.cs index 55814d9..62fb543 100644 --- a/Adaptation/_Tests/Extract/Production/v2.60.0/BIORAD3.cs +++ b/Adaptation/_Tests/Extract/Production/v2.60.0/BIORAD3.cs @@ -31,15 +31,11 @@ public class BIORAD3 catch (Exception) { } } -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD3__QS408M() => _BIORAD3.Production__v2_60_0__BIORAD3__QS408M(); -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD3__QS408M637406016892454000__ReactorAndRDS() { @@ -59,9 +55,7 @@ public class BIORAD3 NonThrowTryCatch(); } -#if DEBUG [Ignore] -#endif [TestMethod] public void Production__v2_60_0__BIORAD3__QS408M638227775101723135__Error() { diff --git a/MET08THFTIRQS408M.csproj b/MET08THFTIRQS408M.csproj index 9ee866c..b0a0ccc 100644 --- a/MET08THFTIRQS408M.csproj +++ b/MET08THFTIRQS408M.csproj @@ -115,6 +115,14 @@ + + + + + + + +