308 lines
11 KiB
C#
308 lines
11 KiB
C#
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();
|
||
}
|
||
}
|
||
} |