using Aitex.Core.Common;
using Aitex.Core.RT.Device;
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 System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Venus_Core;
using Venus_RT.Devices.EFEM;
using Venus_RT.Devices.TM;
using Venus_RT.Modules;
namespace Venus_RT.Devices.VCE
{
///
/// 素珀 vce 驱动
///
public class SunWayVce : VCEModuleBase
{
#region 私有变量
private AsyncSerialPort _serialport;
private string _portname;
private string _newline = "\r\n";//终止符 0D 0A
private object _locker = new object();
private bool _IsAsciiMode;
private LinkedList _lstAsciiMsgs = new LinkedList();
private PeriodicJob _thread;
private Regex _match_ReadMsg = new Regex(@"X,.*");
private Regex _matchErrorCode = new Regex(@"(?<=_ERR,)(.*)");
private ModuleName _moduleName;
private RState _status;
private string _currentMsg;
private VceMessage _currentVceMessage;
private bool _HasReceiveMsg;
private bool _IsDashWaferError;
private int _currentSlot = 0;
public override int CurrentSlot => _currentSlot;
private ModuleName _baseLPIndex
{
get
{
switch (RtInstance.ConfigType)
{
case ConfigType.VenusSE:
return ModuleName.LP1;
case ConfigType.VenusDE:
return _moduleName == ModuleName.VCEA ? ModuleName.LP1 : ModuleName.LP2;
default:
return ModuleName.System;
}
}
}
private Loadport[] _LPMs = new Loadport[1];
public override ILoadport this[ModuleName mod]
{
get
{
if (!ModuleHelper.IsLoadPort(mod))
throw new ApplicationException($"{mod} is NOT Loadport");
return _LPMs[mod - _baseLPIndex];
}
}
//待补充
private Dictionary _ErrorCode2Reason = new Dictionary()
{
{"221","错误的 ARM 参数" },
{"233","伸缩信号未使能" },
{"304","未识别的错误码" },
{"305","未识别的指令" },
{"309","不支持的指令" },
{"401","ZWAFER 参数错误" },
{"402","非法的 slot 参数" },
{"403","运动指令 RX 参数错误" },
{"404","晶圆夹取失败" },
{"405","晶圆释放失败" },
{"406","气缸压力表检测错误" },
{"407","Mapping 传感器伸出失败" },
{"408","Mapping 传感器缩回失败" },
{"409","Mapping 传感器位置数据不正确" },
{"411","Mapping 传感器高度不一致" },
{"412","工位 VIA 参数未使能" },
{"413","不是有效的 Mapping 工位" },
{"414","手指有晶圆无法 mapping" },
{"415","采集的数据个数错误" },
{"416","采集的晶圆厚度过小" },
{"417","晶圆位置超出有效范围" },
{"418","晶圆上下沿槽数错误" },
{"419","斜片上下沿槽数错误" },
{"550","工位号超范围" },
{"552","VIA 参数错误" },
{"553","MAPVIA 参数错误" },
{"600","系统未上电" },
{"602","指令正在执行中" },
{"603","系统上电失败" },
{"604","示教器控制中" },
{"605","机械手运动中停止" },
{"609","系统存在错误" },
{"610","示教盒急停启动" },
{"611","驱动器报警" },
{"629","驱动器存在报警" },
{"705","LOAD 状态未知" },
{"712","真空吸附动作失败" },
{"730","PLACE 前 LOAD 状态错误" },
{"731","PLACE 后 LOAD 状态错误" },
{"734","PLACE 执行 Extend 过程中未检测到晶圆" },
{"736","PLACE 执行 Retract 过程中检测到晶圆" },
{"740","PICK 前 LOAD 状态错误" },
{"741","PICK 后 LOAD 状态错误" },
{"744","PICK 执行 Extend 过程中检测到晶圆" },
{"745","PICK 执行 Retract 过程中未检测到晶圆" },
{"1006","非法的 IO 端口号" },
{"1314","PITCH 轴超界" },
{"1315","关节位置超界" },
{"1316","关节位置超硬限" },
{"1320","机械手跟踪差超限错误" },
{"1321","机械手发生碰撞" },
{"1322","机械手超出工作区" },
{"1323","关节速度超限" },
{"1401","当前位置不正确" },
{"1407","大气压力不足" },
{"1412","晶圆已滑出" },
{"1500","打开门失败" },
{"1501","关闭门失败" },
{"1502","门开关状态不对" },
{"1503","门松开失败" },
{"1504","门夹紧失败" },
{"1506","当前不是自动门模式" },
{"1507","开盖检测互锁" },
{"1508","开门不允许运动" },
{"1509","无 casette 盒不允许运动" },
{"1510","安全检测触发" },
{"1511","R 轴未运动到位" },
{"1512","门动作开关未使能" },
{"1513","运动开关未使能" },
};
//
#endregion
#region 暴露变量
public override bool IsConnected => _serialport.IsOpen();
public override RState Status => _status;
public override bool IsReady => _status == RState.Init || _status == RState.End;
public override bool IsError => _status == RState.Failed || _status == RState.Timeout;
public override bool IsInit => _status == RState.Init;
public override bool IsDashWaferError => _IsDashWaferError;
private string[] _slotMap = new string[25];
public string SlotMap
{
get
{
WaferInfo[] wafers = WaferManager.Instance.GetWafers(ModuleHelper.Converter(Name));
string slot = "";
for (int i = 0; i < 25; i++)
{
slot += wafers[i].IsEmpty ? "0" : "1";
}
return slot;
}
}
private bool _OutDoorIsOpen
{
get
{
switch (_moduleName)
{
case ModuleName.VCE1:
//2024-05-20 16:35:34 泓浒四边形硬件还未实现
//DEVICE.GetDevice("SETM").VCEACassPresent
return _vcedoorflag;
case ModuleName.VCEA:
if (DEVICE.GetDevice("TM").VCEACassPresent)
{
_LPMs[0].HasCassette = true;
}
else
{
_LPMs[0].HasCassette = false;
WaferManager.Instance.DeleteWafer(_LPMs[0].Module, 0, 25);
}
return !DEVICE.GetDevice("TM").VCEALOCKED;
case ModuleName.VCEB:
if (DEVICE.GetDevice("TM").VCEBCassPresent)
{
_LPMs[0].HasCassette = true;
}
else
{
_LPMs[0].HasCassette = false;
WaferManager.Instance.DeleteWafer(_LPMs[0].Module, 0, 25);
}
return !DEVICE.GetDevice("TM").VCEBLOCKED;
default:
return false;
}
}
}
public override bool OutDoorIsOpen => _OutDoorIsOpen;
private bool _vcedoorflag;
private bool _hasProtrusion
{
get
{
switch (_moduleName)
{
case ModuleName.VCE1:
//2024-05-20 16:35:34 泓浒四边形硬件还未实现
//DEVICE.GetDevice("SETM").VCEProtrusion
return true;
case ModuleName.VCEA:
if (DEVICE.GetDevice("TM").VCEAProtrusion)
{
_LPMs[0].Protrusion = true;
return true;
}
else
{
_LPMs[0].Protrusion = false;
return false;
}
case ModuleName.VCEB:
if (DEVICE.GetDevice("TM").VCEBProtrusion)
{
_LPMs[0].Protrusion = true;
return true;
}
else
{
_LPMs[0].Protrusion = false;
return false;
}
default:
return false;
}
}
}
#endregion
public SunWayVce(int slot, ModuleName moduleName) : base(slot, moduleName)
{
_moduleName = moduleName;
_vcedoorflag = false;
_IsAsciiMode = true;
_portname = SC.GetStringValue($"{moduleName}.Port");
_serialport = new AsyncSerialPort(_portname, 9600, 8, Parity.None, StopBits.One, _newline, _IsAsciiMode);
_serialport.Open();
_status = RState.Init;
_serialport.OnDataChanged += onDataChange;
_thread = new PeriodicJob(50, fnTimer, _moduleName.ToString(), true);
if (moduleName == ModuleName.VCE1)
_LPMs[0] = new Loadport(ModuleName.LP1);
else
_LPMs[0] = new Loadport((moduleName - ModuleName.VCEA) + ModuleName.LP1);
CarrierManager.Instance.DeleteCarrier(_LPMs[0].Module.ToString());
WaferManager.Instance.DeleteWafer(_LPMs[0].Module, 0, 25);
CarrierManager.Instance.SubscribeLocation(_LPMs[0].Module.ToString(), 1);
Action _subscribeLoc = (ModuleName module, int waferCount) => {
if (ModuleHelper.IsInstalled(module))
{
WaferManager.Instance.SubscribeLocation(module, waferCount);
}
};
_subscribeLoc(_LPMs[0].Module, slot);
}
private bool fnTimer()
{
lock (_locker)
{
//采用ascii传输
if (_IsAsciiMode)
{
//有数据尚未处理
while (_lstAsciiMsgs.Count > 0)
{
string _needHandle = _lstAsciiMsgs.First.Value;
HandleSingleMsg(_needHandle);
_lstAsciiMsgs.RemoveFirst();
}
}
//采用binary
else
{
}
}
return true;
}
private void HandleSingleMsg(string rawmsgs)
{
string[] msgs = rawmsgs.Split('\r');
foreach (var Msg in msgs)
{
string msg = Msg.Trim();
LOG.Write(eEvent.EV_VCE_COMMON_INFO, _moduleName, $"{_moduleName} Receive msg=>{msg}");
if (!string.IsNullOrEmpty(msg))
{
//action set petrify _BKGRDY结束
switch (_currentVceMessage.Head)
{
case VceMessageHead.Action:
case VceMessageHead.Set:
case VceMessageHead.Petrify:
switch (msg)
{
//设备收到 开始运行 目前状态在下发
case "_RDY":
LOG.Write(eEvent.EV_VCE_COMMON_INFO, _moduleName, $"vce {_currentVceMessage.Head} over");
switch (_currentVceMessage.Command)
{
case VceCommand.Home:
case VceCommand.Map:
case VceCommand.GotoLP:
_currentSlot = 0;
break;
case VceCommand.DoorClose:
_vcedoorflag = false;
break;
case VceCommand.DoorOpen:
_vcedoorflag = true;
break;
}
_status = RState.End;
break;
//异常处理
default:
_status = RState.Failed;
string reason;
Errorhandle(msg, out reason);
LOG.Write(eEvent.ERR_VCE_COMMON_Failed, _moduleName, reason);
break;
}
break;
case VceMessageHead.Read:
//如果收到的信息符合
if (_match_ReadMsg.IsMatch(msg))
{
//收到消息 用于结束
_HasReceiveMsg = true;
switch (_currentVceMessage.Command)
{
//处理wafer 信息为map数据
case VceCommand.ReadMap:
ReadMapData(msg);
break;
case VceCommand.CheckStatus:
ReadStatus(msg);
break;
}
}
//_RDY查询结束
else
{
if (msg == "_RDY")
{
if (_HasReceiveMsg)
{
_status = RState.End;
}
else
{
LOG.Write(eEvent.ERR_VCE_COMMON_Failed, _moduleName, $"Read Message is over but not receive msg! raw message:{_currentMsg}");
_status = RState.Failed;
}
}
else
{
_status = RState.Failed;
LOG.Write(eEvent.ERR_VCE_COMMON_Failed, _moduleName, $"Read Message is invalid: receive message {msg} and send message {_currentMsg}");
}
}
break;
}
}
}
}
private void ReadStatus(string msg)
{
try
{
//BRa,SLbb,CPc,WPd,ERe
string[] status = msg.Split(',');
_currentSlot = Convert.ToInt32(status[4].Substring(2, 2));
}
catch (Exception ex)
{
LOG.Write(eEvent.ERR_VCE_COMMON_Failed, _moduleName, $"illegal msg:{msg}, {ex.Message}");
}
}
private void ReadMapData(string msg)
{
//string waferinfo = "";
string[] waferitems = msg.Split(',');
//智能模式 可以识别叠片
for (int i = 2; i <= waferitems.Length - 1; ++i)
{
switch (waferitems[i])
{
case "O":
WaferManager.Instance.DeleteWafer(_LPMs[0].Module, i - 2);
break;
case "X":
WaferManager.Instance.CreateWafer(_LPMs[0].Module, i - 2, WaferStatus.Normal);
break;
case "I":
LOG.Write(eEvent.ERR_VCE_COMMON_Failed, _moduleName, $"Slot {i - 1}:Thin wafer.");
WaferManager.Instance.CreateWafer(_LPMs[0].Module, i - 2, WaferStatus.Dummy);
break;
case "T":
LOG.Write(eEvent.ERR_VCE_COMMON_Failed, _moduleName, $"Slot {i - 1}:Thick or Double wafer.");
WaferManager.Instance.CreateWafer(_LPMs[0].Module, i - 2, WaferStatus.Double);
break;
case "C":
LOG.Write(eEvent.ERR_VCE_COMMON_Failed, _moduleName, $"Slot {i - 1}:Crossed wafer.");
WaferManager.Instance.CreateWafer(_LPMs[0].Module, i - 2, WaferStatus.Double);
break;
case "?":
LOG.Write(eEvent.ERR_VCE_COMMON_Failed, _moduleName, $"Slot {i - 1}:Unknown error wafer.");
WaferManager.Instance.CreateWafer(_LPMs[0].Module, i - 2, WaferStatus.Double);
break;
default:
LOG.Write(eEvent.ERR_VCE_COMMON_Failed, _moduleName, $"Slot {i - 1} Receive Error Msg:{waferitems}");
break;
}
}
_LPMs[0].IsMapped = true;
}
private void Errorhandle(string msg, out string reason)
{
if (_matchErrorCode.IsMatch(msg))
{
//若是匹配
//包含原因
string errorcode = _matchErrorCode.Match(msg).Value;
if (_ErrorCode2Reason.ContainsKey(errorcode))
{
if (errorcode == "L13")
_IsDashWaferError = true;
reason = _ErrorCode2Reason[errorcode];
}
else
{
reason = "未找到相关Error Code";
}
}
else
{
//若不匹配
reason = "回复消息不符合标准格式";
}
}
private void onDataChange(string oneLineMessage)
{
lock (_locker)
{
if (string.IsNullOrEmpty(_newline))//没有CR
{
_lstAsciiMsgs.AddLast(oneLineMessage);//将消息添加到最后
return;
}
string[] array = oneLineMessage.Split(_newline.ToCharArray());//按照cr分开通讯数据
foreach (string text in array)
{
if (!string.IsNullOrEmpty(text))
{
_lstAsciiMsgs.AddLast(text + _newline);//存进list中等待处理
}
}
}
}
public override bool ServerUp()
{
//if (!CheckVceStatus())
// return false;
_currentVceMessage = new VceMessage { Head = VceMessageHead.Set, Command = VceCommand.ServerUp, Param = "ALL,ON" };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool HomeALL()
{
_currentVceMessage = new VceMessage { Head = VceMessageHead.Action, Command = VceCommand.Home, Param = "ALL" };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool Home(string axis)
{
_currentVceMessage = new VceMessage { Head = VceMessageHead.Action, Command = VceCommand.Home, Param = axis };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool CheckStatus()
{
if (!CheckVceStatus())
return false;
_currentVceMessage = new VceMessage { Head = VceMessageHead.Read, Command = VceCommand.CheckStatus };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool CloseDoor()
{
if (!CheckVceStatus())
return false;
_currentVceMessage = new VceMessage { Head = VceMessageHead.Action, Command = VceCommand.DoorClose };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
///
/// 开门提示
/// 在honghuVCE中没有ATM信号的内部卡控 可能会导致开门的压差
/// 因此每一次都要增加判断,只要引用此处功能的,前面都需要有判断
///
///
///
public override bool OpenDoor()
{
//如果其他指令正在执行 且
//if (!CheckVceStatus())
// return false;
if (_IsDashWaferError)
_IsDashWaferError = false;
_currentVceMessage = new VceMessage { Head = VceMessageHead.Action, Command = VceCommand.DoorOpen };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool Load()
{
if (!CheckVceStatus())
return false;
_currentVceMessage = new VceMessage { Head = VceMessageHead.Action, Command = VceCommand.Load };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool UnLoad()
{
if (!CheckVceStatus())
return false;
_currentVceMessage = new VceMessage { Head = VceMessageHead.Action, Command = VceCommand.UnLoad };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool Map()
{
if (!CheckVceStatus())
return false;
_currentVceMessage = new VceMessage { Head = VceMessageHead.Action, Command = VceCommand.Map };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool ReadMap()
{
if (!CheckVceStatus())
return false;
_currentVceMessage = new VceMessage { Head = VceMessageHead.Read, Command = VceCommand.ReadMap, Param = "S" };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
_HasReceiveMsg = false;
return _serialport.Write(_currentMsg);
}
public override bool Goto(int Targetslot)
{
if (!CheckVceStatus())
return false;
LOG.Write(eEvent.EV_VCE_COMMON_INFO, _moduleName, $"SlotNum:{Targetslot}");
_currentVceMessage = new VceMessage { Head = VceMessageHead.Action, Command = VceCommand.Goto, Param = (Targetslot + 1).ToString().PadLeft(2, '0') };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool GotoLP()
{
if (!CheckVceStatus())
return false;
_currentVceMessage = new VceMessage { Head = VceMessageHead.Action, Command = VceCommand.GotoLP };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
public override bool ClearError()
{
_currentVceMessage = new VceMessage { Head = VceMessageHead.Set, Command = VceCommand.ClearError };
_currentMsg = _currentVceMessage.toSunWayString() + _newline;
_status = RState.Running;
return _serialport.Write(_currentMsg);
}
}
}