MoS2/Framework/MECF.Framework.RT.EquipmentLibrary/HardwareUnits/Temps/AKunTriggerTemp/AKunTriggerTemp.cs

308 lines
11 KiB
C#
Raw Normal View History

2026-08-18 14:04:28 +08:00
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>
2026-08-20 09:10:12 +08:00
//private List<double[]> _reflects;
2026-08-18 14:04:28 +08:00
//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
2026-08-20 09:10:12 +08:00
//_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]);
//}
2026-08-18 14:04:28 +08:00
#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();
2026-08-20 09:10:12 +08:00
//_reflects = _aKunTempManager.GetReflectValue();
2026-08-18 14:04:28 +08:00
return _aKunTempManager.GetWaferTemp();
}
public override void Terminate()
{
_socketServer.Shutdown();
}
public override void Reset()
{
_timer.Start(TCP_TIME_OUT * 1000);
base.Reset();
}
}
}