using Aitex.Core.Common; using Aitex.Core.RT.Device; using Aitex.Core.RT.Device.Unit; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using Aitex.Sorter.Common; using athosRT.tool; using Common.DataCenter; using Common.OP; using MECF.Framework.Common.Communications; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.LoadPortBase; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robots.RobotBase; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO.Ports; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace athosRT.Devices.LP { //注意要与brooks的lp实现保持一致 class HirataLoadPort : LoadPortBaseDevice { private string _lpname = string.Empty; private AsyncSerialPort _serial; private string _port = string.Empty; private object _locker = new object(); private LinkedList _lstAsciiMsgs = new LinkedList(); private string _newLine = "\r";//协议的CR private byte _newHeader = 0x01;//协议的头 此处为SOH 也可以是SOT等 对着表就OK private PeriodicJob lp_thread;//监听收到数据的线程 private bool _isAsciiMode; private bool _isLoaded; private LoadPortStateEnum _current = LoadPortStateEnum.Init; private readonly int _timeout = 1*60*1000; private IoTrigger _lpIsEnable; //private DeviceTimer _device_timer; //关键变量 /* _isPresent 是否Present * _isPlaced 是否Placed * _isLoaded load状态 load后置map后置true * IsReady() 是否busy * _isMapped map状态 map后置true * _isDocked dock状态 load后置map后置true * IsCarrierEnabled 看sc的厚薄设置*/ public override bool IsHomed { get; set; }//是否home过 orgn public override bool IsLoaded => _isLoaded; public override bool IsIdle => fsm.State == (int)LoadPortStateEnum.Idle; public bool IsConnected => _serial != null && _serial.IsOpen();//是否建立连接 public bool IsQueryComplete { get; set; } public string ProtrusionState { get; set; } public override bool IsReady() => fsm.State == (int)LoadPortStateEnum.Idle|| fsm.State == (int)LoadPortStateEnum.Init; private readonly Regex mov_interlock_error = new Regex(@".*MOV:.*\/");//MOV:.../...即是interlock错误发生 private readonly Regex mov_abs_error = new Regex(@".*ABS:.*");//含有ABS即是MOV执行失败 成功是INF private readonly Regex catch_After_param = new Regex(@"(?<=\/)(.+?)(?=\;)");//提取错误 private readonly Regex catch_command = new Regex(@"(?<=\:)(.+?)(?=[\/,\;])");//提取命令 private readonly Regex catch_command_type = new Regex(@"(?<=0000)(.+?)(?=\:)");//提取命令类型 public HirataLoadPort(string module, string lpname, string scRoot, RobotBaseDevice robot,IoTrigger[] LPTriggers) : base(module, lpname, robot) { base.Module = module; base.Name = lpname; _lpname = lpname; _isAsciiMode = true; _port = SC.GetStringValue($"LoadPort.{_lpname}.PortName"); //LOG.Write(); //_port = "COM12";// //参数类型string port, int baudRate, int dataBits, Parity parity, StopBits stopBits, _serial = new AsyncSerialPort(_port, 9600, 8, Parity.None, StopBits.One, _newLine, _isAsciiMode); _serial.OnDataChanged += OnAsciiDataReceived;//使用ascii类型时的数据变化处理 _serial.OnBinaryDataChanged += OnBinaryDataChanged;//使用binary类型时的数据变化处理 _serial.OnErrorHappened += onErrorHappend; DoorState = FoupDoorState.Close; if (_serial.Open()) { LOG.Write($"{_lpname}连接成功"); } else { LOG.Write($"{_lpname}连接失败"); } lp_thread = new PeriodicJob(10, OnTimer, $"{_lpname}->OnTimer", true); Singleton.Instance.SubscribeLocation($"{_lpname}", 25); Singleton.Instance.SubscribeLocation($"{_lpname}"); for (int index = 0;index < 25;++index) { Singleton.Instance.DeleteWafer(ModuleHelper.Converter(_lpname), index); } //_device_timer = new DeviceTimer(); } protected override void SubscribeDataVariable() { } private void OnBinaryDataChanged(byte[] obj) { } /// /// 定时函数 用来监听最新收到的消息 并交给函数处理 /// /// private bool OnTimer() { //处理消息 lock (_locker) { if (DoorState == FoupDoorState.Open) { if (Name == "LP1") DeviceModel.TrigSafetytoSMIF1.SetTrigger(true, out _); if (Name == "LP2") DeviceModel.TrigSafetytoSMIF2.SetTrigger(true, out _); } else { if (Name == "LP1") DeviceModel.TrigSafetytoSMIF1.SetTrigger(false, out _); if (Name == "LP2") DeviceModel.TrigSafetytoSMIF2.SetTrigger(false, out _); } switch (Name) { case "LP1": _isPlaced = DeviceModel.LP1Placement.Value; _isPresent = DeviceModel.LP1Presence.Value; break; case "LP2": _isPlaced = DeviceModel.LP2Placement.Value; _isPresent = DeviceModel.LP2Presence.Value; break; } //if (_device_timer.IsTimeout()) //{ // _device_timer.Stop(); // LogObject.Error(_lpname,$"while {CurrentState} Timeout"); // CheckToPostMessage(LoadPortMsg.Error); // return false; //} //Trace.WriteLine($"{_lpname} state: {CurrentState}"); if (_isAsciiMode)//按照ascii码处理 { while (_lstAsciiMsgs.Count > 0) { string value = _lstAsciiMsgs.First.Value; HandleAsciiData(value); _lstAsciiMsgs.RemoveFirst(); } } else { //暂时用不上 //while (_lstBinsMsgs.Count > 0) //{ // byte[] value2 = _lstBinsMsgs.First.Value; // _port_HandleBinarayData(value2); // _lstBinsMsgs.RemoveFirst(); //} } } return true; } private void HandleAsciiData(string ReceiveMsg) { if (string.IsNullOrEmpty(ReceiveMsg)) return; Trace.WriteLine(_lpname+"收到的msg" +ReceiveMsg); LogObject.Info(_lpname, $"Communication {_port} Receive Message:" + ReceiveMsg.Replace("\r", "")); //LogObject.Info(_lpname,"======收到的msg======="+ReceiveMsg+"=============="); //解析返回的数据 //收到的数据的头是否为00 不是就按照错误代码打log if (ReceiveMsg.Substring(1, 2) != "00") { /* * 错误代码 * Check sum error * Command error * Interlock * Alarm occurring * Command processing * Mode error * Mapping error */ string reason = string.Empty; switch (ReceiveMsg.Substring(0, 2)) { case "01": reason = "Check sum error"; break; case "02": reason = "Command error"; break; case "04": reason = "Interlock"; break; case "05": reason = "Alarm occurring"; break; case "06": reason = "Command processing"; break; case "07": reason = "Mode error"; break; case "08": reason = "Mapping error"; break; default: reason = "Unknown Error"; break; } //找到的原因 LogObject.Error(_lpname, $"Received Error Message:{reason}"); } //MOV不能执行的错误 else if (mov_interlock_error.IsMatch(ReceiveMsg)) { //MOV错误 获取/...;间的数据 Interlock code 表示错误代码 LogObject.Error(_lpname, $"MOV:{catch_command.Match(ReceiveMsg).Value} received the error:{catch_After_param.Match(ReceiveMsg).Value}"); } //MOV执行后 获取ABS错误 else if (mov_abs_error.IsMatch(ReceiveMsg)) { //获取/;之间的参数 string param = string.Empty; if (!string.IsNullOrEmpty(catch_After_param.Match(ReceiveMsg).Value)) param = catch_After_param.Match(ReceiveMsg).Value; if (string.IsNullOrEmpty(param)) { LogObject.Error(_lpname, $"MOV:{catch_command.Match(ReceiveMsg).Value} failed for the Unknown error"); } else { string reason = ""; switch (param[0]) { case '1': switch (param[1]) { case '0': reason = "Clamp time over"; break; case '1': reason = "Unclamp time over"; break; case '2': reason = "Dock time over"; break; case '3': reason = "Undock time over"; break; case '4': reason = "Latch time over"; break; case '5': reason = "Unlatch time over"; break; case '6': reason = "Vacuum time over"; break; case '7': reason = "Vacuum release time over"; break; case '8': reason = "Door open time over"; break; case '9': reason = "Door close time over"; break; case 'A': reason = "Mapping forward time over"; break; case 'B': reason = "Mapping return time over"; break; case 'F': reason = "communication error(3 times of resending)"; break; } break; case '2': switch (param[1]) { case '0': reason = "Home return time over"; break; case '1': reason = "Loading time over"; break; case '2': reason = "Unloading time over"; break; case '3': reason = "Positioning time over"; break; case '8': reason = "Door open/close position movement time over"; break; case '9': reason = "Mapping start position movement time over"; break; case 'A': reason = "Mapping end position movement time over"; break; case 'B': reason = "Load position movement time over"; break; } break; case '4': switch (param[1]) { case '0': reason = "Mapping data error"; break; case '1': reason = "Mode select error"; break; } break; case '7': switch (param[1]) { case '0': reason = "Clamp sensor error"; break; case '1': reason = "Dock sensor error"; break; case '2': reason = "Latch sensor error"; break; case '3': reason = "Door sensor error"; break; case '4': reason = "Mapping sensor error"; break; case '7': reason = "Elevator axis sensor error"; break; } break; case 'A': switch (param[1]) { case '0': reason = "Wafer drop"; break; case '1': reason = "Wafer protrusion"; break; case '2': reason = "FOUP mount error"; break; case '3': reason = "FOUP mount error"; break; case '5': reason = "Air pressure drop"; break; } break; case 'B': switch (param[1]) { case '0': reason = "Host error"; break; } break; case 'C': switch (param[1]) { case '0': reason = "Parameter error"; break; } break; case 'E': switch (param[1]) { case '0': reason = "FAN stop alarm"; break; case '3': reason = "Voltage drop"; break; } break; case 'F': switch (param[1]) { case 'E': reason = "Dock hand pinch error"; break; } break; } if (string.IsNullOrEmpty(reason)) { LogObject.Error(_lpname, $"MOV:{catch_command.Match(ReceiveMsg).Value} failed for the Unknown error {param}"); } else { LogObject.Error(_lpname, $"MOV:{catch_command.Match(ReceiveMsg).Value} failed for the error {param}:{reason}"); } } } else { //基本没有错误 若有遗漏 继续加else if(条件补充) //对事件进行分割 SET GET涉及到wafer mapping MOV涉及到home open clamp等 OnEventHappend(ReceiveMsg);//接受信息 涉及状态机切换 return; } //走到这里表示是错误走出 需要发送message给状态机 CheckToPostMessage(LoadPortMsg.Error); IsError = true; } private void FindErrorReason(string param,out string reason) { reason = string.Empty; switch (param[0]) { case '1': switch (param[1]) { case '0': reason = "Clamp time over"; break; case '1': reason = "Unclamp time over"; break; case '2': reason = "Dock time over"; break; case '3': reason = "Undock time over"; break; case '4': reason = "Latch time over"; break; case '5': reason = "Unlatch time over"; break; case '6': reason = "Vacuum time over"; break; case '7': reason = "Vacuum release time over"; break; case '8': reason = "Door open time over"; break; case '9': reason = "Door close time over"; break; case 'A': reason = "Mapping forward time over"; break; case 'B': reason = "Mapping return time over"; break; case 'F': reason = "communication error(3 times of resending)"; break; } break; case '2': switch (param[1]) { case '0': reason = "Home return time over"; break; case '1': reason = "Loading time over"; break; case '2': reason = "Unloading time over"; break; case '3': reason = "Positioning time over"; break; case '8': reason = "Door open/close position movement time over"; break; case '9': reason = "Mapping start position movement time over"; break; case 'A': reason = "Mapping end position movement time over"; break; case 'B': reason = "Load position movement time over"; break; } break; case '4': switch (param[1]) { case '0': reason = "Mapping data error"; break; case '1': reason = "Mode select error"; break; } break; case '7': switch (param[1]) { case '0': reason = "Clamp sensor error"; break; case '1': reason = "Dock sensor error"; break; case '2': reason = "Latch sensor error"; break; case '3': reason = "Door sensor error"; break; case '4': reason = "Mapping sensor error"; break; case '7': reason = "Elevator axis sensor error"; break; } break; case 'A': switch (param[1]) { case '0': reason = "Wafer drop"; break; case '1': reason = "Wafer protrusion"; break; case '2': reason = "FOUP mount error"; break; case '3': reason = "FOUP mount error"; break; case '5': reason = "Air pressure drop"; break; } break; case 'B': switch (param[1]) { case '0': reason = "Host error"; break; } break; case 'C': switch (param[1]) { case '0': reason = "Parameter error"; break; } break; case 'E': switch (param[1]) { case '0': reason = "FAN stop alarm"; break; case '3': reason = "Voltage drop"; break; } break; case 'F': switch (param[1]) { case 'E': reason = "Dock hand pinch error"; break; } break; } } //按照返回数据处理 包括mov后的状态机切换 set反馈 get反馈 private void OnEventHappend(string receiveMsg) { //首先按照收到的正确数据类型进行分类 //收到的可能是1、set 2、get 3、mov 4、inf string command_type = catch_command_type.Match(receiveMsg).Value;//获取到操作的类型 string command_name = catch_command.Match(receiveMsg).Value;//获取操作的名称 switch (command_type) { case "SET": SetEndAnalysis(command_name); break;//主要是设置 没有太多内容 case "GET"://涉及mapping state要对返回值序列进行处理 string command_parameter = catch_After_param.Match(receiveMsg).Value; GetEndAnalysis(command_name, command_parameter); break; case "MOV"://设备回复收到MOV命令 MovCanExcute(command_name); break; case "INF"://设备回复完成MOV命令 需要对该指令处理并下发msg给状态机 MovOPEnd(command_name); break; default: break; } } private void SetEndAnalysis(string command_name) { switch (command_name) { case "RSET": CheckToPostMessage(LoadPortMsg.ResetComplete); break; default: break; } } private void MovCanExcute(string command_name) { } //设备回复完成MOV命令 需要对该指令处理并下发msg给状态机 private void MovOPEnd(string command_name) { switch(command_name) { //home完成 case "ORGN": CheckToPostMessage(LoadPortMsg.InitComplete); break; //Load完成 case "FPML": SendMessage("GET:MAPR;");//获取扫片的结果 break; //Unload完成 case "FPMU": CheckToPostMessage(LoadPortMsg.UnloadComplete); break; //Unclamp case "FCOP": CheckToPostMessage(LoadPortMsg.MoveComplete, "Unclamp over"); break; //Clamp case "FCCL": CheckToPostMessage(LoadPortMsg.MoveComplete, "Clamp over"); break; } } private void GetEndAnalysis(string command_name, string command_parameter) { switch (command_name) { case "STAS"://此处涉及LP关键状态变量的获取 对efem中的判断有重要影响 OnStasRead(command_parameter); break; case "MAPR"://此处涉及扫片的结果转化为wafermanager存储 efem上层会从wafermanager中读取转化 重要! //================判断 OnSlotMapRead(command_parameter); if (CurrentState == LoadPortStateEnum.Loading) { CheckToPostMessage(LoadPortMsg.LoadComplete); } break; } } private void OnStasRead(string command_parameter) { _isLoaded = false; switch (command_parameter[6])//Continer Status { case '0': //_isPlaced = false; //_isPresent = false; break; case '1': //_isPlaced = true; //_isPresent = true; break; case '2': //_isPlaced = false; //_isPresent = true; break; } switch (command_parameter[7])//Clamp position { case '0': ClampState = FoupClampState.Open; break; case '1': ClampState = FoupClampState.Close; break; case '?': ClampState = FoupClampState.Unknown; break; } switch (command_parameter[10])//Door positon { case '0': DoorState = FoupDoorState.Open; if(Module == "LP1") DeviceModel.TrigSafetytoSMIF1.SetTrigger(true,out _); if (Module == "LP2") DeviceModel.TrigSafetytoSMIF2.SetTrigger(true, out _); break; case '1': DoorState = FoupDoorState.Close; if (Module == "LP1") DeviceModel.TrigSafetytoSMIF1.SetTrigger(false, out _); if (Module == "LP2") DeviceModel.TrigSafetytoSMIF2.SetTrigger(false, out _); break; case '?': DoorState = FoupDoorState.Unknown; if (Module == "LP1") DeviceModel.TrigSafetytoSMIF1.SetTrigger(false, out _); if (Module == "LP2") DeviceModel.TrigSafetytoSMIF2.SetTrigger(false, out _); break; } switch (command_parameter[11])//Wafer protrusion sensor(2025.4.18 +) { case '0': ProtrusionState = "Shading"; break; case '1': ProtrusionState = "Lighting"; break; } switch (command_parameter[13])//Dock positon { case '0': DockState = FoupDockState.Undocked; break; case '1': DockState = FoupDockState.Docked; break; case '?': DockState = FoupDockState.Unknown; break; } if (command_parameter[4]!='0')//状态不是normal { string reason; string param = ""; param += command_parameter[4]; param += command_parameter[5]; FindErrorReason(param, out reason); LogObject.Error(_lpname,reason); CheckToPostMessage(LoadPortMsg.Error); } } //覆盖原SlotMap函数 slotMap是一串数字 代表wafer的状态 public override void OnSlotMapRead(string slotMap) { lock (_locker) { int error_num = 0; //循环所有wafer for (int i = 0; i < slotMap.Length; i++) { WaferInfo waferInfo = null; LogObject.Info(_lpname,$"Slot:{i}:{slotMap[i]}"); switch (slotMap[i]) { case '0'://没有wafer delete Singleton.Instance.DeleteWafer(base.LPModuleName, i); Singleton.Instance.UnregisterCarrierWafer(base.Name, i); break; case '1'://有wafer add waferInfo = Singleton.Instance.CreateWafer(LPModuleName, i, WaferStatus.Normal, WaferSize.WS8); Singleton.Instance.RegisterCarrierWafer(base.Name, i, waferInfo); break; case '2'://错误 waferInfo = Singleton.Instance.CreateWafer(base.LPModuleName, i, WaferStatus.Normal, WaferSize.WS8); Singleton.Instance.RegisterCarrierWafer(base.Name, i, waferInfo); error_num++; LogObject.Error(base.Name, $"Slot {i + 1}: occur Crossed"); break; case '3': waferInfo = Singleton.Instance.CreateWafer(base.LPModuleName, i, WaferStatus.Normal, WaferSize.WS8); Singleton.Instance.RegisterCarrierWafer(base.Name, i, waferInfo); LogObject.Warning(base.Name, $"Slot {i + 1}: Thickness is too Thick"); break; case '4': waferInfo = Singleton.Instance.CreateWafer(base.LPModuleName, i, WaferStatus.Normal, WaferSize.WS8); Singleton.Instance.RegisterCarrierWafer(base.Name, i, waferInfo); LogObject.Warning(base.Name, $"Slot {i + 1}: Thickness is too Thin"); break; case '5': waferInfo = Singleton.Instance.CreateWafer(base.LPModuleName, i, WaferStatus.Normal, WaferSize.WS8); Singleton.Instance.RegisterCarrierWafer(base.Name, i, waferInfo); LogObject.Error(base.Name, $"Slot {i + 1}: Position error”"); break; } } if (error_num == 0) { base.MapError = false; } else { base.MapError = true; } _isMapped = true;//十二分重要 //无所谓的部分 //SerializableDictionary serializableDictionary = new SerializableDictionary(); //serializableDictionary["SlotMap"] = CurrentSlotMapResult; //serializableDictionary["PortID"] = base.PortID; //serializableDictionary["PORT_CTGRY"] = base.SpecPortName; //serializableDictionary["CarrierType"] = SpecCarrierType; //serializableDictionary["CarrierIndex"] = InfoPadCarrierIndex; //serializableDictionary["InfoPadSensorIndex"] = InfoPadSensorIndex; //serializableDictionary["CarrierID"] = base.CarrierId; //EV.Notify(EventSlotMapAvailable, serializableDictionary); //if (base.LPCallBack != null) //{ // base.LPCallBack.MappingComplete(_carrierId, CurrentSlotMapResult); //} } } public override WaferSize GetCurrentWaferSize() { return WaferSize.WS8; } /// /// 用来将接受到的数据按照CR分散为一条 等待OnTimer解析 /// /// private void OnAsciiDataReceived(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 bool SendMessage(string message) { //专注数据的发送 此处对数据进行加校验位、加末位处理 if (string.IsNullOrEmpty(message)) { LogObject.Warning(_lpname,"试图发送空消息"); return false; } if (IsConnected) { message = "0000" + message;//加上头 int _hexsum = 0; foreach (var _schar in message.ToCharArray()) { //获取到的是每一个字符 将其转为Hex存入buffers 并累加 用于最后的计算 int num = Convert.ToInt32(_schar); // 将字符转换为 ASCII 数值 string hex = num.ToString("X"); // 将 ASCII 数值转换为十六进制字符串 _hexsum += int.Parse(hex, System.Globalization.NumberStyles.HexNumber); // 将十六进制字符串转换为整数 } string _name = _hexsum.ToString("X"); //00 + 00 + Message + CSH + CSI + _newLine message = message + _name[_name.Length - 2] + _name[_name.Length - 1] + _newLine; LogObject.Info(_lpname, $"Communication {_port} Send Message:" + message.Replace("\r", "")); int raw_length = Encoding.Default.GetBytes(message).Length; byte[] raw_buffer = Encoding.Default.GetBytes(message); byte[] send_buffer = new byte[raw_length + 1]; send_buffer[0] = _newHeader;//加SOH raw_buffer.CopyTo(send_buffer, 1);//剩下的复制到send_buffer if (_serial.Write(send_buffer)) { //_device_timer.Restart(_timeout); //通过串口发送 //LogObject.Info(_lpname, "===========发送的msg============" + message); return true; } else { LogObject.Error(_lpname,"Send Message failed."); return false; } } else { LogObject.Error(_lpname, "尚未建立连接或初始化!"); return false; } } private void onErrorHappend(string obj) { LogObject.Error($"{_lpname}", $"Connect Error for:{obj}"); } protected override bool fStartExecute(object[] param) { //执行逻辑 超时报警 返回错误 返回带参STAS除外都是有错的 ABS执行错误 try { switch (param[0].ToString()) { case "Unclamp": lock (_locker) { SendMessage("MOV:FCOP;"); } break; case "Clamp": lock (_locker) { SendMessage("MOV:FCCL;"); } break; case "MapWafer": //_serial.Write(""); break; case "QueryState": IsQueryComplete = false; lock (_locker) { SendMessage("GET:STAS;"); } break; default: break; } return true; } catch (Exception ex) { return false; } } protected override bool fMonitorExecuting(object[] param) { base.IsBusy = false; LogObject.Info(_lpname,$"{param[0].ToString()} excuted over"); return true; } protected override bool fStartInit(object[] param) { //收到消息进入initilizing状态 需要先下发 //初始化逻辑MOV:ORGN IsHomed = false; SendMessage("MOV:ORGN;"); return true; } protected override bool fCompleteInit(object[] param) { //一些状态要置为false IsHomed = true; lock (_locker) { SendMessage("GET:STAS;"); } return true; } protected override bool fStartReset(object[] param) { //SET:RSET lock (_locker) { SendMessage("SET:RSET;"); } return true; } protected override bool fMonitorReset(object[] param) { MapError = false; IsError = false; base.IsBusy = false; return true; } protected override bool fStartLoad(object[] param) { //load操作 lock (_locker) { SendMessage("MOV:FPML;"); } return true; } protected override bool fCompleteLoad(object[] param) { base.IsBusy = false; _isLoaded = true; base.DockState = FoupDockState.Docked; base.ClampState = FoupClampState.Close; base.DoorState = FoupDoorState.Open; if (Name == "LP1") DeviceModel.TrigSafetytoSMIF1.SetTrigger(true, out _); if (Name == "LP2") DeviceModel.TrigSafetytoSMIF2.SetTrigger(true, out _); return true; } protected override bool fStartUnload(object[] param) { lock (_locker) { SendMessage("MOV:FPMU;"); } return true; } protected override bool fMonitorUnload(object[] param) { base.IsBusy = false; _isLoaded = false; base.DockState = FoupDockState.Undocked; base.ClampState = FoupClampState.Close; base.DoorState = FoupDoorState.Close; if (Name == "LP1") DeviceModel.TrigSafetytoSMIF1.SetTrigger(false, out _); if (Name == "LP2") DeviceModel.TrigSafetytoSMIF2.SetTrigger(false, out _); return true; } protected override bool fStartWrite(object[] param) { //_serial.Write(""); return true; } protected override bool fStartRead(object[] param) { //MOV:MAPR //_serial.Write("MOV:MAPR") return true ; } public override bool IsEnableTransferWafer(out string reason) { reason = ""; //Trace.WriteLine("============================================================="); //Trace.WriteLine($"时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}"); //Trace.WriteLine($" LP:{_lpname} State:{State}"); //Trace.WriteLine($"The state of Present is {_isPresent}."); //Trace.WriteLine($"The state of Placed is {_isPlaced }."); //Trace.WriteLine($"The state of Ready is {IsReady() }."); //Trace.WriteLine($"The state of Mapped is {_isMapped }."); //Trace.WriteLine("============================================================="); if (_isPresent && _isPlaced && _isLoaded && IsReady() && _isMapped) { return true; } else { reason += $"The State of {_lpname} is {State}. "; reason += _isPresent ? $"The state of Present is {_isPresent}." : ""; reason += _isPlaced ? $"The state of Placed is {_isPlaced }." : ""; reason += _isLoaded ? $"The state of Loaded is {_isLoaded }." : ""; reason += IsReady() ? $"The state of Ready is {IsReady() }." : ""; reason += _isMapped ? $"The state of Mapped is {_isMapped }." : ""; } return false; } public override bool IsEnableLoad(out string reason) { if (!_isPlaced) { reason = "No carrier placed"; return false; } if (_isDocked) { reason = "Carrier is docked"; return false; } if (!IsReady()) { reason = "Not Ready"; return false; } //SC的内容 建议直接 //if (!IsCarrierEnabled) //{ // reason = "CarrierNotEnabled"; // return false; //} reason = ""; return true; } } public enum HirataCommandType { SET, MOD, GET, MOV, TCH } public enum HirataCommand { //SET RSET, RTRY, STPP, PASE, ABOT, RESM, TYP1, TYP2, TYP3, TYP4, TYP5, MAPP, MAP1, MAP2, POSO, //GET, STAS, STA1, STA2, MDAT, MAPR, VERN, //MAPP, //MAP1, //MAP2, //POSO, POSD, MDAH, MDAP, MDTC, MDHS, MDPS, LEST, //MOV ORGN, ABGN, FPLD, FPML, FDOC, FDLD, FDML, FCLD, FCML, FPUL, FPMU, FVOF, FVUL, FUDC, FUMD, //MAPP, RMAP, Z_MP , } }