2026-08-18 14:04:28 +08:00
|
|
|
|
using Aitex.Core.RT.DataCenter;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
|
|
namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps
|
|
|
|
|
|
{
|
|
|
|
|
|
public enum DataType
|
|
|
|
|
|
{
|
|
|
|
|
|
Wafer,
|
|
|
|
|
|
Tray,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 测温点位置
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public enum EnumZoneNum
|
|
|
|
|
|
{
|
|
|
|
|
|
Center,
|
|
|
|
|
|
CenterEdge,
|
|
|
|
|
|
Edge
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class AKunTriggerChannelWaferTempData
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建通道对应的单个晶圆温度对象
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="waferNum">晶圆编号</param>
|
|
|
|
|
|
/// <param name="ch">测温设备通道编号</param>
|
|
|
|
|
|
/// <param name="name">当前晶圆对象的名称,Wafer or Tray,测温对象也能反馈Tray温度</param>
|
|
|
|
|
|
public AKunTriggerChannelWaferTempData(int waferNum, int ch = 1, string name = "Wafer")
|
|
|
|
|
|
{
|
|
|
|
|
|
Detector = ch;
|
|
|
|
|
|
WaferNum = waferNum;
|
|
|
|
|
|
WaferName = $"CH{Detector}.{name}{waferNum}"; //eg: CH1.Wafer1 CH1.Wafer2 CH2.Wafer1 CH2.Wafer2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 通道编号,默认为1
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int Detector { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public string WaferName { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public int WaferNum { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public DataType Type { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public double Temp { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public int ZoneNum { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public EnumZoneNum ZoneNumSelect { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 0表示无效晶圆代表Dummy晶圆或者空位,此位置的温度不能参与STC控温
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int PocketNum { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The reflection of 404nm
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public double Reflect1 { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The reflection of 633nm.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public double Reflect2 { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The reflection of 950nm.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public double Reflect3 { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public double Curvature { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// false不参与控温,晶圆温度是否参与区域计算,不放片或者放Dummy时,不参与区域计算
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool CalZone { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public void UpData(AKunTriggerChannelWaferTempData newData)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 确保传入的 newData 对象不为空
|
|
|
|
|
|
if (newData == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new ArgumentNullException(nameof(newData));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Detector = newData.Detector;
|
|
|
|
|
|
WaferNum = newData.WaferNum;
|
|
|
|
|
|
Temp = newData.Temp;
|
|
|
|
|
|
ZoneNum = newData.ZoneNum;
|
|
|
|
|
|
ZoneNumSelect = newData.ZoneNumSelect;
|
|
|
|
|
|
Reflect1 = newData.Reflect1;
|
|
|
|
|
|
Curvature = newData.Curvature;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class AKunTriggerTempDataManager(int waferNum, double minTemp)
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly int _waferNum = waferNum;
|
|
|
|
|
|
private double _minTemp = minTemp;
|
|
|
|
|
|
|
|
|
|
|
|
private List<AKunTriggerChannelWaferTempData> _waferTempDataList = new();
|
|
|
|
|
|
private static readonly object _lock = new object();
|
|
|
|
|
|
|
|
|
|
|
|
#region 重新整理温度解析
|
|
|
|
|
|
|
|
|
|
|
|
public bool ProcessReceivedData(string tcpReceive)
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
|
|
|
|
|
List<AKunTriggerChannelWaferTempData> tempDataList = new List<AKunTriggerChannelWaferTempData>();
|
|
|
|
|
|
AKunTriggerChannelWaferTempData aKunChWaferTempData;
|
|
|
|
|
|
string[] keyValuePairs = tcpReceive.Split('\0');
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < keyValuePairs.Length - 1; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
aKunChWaferTempData = new AKunTriggerChannelWaferTempData(-999);
|
|
|
|
|
|
string[] keyValues = keyValuePairs[i].Split(',');
|
|
|
|
|
|
foreach (string pair in keyValues)
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] keyValue = pair.Split('=');
|
|
|
|
|
|
switch (keyValue[0])
|
|
|
|
|
|
{
|
|
|
|
|
|
case "Detector":
|
|
|
|
|
|
aKunChWaferTempData.Detector = int.Parse(keyValue[1]);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "PocketNum":
|
|
|
|
|
|
aKunChWaferTempData.PocketNum = int.Parse(keyValue[1]);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "WaferNum":
|
|
|
|
|
|
aKunChWaferTempData.WaferNum = int.Parse(keyValue[1]);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "CalZone":
|
|
|
|
|
|
aKunChWaferTempData.CalZone = int.Parse(keyValue[1]) == 1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "TTemp":
|
|
|
|
|
|
aKunChWaferTempData.Temp = double.Parse(keyValue[1]);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "ZoneNum":
|
|
|
|
|
|
aKunChWaferTempData.ZoneNum = int.Parse(keyValue[1]);
|
|
|
|
|
|
aKunChWaferTempData.ZoneNumSelect =
|
|
|
|
|
|
(EnumZoneNum)Enum.Parse(typeof(EnumZoneNum), keyValue[1]);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "Reflec1":
|
|
|
|
|
|
aKunChWaferTempData.Reflect1 = double.Parse(keyValue[1]);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "Reflec2":
|
|
|
|
|
|
aKunChWaferTempData.Reflect2 = double.Parse(keyValue[1]);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "Reflec3":
|
|
|
|
|
|
aKunChWaferTempData.Reflect3 = double.Parse(keyValue[1]);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "Curvature":
|
|
|
|
|
|
aKunChWaferTempData.Curvature = double.Parse(keyValue[1]);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (aKunChWaferTempData.WaferNum == -999)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
tempDataList.Add(aKunChWaferTempData);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_waferTempDataList = tempDataList;
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool[] GetCalZone()
|
|
|
|
|
|
{
|
|
|
|
|
|
bool[] calZone = new bool[_waferNum];
|
|
|
|
|
|
if (_waferTempDataList.Count < _waferNum)
|
|
|
|
|
|
return calZone;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < _waferNum; i++) //只有前面几个数据,是需要统计是否参与计算
|
|
|
|
|
|
{
|
|
|
|
|
|
calZone[i] = _waferTempDataList[i].CalZone;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return calZone;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public double[] GetWaferTemp()
|
|
|
|
|
|
{
|
|
|
|
|
|
double[] waferTemps = Enumerable.Repeat(_minTemp, _waferNum).ToArray();
|
|
|
|
|
|
if (_waferTempDataList.Count < _waferNum)
|
|
|
|
|
|
return waferTemps;
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-08-20 09:10:12 +08:00
|
|
|
|
//for (int i = 0; i < _waferNum; i++) //只有前面几个温度数据,才是需要统计的
|
2026-08-18 14:04:28 +08:00
|
|
|
|
//{
|
2026-08-20 09:10:12 +08:00
|
|
|
|
// waferTemps[i] = _waferTempDataList[i].Temp;
|
2026-08-18 14:04:28 +08:00
|
|
|
|
//}
|
|
|
|
|
|
|
2026-08-20 09:10:12 +08:00
|
|
|
|
for (int i = 0; i < _waferNum; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
//根据编号,获取同一分区所有温度数据
|
|
|
|
|
|
var tempCaches = _waferTempDataList.Where(item => item.PocketNum == i + 1);
|
|
|
|
|
|
if (tempCaches != null && tempCaches.Count() > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
//同一分区所有温度数据,查找第一个CalZone为true的温度数据
|
|
|
|
|
|
var matchedItem = tempCaches.Where(item => item.CalZone).FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
|
|
if (matchedItem != null)
|
|
|
|
|
|
waferTemps[i] = matchedItem.Temp;
|
|
|
|
|
|
else
|
|
|
|
|
|
waferTemps[i] = tempCaches.First().Temp;//未设置CalZone为true,使用当前分区第一个数据作为默认温度值
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
waferTemps[i] = -1;//没有分区温度是乱的无法解析,使用-1作为提示
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-18 14:04:28 +08:00
|
|
|
|
return waferTemps;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public double GetTrayTemp()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_waferTempDataList.Count == 0)
|
|
|
|
|
|
return _minTemp;
|
|
|
|
|
|
|
|
|
|
|
|
return _waferTempDataList[_waferTempDataList.Count - 1].Temp; //最后一个数据才是Tray温度
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion 重新整理温度解析
|
|
|
|
|
|
|
|
|
|
|
|
public List<double[]> GetReflectValue()
|
|
|
|
|
|
{
|
|
|
|
|
|
List<double[]> reflectList = Enumerable.Range(0, _waferNum)
|
|
|
|
|
|
.Select(_ => new double[3]) // 每个数组默认元素为 0
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
if (_waferTempDataList.Count < _waferNum)
|
|
|
|
|
|
return reflectList;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < _waferNum; i++) //只有前面几个反射率数据,才是需要统计的
|
|
|
|
|
|
{
|
|
|
|
|
|
var data = _waferTempDataList[i];
|
|
|
|
|
|
reflectList.Add([data.Reflect1, data.Reflect2, data.Reflect3]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return reflectList;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|