Bug in yml dotnet tool PackageReference arrangement RDS Blank Change int dotnet test nuget ^ [spcepiworld].[dbo].[evnt_inf] Assembly Version WS Result bug fix and Nuget bump, PSN, Reactor and Extra RDS rule OpenInsightApi and testRunTitle editorconfig bugs Fix Type serializerValue RDS oversight PropertyNameCaseInsensitive Save check for file already present NoWaitDirectory MoveArchive allow empty directory and continueOnError for clean files CreatePointerFile and more on NoWaitDirectory
292 lines
16 KiB
C#
292 lines
16 KiB
C#
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 Adaptation.Shared.Metrology;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
namespace Adaptation.FileHandlers.OpenInsight;
|
|
|
|
public class FileRead : Shared.FileRead, IFileRead
|
|
{
|
|
|
|
private readonly string _IqsConnectionString;
|
|
private readonly string _OpenInsightFilePattern;
|
|
private readonly string _OpenInsightApiECDirectory;
|
|
private readonly string _OpenInsightApiIFXDirectory;
|
|
|
|
public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) :
|
|
base(new Description(), false, smtp, fileParameter, cellInstanceName, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted)
|
|
{
|
|
_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);
|
|
_OpenInsightApiIFXDirectory = @"\\messdv002.na.infineon.com\Candela\Archive\API";
|
|
_OpenInsightApiECDirectory = @"\\messv02ecc1.ec.local\EC_Metrology_Si\Archive\API";
|
|
_IqsConnectionString = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, "IQS.ConnectionString");
|
|
_OpenInsightFilePattern = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, "OpenInsight.FilePattern");
|
|
}
|
|
|
|
void IFileRead.Move(Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResults, Exception exception)
|
|
{
|
|
bool isErrorFile = exception is not null;
|
|
if (!isErrorFile && !string.IsNullOrEmpty(_Logistics.ReportFullPath))
|
|
{
|
|
FileInfo fileInfo = new(_Logistics.ReportFullPath);
|
|
if (fileInfo.Exists && fileInfo.LastWriteTime < fileInfo.CreationTime)
|
|
File.SetLastWriteTime(_Logistics.ReportFullPath, fileInfo.CreationTime);
|
|
}
|
|
Move(extractResults);
|
|
}
|
|
|
|
void IFileRead.WaitForThread() => WaitForThread(thread: null, threadExceptions: null);
|
|
|
|
string IFileRead.GetEventDescription()
|
|
{
|
|
string result = _Description.GetEventDescription();
|
|
return result;
|
|
}
|
|
|
|
List<string> IFileRead.GetHeaderNames()
|
|
{
|
|
List<string> results = _Description.GetHeaderNames();
|
|
return results;
|
|
}
|
|
|
|
string[] IFileRead.Move(Tuple<string, Test[], JsonElement[], List<FileInfo>> 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<string, string> IFileRead.GetDisplayNamesJsonElement()
|
|
{
|
|
Dictionary<string, string> results = _Description.GetDisplayNamesJsonElement(this);
|
|
return results;
|
|
}
|
|
|
|
List<IDescription> IFileRead.GetDescriptions(IFileRead fileRead, List<Test> tests, IProcessData processData)
|
|
{
|
|
List<IDescription> results = _Description.GetDescriptions(fileRead, _Logistics, tests, processData);
|
|
return results;
|
|
}
|
|
|
|
Tuple<string, Test[], JsonElement[], List<FileInfo>> IFileRead.GetExtractResult(string reportFullPath, string eventName)
|
|
{
|
|
Tuple<string, Test[], JsonElement[], List<FileInfo>> 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<string, Test[], JsonElement[], List<FileInfo>>(results.Item1, Array.Empty<Test>(), JsonSerializer.Deserialize<JsonElement[]>("[]"), results.Item4);
|
|
if (results.Item3.Length > 0 && _IsEAFHosted)
|
|
WritePDSF(this, results.Item3);
|
|
UpdateLastTicksDuration(DateTime.Now.Ticks - dateTime.Ticks);
|
|
return results;
|
|
}
|
|
|
|
Tuple<string, Test[], JsonElement[], List<FileInfo>> IFileRead.ReExtract()
|
|
{
|
|
Tuple<string, Test[], JsonElement[], List<FileInfo>> results;
|
|
List<string> headerNames = _Description.GetHeaderNames();
|
|
Dictionary<string, string> keyValuePairs = _Description.GetDisplayNamesJsonElement(this);
|
|
results = ReExtract(this, headerNames, keyValuePairs);
|
|
return results;
|
|
}
|
|
|
|
internal static string GetLines(Logistics logistics, List<pcl.Description> descriptions)
|
|
{
|
|
StringBuilder result = new();
|
|
pcl.Description x = descriptions[0];
|
|
bool ganPPTST = x.Recipe.Contains("GAN_PPTST");
|
|
if (ganPPTST)
|
|
{
|
|
string slot;
|
|
string reactor;
|
|
const int eight = 8;
|
|
DateTime dateTime = DateTime.Parse(x.Date);
|
|
string lot = x.Lot.ToLower().Replace("69-", string.Empty).Replace("71-", string.Empty).Replace("-", string.Empty);
|
|
if (string.IsNullOrEmpty(x.Lot) || x.Lot.Length < 2)
|
|
reactor = "R";
|
|
else
|
|
reactor = string.Concat("R", x.Lot.Substring(0, 2));
|
|
_ = result.Append(nameof(x.Date)).Append(';').
|
|
Append("Part").Append(';').
|
|
Append(nameof(x.Reactor)).Append(';').
|
|
Append("Lot").Append(';').
|
|
Append(nameof(pcl.Detail.Slot)).Append(';').
|
|
Append(nameof(pcl.Detail.Bin1)).Append(';').
|
|
Append(nameof(pcl.Detail.Bin2)).Append(';').
|
|
Append(nameof(pcl.Detail.Bin3)).Append(';').
|
|
Append(nameof(pcl.Detail.Bin4)).Append(';').
|
|
Append(nameof(pcl.Detail.Bin5)).Append(';').
|
|
Append(nameof(pcl.Detail.Bin6)).Append(';').
|
|
Append("Bin9").
|
|
AppendLine();
|
|
foreach (pcl.Description description in descriptions)
|
|
{
|
|
slot = description.Slot.Replace("*", string.Empty);
|
|
_ = result.Append('!').Append(dateTime.ToString("MM/dd/yyyy HH:mm:ss")).Append(';').
|
|
Append("Particle Adder;").
|
|
Append(reactor).Append(';').
|
|
Append(lot).Append(';').
|
|
Append(slot).Append(';').
|
|
Append(description.Bin1).Append(';').
|
|
Append(description.Bin2).Append(';').
|
|
Append(description.Bin3).Append(';').
|
|
Append(description.Bin4).Append(';').
|
|
Append(description.Bin5).Append(';').
|
|
Append(description.Bin6).Append(';').
|
|
Append(description.AreaCount).
|
|
AppendLine();
|
|
}
|
|
if (descriptions.Count != eight)
|
|
{
|
|
string negativeTenThousand = "-10000";
|
|
for (int i = descriptions.Count; i < eight; i++)
|
|
{
|
|
_ = result.Append('!').Append(dateTime.ToString("MM/dd/yyyy HH:mm:ss")).Append(';').
|
|
Append("Particle Adder;").
|
|
Append(reactor).Append(';').
|
|
Append(lot).Append(';').
|
|
Append(negativeTenThousand).Append(';').
|
|
Append(negativeTenThousand).Append(';').
|
|
Append(negativeTenThousand).Append(';').
|
|
Append(negativeTenThousand).Append(';').
|
|
Append(negativeTenThousand).Append(';').
|
|
Append(negativeTenThousand).Append(';').
|
|
Append(negativeTenThousand).Append(';').
|
|
Append(negativeTenThousand).
|
|
AppendLine();
|
|
}
|
|
}
|
|
if (result.ToString().Split('\n').Length != (eight + 2))
|
|
throw new Exception(string.Concat("Must have ", eight, " samples"));
|
|
}
|
|
else
|
|
{
|
|
char del = '\t';
|
|
_ = result.Append(x.AreaCountAvg).Append(del). // 001 - AreaCountAvg
|
|
Append(x.AreaCountMax).Append(del). // 002 - AreaCountMax
|
|
Append(x.AreaCountMin).Append(del). // 003 - AreaCountMin
|
|
Append(x.AreaCountStdDev).Append(del). // 004 - AreaCountStdDev
|
|
Append(x.AreaTotalAvg).Append(del). // 005 - AreaTotalAvg
|
|
Append(x.AreaTotalMax).Append(del). // 006 - AreaTotalMax
|
|
Append(x.AreaTotalMin).Append(del). // 007 - AreaTotalMin
|
|
Append(x.AreaTotalStdDev).Append(del). // 008 - AreaTotalStdDev
|
|
Append(x.Date).Append(del). // 009 -
|
|
Append(x.HazeAverageAvg).Append(del). // 010 - Haze Average
|
|
Append(x.HazeAverageMax).Append(del). // 011 -
|
|
Append(x.HazeAverageMin).Append(del). // 012 -
|
|
Append(x.HazeAverageStdDev).Append(del). // 013 -
|
|
Append(x.HazeRegionAvg).Append(del). // 014 -
|
|
Append(x.HazeRegionMax).Append(del). // 015 -
|
|
Append(x.HazeRegionMin).Append(del). // 016 -
|
|
Append(x.HazeRegionStdDev).Append(del). // 017 -
|
|
Append(x.Lot).Append(del). // 018 -
|
|
Append(x.LPDCM2Avg).Append(del). // 019 -
|
|
Append(x.LPDCM2Max).Append(del). // 020 -
|
|
Append(x.LPDCM2Min).Append(del). // 021 -
|
|
Append(x.LPDCM2StdDev).Append(del). // 022 -
|
|
Append(x.LPDCountAvg).Append(del). // 023 -
|
|
Append(x.LPDCountMax).Append(del). // 024 -
|
|
Append(x.LPDCM2Min).Append(del). // 025 -
|
|
Append(x.LPDCountStdDev).Append(del). // 026 -
|
|
Append(x.Employee).Append(del). // 027 -
|
|
Append(x.RDS).Append(del). // 028 - Lot
|
|
Append(x.Reactor).Append(del). // 029 - Process
|
|
Append(x.Recipe.Replace(";", string.Empty)).Append(del). // 030 - Part
|
|
Append(x.ScratchCountAvg).Append(del). // 031 - Scratch Count
|
|
Append(x.ScratchCountMax).Append(del). // 032 -
|
|
Append(x.ScratchCountMin).Append(del). // 033 -
|
|
Append(x.ScratchTotalStdDev).Append(del). // 034 -
|
|
Append(x.ScratchTotalAvg).Append(del). // 035 - Scratch Length
|
|
Append(x.ScratchTotalMax).Append(del). // 036 -
|
|
Append(x.ScratchTotalMin).Append(del). // 037 -
|
|
Append(x.ScratchTotalStdDev).Append(del). // 038 -
|
|
Append(x.SumOfDefectsAvg).Append(del). // 039 - Average Sum of Defects
|
|
Append(x.SumOfDefectsMax).Append(del). // 040 - Max Sum of Defects
|
|
Append(x.SumOfDefectsMin).Append(del). // 041 - Min Sum of Defects
|
|
Append(x.SumOfDefectsStdDev).Append(del). // 042 - SumOfDefectsStdDev
|
|
Append(logistics.MesEntity).Append(del). // 043 -
|
|
AppendLine();
|
|
}
|
|
return result.ToString();
|
|
}
|
|
|
|
private void SaveOpenInsightFile(string reportFullPath, DateTime dateTime, string logistics, List<pcl.Description> descriptions, Test[] tests)
|
|
{
|
|
bool isDummyRun = false;
|
|
List<(Shared.Properties.IScopeInfo, string)> collection = new();
|
|
string successDirectory = _FileConnectorConfiguration.AlternateTargetFolder;
|
|
string parentParent = GetParentParent(_FileConnectorConfiguration.SourceFileLocation);
|
|
if (parentParent.Contains(_CellInstanceName))
|
|
parentParent = Path.GetDirectoryName(parentParent);
|
|
string duplicateDirectory = Path.Combine(parentParent, "Data");
|
|
if (!Directory.Exists(duplicateDirectory))
|
|
_ = Directory.CreateDirectory(duplicateDirectory);
|
|
string duplicateFile = Path.Combine(duplicateDirectory, Path.GetFileName(reportFullPath));
|
|
if (descriptions.Any() && tests.Any())
|
|
{
|
|
string lines = GetLines(_Logistics, descriptions);
|
|
if (!string.IsNullOrEmpty(lines))
|
|
{
|
|
int? count;
|
|
long? subGroupId;
|
|
long breakAfter = dateTime.AddSeconds(_BreakAfterSeconds).Ticks;
|
|
long preWait = _FileConnectorConfiguration?.FileHandleWaitTime is null ? dateTime.AddMilliseconds(1234).Ticks : dateTime.AddMilliseconds(_FileConnectorConfiguration.FileHandleWaitTime.Value).Ticks;
|
|
if (string.IsNullOrEmpty(descriptions[0].Reactor) || string.IsNullOrEmpty(descriptions[0].PSN))
|
|
(subGroupId, count) = (null, null);
|
|
else
|
|
(subGroupId, count, string _) = FromIQS.GetCommandText(_IqsConnectionString, _Logistics, descriptions[0], breakAfter, preWait);
|
|
if (subGroupId is null)
|
|
collection.Add(new(new ScopeInfo(tests[0], _OpenInsightFilePattern), lines));
|
|
else if (count is null)
|
|
collection.Add(new(new ScopeInfo(tests[0], $"{subGroupId.Value} {_OpenInsightFilePattern}"), lines));
|
|
else
|
|
collection.Add(new(new ScopeInfo(tests[0], $"{subGroupId.Value} E{count.Value} {_OpenInsightFilePattern}"), lines));
|
|
string weekOfYear = _Calendar.GetWeekOfYear(_Logistics.DateTimeFromSequence, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00");
|
|
FromIQS.Save(_OpenInsightApiECDirectory, _OpenInsightApiIFXDirectory, _Logistics, reportFullPath, logistics, descriptions.First(), lines, subGroupId, weekOfYear);
|
|
}
|
|
}
|
|
if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0)
|
|
WaitForFileConsumption(dateTime, descriptions, isDummyRun, successDirectory, duplicateDirectory, collection, duplicateFile);
|
|
}
|
|
|
|
private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime)
|
|
{
|
|
Tuple<string, Test[], JsonElement[], List<FileInfo>> results;
|
|
Tuple<string, string[], string[]> pdsf = ProcessDataStandardFormat.GetLogisticsColumnsAndBody(reportFullPath);
|
|
_Logistics = new Logistics(reportFullPath, pdsf.Item1);
|
|
SetFileParameterLotIDToLogisticsMID();
|
|
JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(pdsf);
|
|
List<pcl.Description> descriptions = pcl.ProcessData.GetDescriptions(jsonElements);
|
|
Test[] tests = (from l in descriptions select (Test)l.Test).ToArray();
|
|
if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0)
|
|
SaveOpenInsightFile(reportFullPath, dateTime, pdsf.Item1, descriptions, tests);
|
|
results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(pdsf.Item1, tests, jsonElements, new List<FileInfo>());
|
|
return results;
|
|
}
|
|
|
|
} |