MET08DDUPSP1TBI - v2.43.4 - Builtin MonA,

Run with layer and 1T
This commit is contained in:
2022-09-07 12:38:37 -07:00
parent 90c44cffbb
commit 65b4ae1463
15 changed files with 859 additions and 185 deletions

View File

@ -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

View File

@ -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<Item> Items { get; }
public Job(string lsl2SQLConnectionString, string mid)
public Job(string lsl2SQLConnectionString, string metrologyFileShare, string mid)
{
const int zero = 0;
Items = new List<Item>();
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<Input>(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<Run[]>(json); }
catch (Exception)
{ runs = Array.Empty<Run>(); }
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<Run[]>(json); }
catch (Exception)
{ runs = Array.Empty<Run>(); }
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);
}
}

View File

@ -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);

View File

@ -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; }
}

View File

@ -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;