|
@@ -0,0 +1,289 @@
|
|
|
+using Aitex.Core.RT.Log;
|
|
|
+using Aitex.Core.RT.SCCore;
|
|
|
+using Aitex.Core.Util;
|
|
|
+using MECF.Framework.Common.Communications;
|
|
|
+using MECF.Framework.Common.Equipment;
|
|
|
+using MECF.Framework.Common.SubstrateTrackings;
|
|
|
+using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.IO.Ports;
|
|
|
+using System.Linq;
|
|
|
+using System.Runtime.InteropServices;
|
|
|
+using System.Text;
|
|
|
+using System.Text.RegularExpressions;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using Venus_Core;
|
|
|
+
|
|
|
+namespace Venus_RT.Devices.PreAligner
|
|
|
+{
|
|
|
+ public class SunWayVPA : IPreAlign
|
|
|
+ {
|
|
|
+ private AsyncSerialPort _serialport;//串口
|
|
|
+ private string _newLine = "\r\n";//结束符号
|
|
|
+ private object _locker = new object();//锁变量
|
|
|
+ private bool _IsAsciiMode = true;
|
|
|
+ private PeriodicJob _thread;
|
|
|
+ private RState _state;
|
|
|
+ private Regex _catchErrorCode = new Regex(@"(?<=_ERR )(.*)");
|
|
|
+ private Regex _checkData = new Regex(@"(?<=DATA)(.*)");
|
|
|
+ private LinkedList<string> _lstMessage = new LinkedList<string>();
|
|
|
+ private ModuleName _module;
|
|
|
+
|
|
|
+ private enum AlignerAction
|
|
|
+ {
|
|
|
+ Home,
|
|
|
+ Align,
|
|
|
+ AlignWithAngle,
|
|
|
+ Reset,
|
|
|
+ Scan,
|
|
|
+ RsLT,
|
|
|
+ ServeUp
|
|
|
+ }
|
|
|
+ private Dictionary<int, string> _ErrorCode2Msg = new Dictionary<int, string>()
|
|
|
+ {
|
|
|
+ { 16 , "" },
|
|
|
+ };
|
|
|
+ private Dictionary<AlignerAction, string> _Command2Msg = new Dictionary<AlignerAction, string>()
|
|
|
+ {
|
|
|
+ //Action
|
|
|
+ { AlignerAction.Align , "ALIGNER ALGN" },//旋转到预设的站点方向
|
|
|
+ { AlignerAction.AlignWithAngle, "MOVT REL" },//旋转到指定的角度
|
|
|
+ { AlignerAction.Home , "ALIGNER HOME" },//Home 初始化时 error时用
|
|
|
+ { AlignerAction.Reset , "RSET" },//重置 error时用
|
|
|
+ { AlignerAction.Scan , "ALIGNER SCAN" },//扫描整个Wafer参数
|
|
|
+ { AlignerAction.RsLT , "ALIGNER RSLT" },
|
|
|
+ { AlignerAction.ServeUp , "SET SERVOS ON"}
|
|
|
+ //Read
|
|
|
+ //{ "" , "RQCD" },
|
|
|
+ //{ "" , "RQCCDPOS" },
|
|
|
+ //{ "" , "RQID" },
|
|
|
+ //{ "" , "RQPS" },
|
|
|
+ //Set
|
|
|
+ //{ "" , "" },
|
|
|
+ //Welding
|
|
|
+ //{ "" , "SVCD" },
|
|
|
+ };
|
|
|
+ public ModuleName Module => _module;
|
|
|
+ public bool IsConnect => _serialport.IsConnected;
|
|
|
+ public RState Status => _state;//状态
|
|
|
+
|
|
|
+ public bool IsError => _state == RState.Failed || _state == RState.Timeout;
|
|
|
+
|
|
|
+ private int _ROffset = 0;
|
|
|
+ private int _TOffset = 0;
|
|
|
+ private bool _IsOverRange = false;
|
|
|
+ public int ROffset => _ROffset;
|
|
|
+
|
|
|
+ public int TOffset => _TOffset;
|
|
|
+
|
|
|
+ public bool IsOverRange => _IsOverRange;
|
|
|
+
|
|
|
+ public SunWayVPA(ModuleName module)
|
|
|
+ {
|
|
|
+ _module = module;
|
|
|
+ string port = SC.GetStringValue($"{module}.AlignerPort");
|
|
|
+ _serialport = new AsyncSerialPort(port, 9600, 8, Parity.None, StopBits.One, _newLine, _IsAsciiMode);
|
|
|
+ _serialport.Open();
|
|
|
+ WaferManager.Instance.SubscribeLocation(ModuleName.Aligner1, 1);
|
|
|
+ _serialport.OnDataChanged += OnReceiveData;
|
|
|
+ _state = RState.Init;
|
|
|
+ _thread = new PeriodicJob(50, OnTimer, "OnTimer->Aligner1");
|
|
|
+ _thread.Start();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnReceiveData(string obj)
|
|
|
+ {
|
|
|
+ lock (_locker)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(_newLine))//没有CR
|
|
|
+ {
|
|
|
+ _lstMessage.AddLast(obj);//将消息添加到最后
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ string[] array = obj.Split(_newLine.ToCharArray());//按照cr分开通讯数据
|
|
|
+ foreach (string text in array)
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrEmpty(text))
|
|
|
+ {
|
|
|
+ _lstMessage.AddLast(text + _newLine);//存进list中等待处理
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //定时器处理新信息为状态
|
|
|
+ private bool OnTimer()
|
|
|
+ {
|
|
|
+ //线程锁
|
|
|
+ lock (_locker)
|
|
|
+ {
|
|
|
+ //采用ascii码模式处理
|
|
|
+ if (_IsAsciiMode)
|
|
|
+ {
|
|
|
+ //存在尚未处理的信息
|
|
|
+ while (_lstMessage.Count > 0)
|
|
|
+ {
|
|
|
+ //获取头上的数据
|
|
|
+ string handlemsg = _lstMessage.First.Value;
|
|
|
+ Handlemessage(handlemsg);
|
|
|
+ _lstMessage.RemoveFirst();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //采用binary模式处理
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Handlemessage(string handlemsg)
|
|
|
+ {
|
|
|
+ //需要按类型进行处理 Action需要将其error
|
|
|
+ bool IsAction = true;
|
|
|
+ handlemsg = handlemsg.Trim();
|
|
|
+ if (IsAction)
|
|
|
+ {
|
|
|
+ switch (handlemsg)
|
|
|
+ {
|
|
|
+ //正确执行
|
|
|
+ case "_RDY":
|
|
|
+ _state = RState.End;
|
|
|
+ break;
|
|
|
+ //返回
|
|
|
+ default:
|
|
|
+ if (_checkData.IsMatch(handlemsg))
|
|
|
+ {
|
|
|
+ string[] data = handlemsg.Split(' ');
|
|
|
+ _ROffset = Convert.ToInt32(data[2]);
|
|
|
+ _TOffset = Convert.ToInt32(data[3]);
|
|
|
+
|
|
|
+ if (data[5] == "Y")
|
|
|
+ {
|
|
|
+ _IsOverRange = true;
|
|
|
+ LOG.Write(eEvent.WARN_DEVICE_INFO, Module, $"Wafer offset is over range");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data[5] == "N")
|
|
|
+ {
|
|
|
+ _IsOverRange = false;
|
|
|
+ LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Wafer offset is in range");
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG.Write(eEvent.EV_DEVICE_INFO, Module, $"Ro{_ROffset} To{_TOffset}");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _state = RState.Failed;
|
|
|
+ //分两种 1、不按格式的未知错误 2、有错误码的
|
|
|
+ if (_catchErrorCode.IsMatch(handlemsg))
|
|
|
+ {
|
|
|
+ int errorcode = Convert.ToInt32(_catchErrorCode.Match(handlemsg).Value);
|
|
|
+ if (_ErrorCode2Msg.ContainsKey(errorcode))
|
|
|
+ {
|
|
|
+ LOG.Write(eEvent.ERR_DEVICE_INFO, Module, _ErrorCode2Msg[errorcode]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LOG.Write(eEvent.ERR_DEVICE_INFO, Module, $"未知错误码{errorcode}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LOG.Write(eEvent.ERR_DEVICE_INFO, Module, "未收录相关错误");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool SendMessage(string msg, params string[] args)
|
|
|
+ {
|
|
|
+ _state = RState.Running;
|
|
|
+ if (args.Length > 0)//含参
|
|
|
+ {
|
|
|
+ foreach (string arg in args)
|
|
|
+ msg = msg + " " + arg;
|
|
|
+ LOG.WriteSingeLine(eEvent.EV_DEVICE_INFO, _module, $"Send Command to SunWay Aligner: {msg}");
|
|
|
+ return _serialport.Write(msg + _newLine);
|
|
|
+ }
|
|
|
+ else//空参
|
|
|
+ {
|
|
|
+ LOG.WriteSingeLine(eEvent.EV_DEVICE_INFO, _module, $"Send Command to SunWay Aligner: {msg}");
|
|
|
+ return _serialport.Write(msg + _newLine);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool Align()
|
|
|
+ {
|
|
|
+ if (!CanSendCommand())
|
|
|
+ return false;
|
|
|
+ return SendMessage(_Command2Msg[AlignerAction.Align]);
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool AlignWithAngle(float angle)
|
|
|
+ {
|
|
|
+ if (!CanSendCommand())
|
|
|
+ return false;
|
|
|
+ int ang = (int)Math.Floor(angle);//不能用Convert.toInt32("angle") 其遵守四舍五入 此处需向上取整
|
|
|
+ return SendMessage(_Command2Msg[AlignerAction.AlignWithAngle], ang.ToString());
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool Home()
|
|
|
+ {
|
|
|
+ return SendMessage(_Command2Msg[AlignerAction.Home]);
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool QueryOffset()
|
|
|
+ {
|
|
|
+ if (!CanSendCommand())
|
|
|
+ return false;
|
|
|
+ return SendMessage(_Command2Msg[AlignerAction.RsLT]);
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool ReSet()
|
|
|
+ {
|
|
|
+ if (!IsError)
|
|
|
+ return false;
|
|
|
+ return SendMessage(_Command2Msg[AlignerAction.Reset]);
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool SCAN()
|
|
|
+ {
|
|
|
+ if (!CanSendCommand())
|
|
|
+ return false;
|
|
|
+ return SendMessage(_Command2Msg[AlignerAction.Scan]);
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool ServeUp()
|
|
|
+ {
|
|
|
+ return SendMessage(_Command2Msg[AlignerAction.ServeUp]);
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool CanSendCommand()
|
|
|
+ {
|
|
|
+ if (Status == RState.Init)
|
|
|
+ {
|
|
|
+ LOG.Write(eEvent.ERR_DEVICE_INFO, _module, "Aligner is not homed, please home first.");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else if (Status == RState.Running)
|
|
|
+ {
|
|
|
+ LOG.Write(eEvent.ERR_DEVICE_INFO, _module, "Aligner is busy, please wait a minute");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else if (Status == RState.Failed || Status == RState.Timeout)
|
|
|
+ {
|
|
|
+ LOG.Write(eEvent.ERR_DEVICE_INFO, _module, "Aligner has a error, please check and fix the hardware issue and home it");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|