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 ( ) ;
}
}
}