MET08DDUPSP1TBI - v2.43.4 - Builtin MonA,
Run with layer and 1T
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user