| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639 | 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{    /// <summary>    /// 素珀 vce 驱动    /// </summary>    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<string> _lstAsciiMsgs = new LinkedList<string>();        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<string, string> _ErrorCode2Reason = new Dictionary<string, string>()        {            {"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<HongHuTM>("SETM").VCEACassPresent                        return _vcedoorflag;                    case ModuleName.VCEA:                        if (DEVICE.GetDevice<SunWayDETM>("TM").VCEACassPresent)                        {                            _LPMs[0].HasCassette = true;                        }                        else                        {                            _LPMs[0].HasCassette = false;                            WaferManager.Instance.DeleteWafer(_LPMs[0].Module, 0, 25);                        }                        return !DEVICE.GetDevice<SunWayDETM>("TM").VCEALOCKED;                    case ModuleName.VCEB:                        if (DEVICE.GetDevice<SunWayDETM>("TM").VCEBCassPresent)                        {                            _LPMs[0].HasCassette = true;                        }                        else                        {                            _LPMs[0].HasCassette = false;                            WaferManager.Instance.DeleteWafer(_LPMs[0].Module, 0, 25);                        }                        return !DEVICE.GetDevice<SunWayDETM>("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<HongHuTM>("SETM").VCEProtrusion                        return true;                    case ModuleName.VCEA:                        if (DEVICE.GetDevice<SunWayDETM>("TM").VCEAProtrusion)                        {                            _LPMs[0].Protrusion = true;                            return true;                        }                        else                        {                            _LPMs[0].Protrusion = false;                            return false;                        }                    case ModuleName.VCEB:                        if (DEVICE.GetDevice<SunWayDETM>("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<ModuleName, int> _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);        }        /// <summary>        /// 开门提示        /// 在honghuVCE中没有ATM信号的内部卡控 可能会导致开门的压差        /// 因此每一次都要增加判断,只要引用此处功能的,前面都需要有判断        ///         /// </summary>        /// <returns></returns>        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);        }    }}
 |