MoS2/Framework/MECF.Framework.RT.EquipmentLibrary/HardwareUnits/Temps/AKunTriggerTemp/AKunTriggerTemp.cs
2026-08-18 14:04:28 +08:00

308 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Kxware.Connectivity.Remoting.Messages;
using MECF.Framework.Common.Communications.Tcp.Socket.Framing;
using MECF.Framework.Common.Communications.Tcp.Socket.Server.APM;
using MECF.Framework.Common.Communications.Tcp.Socket.Server.APM.EventArgs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Xml;
namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps
{
/// <summary>
/// 昂坤测温使用Trigger触发
/// 返回温度数组依次包含CH平均Wafer平均Tray平均
/// 目前仅支持一个托盘计算
/// </summary>
public class AKunTriggerTemp : TempSensorBase
{
private TcpSocketServer _socketServer;
private TcpSocketSession _session;
private int _port;
private string _ip;
/// <summary>
/// 温度不变Trig
/// </summary>
private readonly R_TRIG _rTrigTempNoChange = new();
/// <summary>
/// 通讯超时时间秒
/// </summary>
private const int TCP_TIME_OUT = 6;
/// <summary>
/// 晶圆的数量
/// </summary>
private readonly int _waferNum=1;
/// <summary>
/// 晶圆的数量
/// </summary>
private readonly int _trayNum=1;
///// <summary>
///// 一个测温通道对应一个集合索引
///// </summary>
//private readonly List<AKunTriggerChannelWaferTempData[]> _chWaferTempDataList=new ();
private double _trayTemp;
//private bool[] _calZone;
/// <summary>
/// 反射率数组
/// </summary>
private List<double[]> _reflects;
//private AKunTriggerChannelWaferTempData[] _tempDataArray;
private AKunTriggerTempDataManager _aKunTempManager;
/// <summary>
/// 定义时钟监视数据发送,有可能通讯还在数据不发送
/// </summary>
private DeviceTimer _timer = new DeviceTimer();
public AKunTriggerTemp(string module, XmlElement node, string ioModule = "") : base(module, node, ioModule)
{
var maxWaferNum = node.GetAttribute("WaferNum");
//if (string.IsNullOrWhiteSpace(maxWaferNum))
// _waferNum = SC.GetStringValue($"System.InchType") == "Inch6" ? 8 : 5;
//else
// int.TryParse(maxWaferNum, out _waferNum);
//var trayNum = node.GetAttribute("TrayNum");
//if (!string.IsNullOrWhiteSpace(trayNum) && int.TryParse(trayNum, out var maxT))
// _trayNum = maxT;
RTrigs.Add(_rTrigTempNoChange);
}
protected override void InitTempDataFilter()
{
TempBasFunction = new TempBasFunction(Name, MinimalTemp, _waferNum);
_aKunTempManager = new(_waferNum, MinimalTemp);
_trayTemp = MinimalTemp;
TempBasFunction.SetTempCh(_waferNum);
Temp = Enumerable.Repeat(MinimalTemp, _waferNum).ToArray();
//_calZone = new bool[_waferNum];
//PM可以选的Wafer注册,初始索引需要加上通道数
for (var i = 0; i < _waferNum; i++)
{
var index = i;
DATA.Subscribe($"TempSensor.{Name}.Wafer{i + 1}.Temp", () => Temp[index]);
}
//PM可以选的Tray注册,初始索引需要加上通道数和Wafer数量
DATA.Subscribe($"TempSensor.{Name}.Tray.Temp", () => _trayTemp);
//DATA.Subscribe($"TempSensor.{Name}.CalZone", () => _calZone);
#region
_reflects = Enumerable
.Range(0, _waferNum)
.Select(i => new double[3])
.ToList();
for (int i = 0; i < _waferNum; i++)
{
var index = i;
DATA.Subscribe($"TempSensor.{Name}.Wafer{index + 1}.Reflect1", () => _reflects[index][0]);
DATA.Subscribe($"TempSensor.{Name}.Wafer{index + 1}.Reflect2", () => _reflects[index][1]);
DATA.Subscribe($"TempSensor.{Name}.Wafer{index + 1}.Reflect3", () => _reflects[index][2]);
}
#endregion
OP.Subscribe($"{Module}.AKunTriggerTemp.MarkerActive", (function, args) =>
{
ProcessWriteMessage($"MarkerActive={args[0]}");
return true;
});
OP.Subscribe($"{Module}.AKunTriggerTemp.RunID", (function, args) =>
{
ProcessWriteMessage($"RunID={args[0]}");
return true;
});
OP.Subscribe($"{Module}.AKunTriggerTemp.StepCode", (function, args) =>
{
ProcessWriteMessage($"StepCode={args[0]}");
return true;
});
}
protected override bool HandleInitialize()
{
InitController();
return true;
}
private void InitController()
{
var data = SC.GetStringValue($"{ScBasePath}.{Name}.Address").Split(':');
_ip = data[0]; ;
_port = Convert.ToInt32(data[1]);
TcpSocketServerConfiguration config = new TcpSocketServerConfiguration()
{
FrameBuilder = new LineBasedFrameBuilder(new LineDelimiter("\r\n")),
};
_socketServer = new TcpSocketServer(IPAddress.Parse(_ip), _port, config);
_socketServer.ClientConnected += ClientConnected;
_socketServer.ClientDisconnected += ClientDisconnected;
_socketServer.ClientDataReceived += ClientDataReceived;
}
protected override void HandleMonitor()
{
if (_socketServer == null)
return;
if (!_socketServer.IsListening)
{
_socketServer.Listen();
}
if (_timer.IsTimeout())
{
_timer.Stop();
if (IsProcess())
{
TempBasFunction.PMPostLog(Module, $"TCP server received temp data timeout {TCP_TIME_OUT}s, {_ip}:{_port}, {Module}.{Name}", EV.PostWarningLog);
TempBasFunction.SetPmIoForInterlock(Module, true);
}
}
}
private void ClientDataReceived(object sender, TcpClientDataReceivedEventArgs e)
{
OnReadMessage(Encoding.UTF8.GetString(e.Data, e.DataOffset, e.DataLength));
}
private void OnReadMessage(string message)
{
_timer.Stop();
if (IsEnableLog)
LOG.Write(message);
if (_aKunTempManager.ProcessReceivedData(message))
TempReadThread();
else
TempBasFunction.PMPostLog(Module, $"TCP server received error temp data from AKun {_ip}:{_port}, {Module}.{Name}\r\ninf:'{message}'", EV.PostWarningLog);
_timer.Start(TCP_TIME_OUT * 1000);
}
private void ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e)
{
_socketServer.CloseSession(_session.SessionKey);
_session = null;
TempBasFunction.PMPostLog(Module, $"Can not connect with {_ip}:{_port}, {Module}.{Name}", EV.PostWarningLog);
TempBasFunction.SetPmIoForInterlock(Module, true);
}
private void ClientConnected(object sender, TcpClientConnectedEventArgs e)
{
_session = e.Session;
TempBasFunction.PMPostLog(Module, $"Connected with {_ip}:{_port}, {Module}.{Name}", EV.PostInfoLog);
TempBasFunction.SetPmIoForInterlock(Module, false);
_timer.Start(TCP_TIME_OUT * 1000);
}
private void ProcessWriteMessage(string msg)
{
TempBasFunction.PMPostLog(Module, $"{Name} Tcp Socket Write Message {msg}", EV.PostInfoLog);
if (_session != null)
_session.Send(Encoding.ASCII.GetBytes(msg));
else
TempBasFunction.PMPostLog(Module, $"Tcp Socket Server is null {_ip}:{_port}, {Module}.{Name}", EV.PostWarningLog);
}
protected override bool DoTempReadThread()
{
return true;
}
private bool TempReadThread()
{
// get temp. points according to the "IsSimulatorMode" system config.
var temps = IsSimMode ? RandomTemps(_waferNum) : HandleReadTemp();
_rTrigReadTempFailed.CLK = temps == null || temps.Length != (_waferNum);
if (_rTrigReadTempFailed.Q)
{
LOG.Error(temps != null
? $"{this} {_waferNum} temperature data wanted but {temps.Length} points read."
: $"{this} None temperature data read from controller.");
}
// Too less temp. points read from the sensor.
if (_rTrigReadTempFailed.M)
return true;
if (IsProcess() && AllTempNoChange(temps))//检测所有通道温度是否变化
return true;
// Get the right temp value from the filter
for (var i = 0; i < Temp.Length; i++)
{
Temp[i] = temps[i];
}
return true;
}
private bool AllTempNoChange(double[] tempArray)
{
int noChangeCount = TempBasFunction.AllTempNoChangeCount(tempArray, out string resuonInf);
if (noChangeCount >= 18)
{
_rTrigTempNoChange.CLK = true;
if (_rTrigTempNoChange.Q)
{
TempBasFunction.PMPostLog(Module, $"{this} all temp no change: \r\n" +
$"{resuonInf}", EV.PostWarningLog);
}
return true;
}
return false;
}
protected override double[] HandleReadTemp()
{
//昂坤的温度数据上位机在这里被动接受
//_calZone = _aKunTempManager.GetCalZone();
_trayTemp = _aKunTempManager.GetTrayTemp();
_reflects = _aKunTempManager.GetReflectValue();
return _aKunTempManager.GetWaferTemp();
}
public override void Terminate()
{
_socketServer.Shutdown();
}
public override void Reset()
{
_timer.Start(TCP_TIME_OUT * 1000);
base.Reset();
}
}
}