using System; using System.Collections.Generic; using System.Linq; using System.Text; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Communications; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Aligners.HiWinAligner.Handlers; namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Aligners.HiWinAligner { public class HwAlignerGuide : BaseDevice, IConnection, IDevice { #region Variables private enum CommandEnum { NULL, SME11, SME21, SME31, HOM, DOC, CVN, MTM, CCD, BAL, MVR, CVF, ERS, STA, // SPS, WSZ, _WT, GLM, FWO, }; private HwAlignerGuideConnection _connection; private readonly bool _activeMonitorStatus; private readonly R_TRIG _trigCommunicationError = new(); private readonly R_TRIG _trigRetryConnect = new(); private bool _bIsDisconnect = false; private uint _iCurrentOper = 0xff; private readonly LinkedList _lstHandler = new(); private readonly object _locker = new(); #endregion #region Constructors /// /// 构造上银巡边器对象实例。 /// /// 所属模组名称。 /// 系统配置定义了当前巡边器相关配置的节点。 /// 当前巡边器名称。 public HwAlignerGuide(string module, string scRoot, string name) : base(module, name, name, name) { ScBasePath = scRoot; _activeMonitorStatus = true; } #endregion #region Properties public bool HaveWafer { get; set; } public string Address { get; set; } public bool IsConnected => _connection is { IsConnected: true }; public bool AlarmStatus { get; set; } public bool PositionComplete { get; set; } public bool MotorBusy { get; set; } public bool IsBusy { get { lock (_locker) { return _lstHandler.Count > 0 || _iCurrentOper != (uint)CommandEnum.NULL; } } } #endregion #region Private Methods private void InitData() { DATA.Subscribe($"{Module}.{Name}.HaveWafer", () => HaveWafer); } private void InitOp() { //参数保存 OP.Subscribe($"{Module}.{Name}.HwSaveParameters", (_, _) => { Set("SPS"); return true; }); //读取/设定晶圆尺寸 OP.Subscribe($"{Module}.{Name}.HwWaferSize", (_, param) => { Set("WSZ" + " " + param[0]); return true; }); //晶圆种类 OP.Subscribe($"{Module}.{Name}.HwWaferType", (_, param) => { Set("_WT" + " " + param[0]); return true; }); //寻边材质 OP.Subscribe($"{Module}.{Name}.HwWaferMaterial", (cmd, param) => { Set("GLM" + " " + param[0]); return true; }); //晶圆方向 OP.Subscribe($"{Module}.{Name}.HwWaferOrientation", (cmd, param) => { Set("FWO" + " " + param[0]); return true; }); //------------------------------------------------------------ //原点复归 OP.Subscribe($"{Module}.{Name}.HwHOM", (_, _) => MsgHome()); //晶圆确认 OP.Subscribe($"{Module}.{Name}.HwDOC", (_, _) => CheckWaferLoad()); //开启真空 OP.Subscribe($"{Module}.{Name}.HwCVN", (_, _) => OpenVacuum()); //寻边补正 OP.Subscribe($"{Module}.{Name}.HwBAL", (_, _) => MsgAliger()); //关闭真空 OP.Subscribe($"{Module}.{Name}.HwCVF", (_, _) => CloseVacuum()); //移至测量中心点 OP.Subscribe($"{Module}.{Name}.HwMTM", (_, _) => MoveToRobotPutPlace()); //清除报警 OP.Subscribe($"{Module}.{Name}.HwERS", (_, _) => ClearError()); //马达激磁 OP.Subscribe($"{Module}.{Name}.HwSME", (_, _) => { InitMachine(); return true; }); //相对位移 OP.Subscribe($"{Module}.{Name}.HwMVR", (cmd, param) => { Set("MVR"); return true; }); // OP.Subscribe($"{Module}.{Name}.HwAbort", (cmd, param) => { Abort(); return true; }); } private bool OnTimer() { try { _connection.MonitorTimeout(); //若断,重连 if ((!_connection.IsConnected) || _connection.IsCommunicationError || _bIsDisconnect) { _trigRetryConnect.CLK = _bIsDisconnect; //重连机制要改,timeout之后,要是用心跳方式探测重连 _trigRetryConnect.CLK = _bIsDisconnect; if (_connection.Connect()) { _bIsDisconnect = false; // if (_trigRetryConnect.Q) { EV.PostInfoLog(Module, $"{Module}.{Name} connected"); LOG.Write($"{Module}.{Name} connected"); } } else { if (_trigRetryConnect.Q) { EV.PostInfoLog(Module, $"Trying to connect {Module}.{Name} with address: {_connection.Address}"); LOG.Write($"Trying to connect {Module}.{Name} with address: {_connection.Address}"); } } } //处理命令队列 HandlerBase handler = null; if (!_connection.IsBusy) { lock (_locker) { if (_lstHandler.Count == 0 && _activeMonitorStatus && !IsBusy) { //Query(); } if (_lstHandler.Count > 0) { handler = _lstHandler.First.Value; _lstHandler.RemoveFirst(); } } if (handler != null) { _connection.Execute(handler); } } // return true; } catch (Exception ex) { LOG.Write(ex); } return true; } internal void NoteError() { } protected override void HandleMonitor() { try { _trigCommunicationError.CLK = _connection.IsCommunicationError; if (_trigCommunicationError.Q) { EV.PostAlarmLog(Module, $"{Module}.{Name} communication error, {_connection.LastCommunicationError}"); } } catch (Exception ex) { LOG.Write(ex); } } #endregion #region Methods public bool Connect() { return true; } public bool Disconnect() { return true; } public bool Initialize() { // string portName = SC.GetStringValue($"{_scRoot}.{Module}.{Name}.Address"); var portName = SC.GetStringValue($"{ScBasePath}.Address"); Address = portName; var scEnableLog = $"{ScBasePath}.EnableLogMessage"; var enableLog = SC.GetValue(scEnableLog); SC.RegisterValueChangedCallback(scEnableLog, scValue => { if (scValue is bool bEnableLog) _connection.EnableLog(bEnableLog); }); _connection = new HwAlignerGuideConnection(portName); _connection.EnableLog(enableLog); if (_connection.Connect()) { EV.PostInfoLog(Module, $"{Module}.{Name} Connected"); } var periodicJob = new PeriodicJob(200, OnTimer, $"{Name} MonitorHandler", true); InitData(); InitOp(); ConnectionManager.Instance.Subscribe($"{Name}", this); return true; } public void Abort() { } /// /// 初始化当前巡边器。 /// public void InitMachine() { lock (_locker) { _lstHandler.Clear(); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "SME11", "SME 11")); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "SME12", "SME 21")); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "SME13", "SME 31")); } } /// /// 开始巡边。 /// public void Aligner() { lock (_locker) { _lstHandler.Clear(); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVN", "CVN")); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "BAL", "BAL")); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVF", "CVF")); } } /// /// 回机械零点。 /// /// /// True:命令发送成功。 ///
/// False:命令发送失败 ///
public bool MsgHome() { //_lstHandler.Clear(); lock (_locker) { _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "HOM", "HOM", 30)); } return true; } /// /// 检测当前巡边器上是否有晶圆。 /// /// /// True:命令发送成功。 ///
/// False:命令发送失败 ///
public bool CheckWaferLoad() { lock (_locker) { _lstHandler.AddLast(new HwAlignerWaferCheckHandler(this)); } return true; } /// /// 打开当前巡边器的真空吸附。 /// /// /// True:命令发送成功。 ///
/// False:命令发送失败 ///
public bool OpenVacuum() { lock (_locker) { _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVN", "CVN")); } return true; } /// /// 关闭当前巡边器的真空吸附。 /// /// /// True:命令发送成功。 ///
/// False:命令发送失败 ///
public bool CloseVacuum() { lock (_locker) { _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVF", "CVF")); } return true; } public bool MoveToRobotPutPlace() { lock (_locker) { _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "MTM", "MTM")); } return true; } public bool MsgAliger() { lock (_locker) { _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "BAL", "BAL")); } return true; } public bool DoAliger() { lock (_locker) { _lstHandler.Clear(); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVN", "CVN")); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "BAL", "BAL")); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "CVF", "CVF")); } return true; } public bool ClearError() { lock (_locker) { _lstHandler.Clear(); _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, "ERS", "ERS")); } return true; } /// /// 新增一条命令到命令执行列队。 /// /// 命令字符。 public void Set(string command) { lock (_locker) { _lstHandler.AddLast(new HwAlignerGuideSetHandler(this, command, command)); } } public void Terminate() { try { if (_connection != null) { _connection.Disconnect(); _connection = null; } } catch (Exception ex) { LOG.Write(ex); } } public void Reset() { _bIsDisconnect = _connection.IsCommunicationError; //这里重置了CommunicationError ,就是去了OnTimer里面的重连的触发,所以需要另设变量以触发之(使用timeout来触发的情况) _connection.SetCommunicationError(false,""); _trigCommunicationError.RST = true; _trigRetryConnect.RST = true; _iCurrentOper = (uint)CommandEnum.NULL; lock (_locker) _lstHandler.Clear(); } public void SetCurrentOper() { _iCurrentOper = (uint)CommandEnum.CCD; } internal bool ParseData(string name, byte[] buffer, out bool bResult) { bResult = true; var sAnswer = Encoding.ASCII.GetString(buffer); if (sAnswer.Contains("END")) { _iCurrentOper = (uint)CommandEnum.NULL; return true; } if (sAnswer.Contains("ERR")) { lock (_locker) { _lstHandler.Clear(); } _iCurrentOper = (uint)CommandEnum.NULL; bResult = false; return true; //Handled } return false; } internal bool CheckWaferDataA(string name, byte[] buffer, out bool bResult) { bResult = true; var sAnswer = Encoding.ASCII.GetString(buffer.ToArray()); if (sAnswer.Contains("END")) { HaveWafer = sAnswer.Contains("1\r\nEND"); _iCurrentOper = (uint)CommandEnum.NULL; return true; } if (sAnswer.Contains("ERR")) { lock (_locker) { _lstHandler.Clear(); } _iCurrentOper = (uint)CommandEnum.NULL; bResult = false; return false; //Handle } return false; } } #endregion }