using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Diagnostics; using BAI.Systems.Common; using BAI.Systems.Common.Carriers; using BAI.Systems.Common.Controls; using BAI.Systems.Devices.LightTower; using BAI.Systems.Modules.EFEM; using BAI.Systems.Common.Substrates; using VirgoRT.Device; using VirgoRT.Modules; using Aitex.Core.RT.Event; using Aitex.Core.Common; using Aitex.Core.Util; using VirgoRT.Device.YASKAWA; using VirgoCommon; using Aitex.Core.RT.SCCore; using System.Text.RegularExpressions; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.Common.CommonData; namespace VirgoRT.Devices.EFEM { class BrooksEFEMProxy { public bool Connected { get { return _ef != null && _lt != null; } } private EfemRemoteProxy _ef; private LightTowerLocalProxy _lt; private bool _VerifyWaferExistence = false; public event EventHandler CommandUpdated; public event EventHandler EventUpdated; public event EventHandler ErrorOccurred; private readonly Regex _Reg_hostname = new Regex(@"(?:EFEM\.)?Port[A|B|C|D]\.Slot(\d+)"); public BrooksEFEMProxy() { BAI.CTC.ClientInit.ClientLibLoader.InitializeLoader(); } public bool Initialize() { if (_ef == null || _lt == null) { try { _ef = new EfemRemoteProxy("EFEM", "CTC"); _lt = new LightTowerLocalProxy("EFEM.LightTower1", "CTC"); string PMAPortName = SC.GetStringValue("PMA.BrooksPortName"); string PMBPortName = SC.GetStringValue("PMB.BrooksPortName"); _VerifyWaferExistence = SC.GetValue("EFEM.VerifyWaferExistenceAtferRetract"); BrooksConst.ModuleString["LLA"] = $"EFEM.{PMAPortName}.Slot1"; BrooksConst.ModuleString["LLB"] = $"EFEM.{PMBPortName}.Slot1"; BrooksConst.ModuleString["LLA01"] = $"EFEM.{PMAPortName}.Slot1"; BrooksConst.ModuleString["LLB01"] = $"EFEM.{PMBPortName}.Slot1"; } catch (Exception ex) { EV.PostAlarmLog("EFEM", $"Error happen while connect Brooks EFEM: {ex.Message} "); return false; } //_ef.Initialize(); Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.CommReady); } subscribeEvents(); return _ef != null && _lt != null; } public async Task Send(IEfemMessage msg) { if (_ef == null || _lt == null) { if (!Initialize()) { EV.PostAlarmLog("EFEM", "Initialize Brooks BAI library failed"); return; } } EfemMessage Msg = msg as EfemMessage; bool bResult; string strLogParas = string.Empty; switch (Msg.Operation) { case EfemOperation.Home: bResult = await AsyncInitialize(Msg); break; case EfemOperation.Pick: bResult = await AsyncAction(() => _ef.GetWafer(BrooksConst.ArmString[Msg.Parameters[1]], BrooksConst.GetHostName(Msg.Parameters[0])), Msg); strLogParas = $", From: {BrooksConst.ModuleString[Msg.Parameters[0]]}, EndEffector: {BrooksConst.ArmString[Msg.Parameters[1]]}"; break; case EfemOperation.Place: bResult = await AsyncAction(() => _ef.PutWafer(BrooksConst.ArmString[Msg.Parameters[1]], BrooksConst.GetHostName(Msg.Parameters[0])), Msg); strLogParas = $", To: {BrooksConst.ModuleString[Msg.Parameters[0]]}, EndEffector: {BrooksConst.ArmString[Msg.Parameters[1]]}"; break; case EfemOperation.Goto: bResult = await AsyncAction(() => _ef.MoveToReadyGet(BrooksConst.ArmString[Msg.Parameters[1]], BrooksConst.ModuleString[Msg.Parameters[0]]), Msg); strLogParas = $", To: {BrooksConst.ModuleString[Msg.Parameters[0]]}, EndEffector: {BrooksConst.ArmString[Msg.Parameters[1]]}"; break; case EfemOperation.Extend: if (Msg.Parameters[1] == "PB" || Msg.Parameters[1] == "GB") { bResult = await AsyncExtend(Msg); strLogParas = $", To: {BrooksConst.ModuleString[Msg.Parameters[0]]}, EndEffector: {BrooksConst.ArmString[Msg.Parameters[2]]}"; } else { bResult = await AsyncRetract(Msg); strLogParas = $", From: {BrooksConst.ModuleString[Msg.Parameters[0]]}, EndEffector: {BrooksConst.ArmString[Msg.Parameters[2]]}"; } break; case EfemOperation.Align: { double angle = SC.GetValue("EFEM.AlignAngle"); bResult = await AsyncAction(() => _ef.AlignWafer("Aligner", WaferAlignFeature.Notch, angle), Msg); strLogParas = $", Module: Aligner, Angle:{angle}"; } break; case EfemOperation.Map: bResult = await AsyncMap(BrooksConst.ModuleString[Msg.Parameters[0]], Msg.Operation); strLogParas = $", LoadPort: {BrooksConst.ModuleString[Msg.Parameters[0]]}"; break; case EfemOperation.Light: bResult = await AsyncAction(() => _lt.SetLightTowerState(StringToLightState(Msg.Parameters[1], Msg.Parameters[2])), Msg); strLogParas = $", Parameters: {BrooksConst.LightTowerColorMap[Msg.Parameters[1]]},{BrooksConst.LightTowerIndicatorMap[Msg.Parameters[2]]}"; break; case EfemOperation.Dock: bResult = await AsyncAction(() => _ef.GetLoadPortCtrl(BrooksConst.ModuleString[Msg.Parameters[0]]).DockCarrier(), Msg); strLogParas = $", LoadPort: {BrooksConst.ModuleString[Msg.Parameters[0]]}"; break; case EfemOperation.Undock: bResult = await AsyncAction(() => _ef.GetLoadPortCtrl(BrooksConst.ModuleString[Msg.Parameters[0]]).UndockCarrier(), Msg); strLogParas = $", LoadPort: {BrooksConst.ModuleString[Msg.Parameters[0]]}"; break; case EfemOperation.Clamp: bResult = await AsyncAction(() => _ef.ClampCarrier(BrooksConst.ModuleString[Msg.Parameters[0]]), Msg); strLogParas = $", LoadPort: {BrooksConst.ModuleString[Msg.Parameters[0]]}"; break; case EfemOperation.Unclamp: bResult = await AsyncAction(() => _ef.UnclampCarrier(BrooksConst.ModuleString[Msg.Parameters[0]]), Msg); strLogParas = $", LoadPort: {BrooksConst.ModuleString[Msg.Parameters[0]]}"; break; case EfemOperation.ClearError: bResult = await AsyncAction(() => _ef.ClearAlarm(), Msg); break; case EfemOperation.Load: bResult = await AsyncLoad(BrooksConst.ModuleString[Msg.Parameters[0]]); strLogParas = $", LoadPort: {BrooksConst.ModuleString[Msg.Parameters[0]]}"; break; case EfemOperation.Unload: bResult = await AsyncUnload(BrooksConst.ModuleString[Msg.Parameters[0]]); strLogParas = $", LoadPort: {BrooksConst.ModuleString[Msg.Parameters[0]]}"; break; case EfemOperation.CarrierId: if (Msg.Head == EfemMessage.MsgHead.GET) { bResult = await AsyncReadCarrierID(BrooksConst.ModuleString[Msg.Parameters[0]], Msg); } else if (Msg.Head == EfemMessage.MsgHead.SET) { bResult = await AsyncAction(() => _ef.WriteCarrierId(BrooksConst.ModuleString[Msg.Parameters[0]], Msg.Parameters[1]), Msg); } break; case EfemOperation.Flip: bResult = await AsyncFlip(Msg); strLogParas = $", EndEffector: {BrooksConst.ArmString[Msg.Parameters[0]]}, Orientation: {SubstrateHostOrientation.FaceDown}"; break; case EfemOperation.EmsStop: bResult = await AsyncAction(() => _ef.Ems(), Msg); strLogParas = $",Emergency Motor Stop (EMS) - stops motion, servo for all-axes turned off."; break; case EfemOperation.SetRobotSpeed: bResult = await AsyncAction(() => _ef.SetActiveRobotMotionProfile(Msg.Parameters[0]), Msg); strLogParas = $",Set Robot Speed: {Msg.Parameters[0]}"; break; case EfemOperation.QueryLPPresence: bResult = await AsyncQueryLPPresence(); break; case EfemOperation.Orgsh: case EfemOperation.StateTrack: { var args = new EfemActionArgs { Module = Msg.Port, CommandType = Msg.Operation, Status = ActionStatus.Completed, Data = (Msg.Data != null && Msg.Data.Count > 0) ? Msg.Data.First() : string.Empty }; await Task.Delay(200); CommandUpdated?.Invoke(this, args); Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.ActionDone, Msg.Operation); } break; case EfemOperation.Abort: case EfemOperation.SetThickness: case EfemOperation.Grip: case EfemOperation.Retract: case EfemOperation.Lift: break; default: Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.ActionDone, Msg.Operation); return; } if (strLogParas.Length > 0) { EV.PostInfoLog("EFEM", $"Command: {msg.Operation}{strLogParas}"); } } private void subscribeEvents() { _ef.AlarmGenerated += new AlarmEventHandler(onAlarm); _ef.CarrierArrived += new CarrierHandoffPassiveDeviceEventHandler(onCarrierArrival); _ef.CarrierRemoved += new CarrierHandoffPassiveDeviceEventHandler(onCarrierRemoval); _ef.CarrierHandoffError += new CarrierHandoffPassiveDeviceErrorHandler(onCarrierHandoffError); _ef.WaferPresenceChanged += new WaferStatusUpdateHandler(onWaferPresenceChange); } private void onCarrierArrival(string port, string location, PresenceState carrier, string data, string message) { // only for test no loadport EFEM on simulation //if (SC.GetValue("EFEM.LoadPort.EnableDockUndock") == false) // return; var args = new EfemEventArgs { Module = BrooksConst.dictLPs[port], CommandType = EfemOperation.SigStatus, EvtStr = "Carrier Arrival", DataList = new List { BrooksConst.dictModuleToString[BrooksConst.dictLPs[port]], "00000341", "00000000" } }; this.EventUpdated?.Invoke(this, args); EV.PostInfoLog("EFEM", "Carrier arrived on " + port + ": " + data + ": " + message); } private void onCarrierRemoval(string port, string location, PresenceState carrier, string data, string message) { // only for test no loadport EFEM on simulation //if (SC.GetValue("EFEM.LoadPort.EnableDockUndock") == false) // return; var args = new EfemEventArgs { Module = BrooksConst.dictLPs[port], CommandType = EfemOperation.SigStatus, EvtStr = "Carrier Leave", DataList = new List { BrooksConst.dictModuleToString[BrooksConst.dictLPs[port]], "00000342", "00000002" } }; this.EventUpdated?.Invoke(this, args); EV.PostInfoLog("EFEM", "Carrier removed on " + port + ": " + data + ": " + message); } private void onCarrierHandoffError(string port, AlarmLevel alarm, string lcoation, PresenceState carrier, string data, string message) { EV.PostAlarmLog("EFEM", "Carrier handoff error on " + port + ": " + alarm.ToString() + " : " + message); } private void onAlarm(string source, AlarmLevel level, string message) { if (level == AlarmLevel.Fatal) { var args = new EfemErrorArgs { Module = BrooksConst.dictLPs[source], Description = message }; this.ErrorOccurred?.Invoke(this, args); EV.PostAlarmLog(source, _ef.ModuleName + " alarm at level " + level.ToString() + " : " + message); } else { EV.PostWarningLog(source, message); } } private void onWaferPresenceChange(string module, string location, WaferPresenceState after) { EV.PostInfoLog("LPX", module + ": wafer presence changed to Wafer[" + location + "] = " + after.ToString()); } private LightTowerSignalState[] StringToLightState(string para1, string para2) { var stateArray = new LightTowerSignalState[1]; stateArray[0] = new LightTowerSignalState(BrooksConst.LightTowerColorMap[para1], BrooksConst.LightTowerIndicatorMap[para2]); return stateArray; } #region efem operation private async Task AsyncInitialize(EfemMessage Msg) { try { await Task.Run(() => { if (Msg.Parameters[0] == "ROB") { if (Msg.Parameters.Count > 1) { switch (Msg.Parameters[1]) { case "AllAxes": _ef.HomeAllAxes(); break; default: _ef.HomeAxis(Msg.Parameters[1]); break; } } } else if (Msg.Parameters[0] == "P1" || Msg.Parameters[0] == "P2" || Msg.Parameters[0] == "P3") { _ef.GetLoadPortCtrl(BrooksConst.ModuleString[Msg.Parameters[0]]).HomeLoadPort(); } else { _ef.Initialize(); // verify wafer existance var waferPresences = _ef.GetWaferPresence(""); foreach (var wafer in waferPresences) { var waferLoc = wafer.HostName.Replace("EFEM.", "").Split(new char[] { '.' }); if (BrooksConst.dictLocToModule.ContainsKey(waferLoc[0])) { if (ModuleHelper.IsLoadPort(BrooksConst.dictLocToModule[waferLoc[0]])) continue; int slot = 0; string SlotName = string.Empty; Regex reg_slot = new Regex(@"Slot(\d+)"); if (waferLoc[0].Contains("WaferEngine")) { if (waferLoc[1] == "EE1") { slot = 0; SlotName = "Blade1"; } else { slot = 1; SlotName = "Blade2"; } } else if (ModuleHelper.IsBuffer(BrooksConst.dictLocToModule[waferLoc[0]]) && reg_slot.IsMatch(waferLoc[1])) { Match result = reg_slot.Match(waferLoc[1]); slot = int.Parse(result.Groups[1].Value) - 1; SlotName = $"Slot{slot + 1}"; } if (wafer.WaferPresence == WaferPresenceState.Absent && WaferManager.Instance.CheckHasWafer(BrooksConst.dictLocToModule[waferLoc[0]], slot)) { EV.PostWarningLog("EFEM Home", $"EFEM 初始化时发现{BrooksConst.dictLocToModule[waferLoc[0]]} {SlotName} 没有Wafer, 删除此位置Wafer."); WaferManager.Instance.DeleteWafer(BrooksConst.dictLocToModule[waferLoc[0]], slot); } else if ((wafer.WaferPresence == WaferPresenceState.Present) && WaferManager.Instance.CheckNoWafer(BrooksConst.dictLocToModule[waferLoc[0]], slot)) { EV.PostWarningLog("EFEM Home", $"EFEM 初始化时发现{BrooksConst.dictLocToModule[waferLoc[0]]} {SlotName}有一片, 创建该位置Wafer."); WaferManager.Instance.CreateWafer(BrooksConst.dictLocToModule[waferLoc[0]], slot, WaferStatus.Unknown); } if (wafer.WaferPresence == WaferPresenceState.Unknown) { EV.PostWarningLog("EFEM Home", $"EFEM 初始化时发现{BrooksConst.dictLocToModule[waferLoc[0]]} {SlotName}Wafer信息不确定, 请检查改位置是否有Wafer."); } } } // verify Loadport is on position foreach (var lp in BrooksConst.dictLocToModule) { if (ModuleHelper.IsInstalled(lp.Value) && ModuleHelper.IsLoadPort(lp.Value)) { var lpState = _ef.GetCarrierPresenceState(lp.Key); if (lpState == PresenceState.Present) { var argss = new EfemEventArgs { Module = lp.Value, CommandType = EfemOperation.SigStatus, EvtStr = "Carrier Arrival", DataList = new List { BrooksConst.dictModuleToString[lp.Value], "00000341", "00000000" } }; EventUpdated?.Invoke(this, argss); } } } // Mock PortD as Buffer for Simulator if (SC.GetValue("System.IsSimulatorMode")) { _ef.ClampCarrier("PortD"); _ef.MoveCarrierPortToLocation("PortD", "Docked"); var mapData = _ef.OpenAndMapCarrier("PortD"); } } }); } catch (Exception e) { Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.Error, EfemOperation.Home); EV.PostAlarmLog("EFEM", e.Message.ToString()); return false; } var args = new EfemActionArgs { Module = ModuleName.EFEM, CommandType = EfemOperation.Home, Status = ActionStatus.Completed, }; CommandUpdated?.Invoke(this, args); Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.ActionDone, EfemOperation.Home); return true; } private async Task AsyncLoad(string lp) { string mapReulst = string.Empty; bool bLPRemoved = false; bool bPlacementError = false; try { await Task.Run(() => { if (SC.GetValue("EFEM.LoadPort.EnableDockUndock") == false) { PresenceState presence = _ef.GetCarrierPresenceState(lp); if (presence != PresenceState.Present) { bLPRemoved = true; return; } } Aitex.Core.Common.WaferSize wafer_size = (SC.GetValue($"System.BigWafer") == 8) ? Aitex.Core.Common.WaferSize.WS8 : Aitex.Core.Common.WaferSize.WS12; _ef.ClampCarrier(lp); if (SC.GetValue("EFEM.LoadPort.EnableDockUndock") || SC.GetValue("System.IsSimulatorMode")) { _ef.MoveCarrierPortToLocation(lp, "Docked"); } var mapData = _ef.OpenAndMapCarrier(lp); StringBuilder sb = new StringBuilder(mapData.Length); foreach (var slot in mapData) { if (_Reg_hostname.IsMatch(slot.HostName)) { Match result = _Reg_hostname.Match(slot.HostName); int SlotId = int.Parse(result.Groups[1].Value) - 1; if (slot.WaferPresence == WaferPresenceState.Present) { WaferManager.Instance.CreateWafer(BrooksConst.dictLPs[lp], SlotId, WaferStatus.Normal, wafer_size); sb.Append("1"); } else if (slot.WaferPresence == WaferPresenceState.Cross) { WaferManager.Instance.CreateWafer(BrooksConst.dictLPs[lp], SlotId, WaferStatus.Crossed, wafer_size); EV.PostAlarmLog("EFEM", $"{BrooksConst.dictLPs[lp]}.Slot{SlotId + 1} 发现斜片"); sb.Append("3"); } else if (slot.WaferPresence == WaferPresenceState.Double) { WaferManager.Instance.CreateWafer(BrooksConst.dictLPs[lp], SlotId, WaferStatus.Double, wafer_size); EV.PostAlarmLog("EFEM", $"{BrooksConst.dictLPs[lp]}.Slot{SlotId + 1} 发现叠片"); sb.Append("7"); } else { sb.Append("0"); } // Wafer Placement Parity Check int parityFlag = SC.GetValue("EFEM.LoadPort.WaferPlacementParityFlag"); if(parityFlag != 0 && slot.WaferPresence != WaferPresenceState.Absent) { if(SlotId % 2 == parityFlag % 2) { bPlacementError = true; string slotParity = parityFlag == 2 ? "奇数槽" : "偶数槽"; EV.PostAlarmLog("EFEM", $"{slotParity} {BrooksConst.dictLPs[lp]}.Slot{SlotId + 1} 有Wafer"); } } } } Singleton.Instance.EFEM.EfemDevice[BrooksConst.dictLPs[lp]].IsMapped = true; mapReulst = sb.ToString(); }); } catch (Exception e) { Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.Error, EfemOperation.Load); EV.PostAlarmLog("EFEM", e.Message.ToString()); return false; } if (bLPRemoved) { ModuleName removeLP = BrooksConst.dictLPs[lp]; var evgs_removed = new EfemEventArgs { Module = removeLP, CommandType = EfemOperation.SigStatus, EvtStr = "Carrier Leave", DataList = new List { BrooksConst.dictModuleToString[BrooksConst.dictLPs[lp]], "00000342", "00000000" } }; EventUpdated?.Invoke(this, evgs_removed); await Task.Delay(200); var args_removed = new EfemActionArgs { Module = removeLP, CommandType = EfemOperation.Load, Status = ActionStatus.Cancel, Data = string.Empty }; CommandUpdated?.Invoke(this, args_removed); Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.ActionDone, EfemOperation.Load); return true; } var evgs = new EfemEventArgs { Module = BrooksConst.dictLPs[lp], CommandType = EfemOperation.GetWaferInfo, EvtStr = "map result", DataList = new List { mapReulst } }; EventUpdated?.Invoke(this, evgs); await Task.Delay(200); var args = new EfemActionArgs { Module = BrooksConst.dictLPs[lp], CommandType = EfemOperation.Load, Status = ActionStatus.Completed, Data = string.Empty }; CommandUpdated?.Invoke(this, args); Singleton.Instance.EFEM.EfemDevice[BrooksConst.dictLPs[lp]].HasPlacementError = bPlacementError; return true; } private async Task AsyncUnload(string lp) { try { await Task.Run(() => { _ef.CloseAndMapCarrier(lp); if (SC.GetValue($"EFEM.LoadPort.EnableDockUndock") || SC.GetValue("System.IsSimulatorMode")) { _ef.MoveCarrierPortToLocation(lp, "Undocked"); } _ef.UnclampCarrier(lp); }); } catch (Exception e) { Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.Error, EfemOperation.Unload); EV.PostAlarmLog("EFEM", e.Message.ToString()); return false; } var args2 = new EfemActionArgs { Module = BrooksConst.dictLPs[lp], CommandType = EfemOperation.Unload, Status = ActionStatus.Completed, Data = string.Empty }; CommandUpdated?.Invoke(this, args2); await Task.Delay(200); var args = new EfemEventArgs { Module = BrooksConst.dictLPs[lp], CommandType = EfemOperation.SigStatus, EvtStr = "Carrier Leave", DataList = new List { BrooksConst.dictModuleToString[BrooksConst.dictLPs[lp]], "00000342", "00000000" } }; this.EventUpdated?.Invoke(this, args); Singleton.Instance.EFEM.EfemDevice[BrooksConst.dictLPs[lp]].HasPlacementError = false; return true; } private async Task AsyncMap(string lp, EfemOperation operation) { string mapReulst = string.Empty; try { await Task.Run(() => { var mapData = _ef.OpenAndMapCarrier(lp); StringBuilder sb = new StringBuilder(mapData.Length); foreach (var slot in mapData) { if (_Reg_hostname.IsMatch(slot.HostName)) { Match result = _Reg_hostname.Match(slot.HostName); int SlotId = int.Parse(result.Groups[1].Value) - 1; if (slot.WaferPresence == WaferPresenceState.Present) { WaferManager.Instance.CreateWafer(BrooksConst.dictLPs[lp], SlotId, WaferStatus.Normal, Aitex.Core.Common.WaferSize.WS12); sb.Append("1"); } else if (slot.WaferPresence == WaferPresenceState.Cross) { WaferManager.Instance.CreateWafer(BrooksConst.dictLPs[lp], SlotId, WaferStatus.Crossed, Aitex.Core.Common.WaferSize.WS12); EV.PostAlarmLog("EFEM", $"{slot.HostName} 发现斜片"); sb.Append("3"); } else if (slot.WaferPresence == WaferPresenceState.Double) { WaferManager.Instance.CreateWafer(BrooksConst.dictLPs[lp], SlotId, WaferStatus.Double, Aitex.Core.Common.WaferSize.WS12); EV.PostAlarmLog("EFEM", $"{slot.HostName} 发现叠片"); sb.Append("7"); } else { sb.Append("0"); } } } Singleton.Instance.EFEM.EfemDevice[BrooksConst.dictLPs[lp]].IsMapped = true; mapReulst = sb.ToString(); }); } catch (Exception e) { Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.Error, EfemOperation.Load); EV.PostAlarmLog("EFEM", e.Message.ToString()); return false; } var args = new EfemActionArgs { Module = BrooksConst.dictLPs[lp], CommandType = EfemOperation.Map, Status = ActionStatus.Completed, Data = string.Empty }; CommandUpdated?.Invoke(this, args); var evgs = new EfemEventArgs { Module = BrooksConst.dictLPs[lp], CommandType = EfemOperation.GetWaferInfo, EvtStr = "map result", DataList = new List { mapReulst } }; EventUpdated?.Invoke(this, evgs); Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.ActionDone, EfemOperation.Map); return true; } private async Task AsyncAction(Action t, EfemMessage Msg) { try { await Task.Run(() => t.Invoke()); } catch (Exception e) { Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.Error, Msg); EV.PostAlarmLog("EFEM", e.Message.ToString()); return false; } if (Msg.Operation == EfemOperation.Light) return true; var args = new EfemActionArgs { Module = Msg.Port, CommandType = Msg.Operation, Status = ActionStatus.Completed, Data = (Msg.Data != null && Msg.Data.Count > 0) ? Msg.Data.First() : string.Empty }; CommandUpdated?.Invoke(this, args); Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.ActionDone, Msg.Operation); return true; } private async Task AsyncReadCarrierID(string lp, EfemMessage Msg) { string strCarrierID = string.Empty; try { await Task.Run(() => { strCarrierID = _ef.ReadCarrierId(lp); }); } catch (Exception e) { //Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.Error, Msg); EV.PostAlarmLog("EFEM", e.Message.ToString()); return false; } var args = new EfemActionArgs { Module = BrooksConst.dictLPs[lp], CommandType = EfemOperation.CarrierId, Status = ActionStatus.Completed, Data = strCarrierID }; CommandUpdated?.Invoke(this, args); return true; } private async Task AsyncExtend(EfemMessage Msg) { ModuleName mod = Msg.Parameters[0].Contains("LLA") ? ModuleName.PMA : ModuleName.PMB; var hand = Msg.Parameters[2] == "ARM2" ? Aitex.Sorter.Common.Hand.Blade1 : Aitex.Sorter.Common.Hand.Blade2; Singleton.Instance.EFEM.EfemDevice.SetRobotMovingInfo(RobotAction.Extending, hand, mod); try { await Task.Run(() => { string host = BrooksConst.ModuleString[Msg.Parameters[0]]; string endEffect = BrooksConst.ArmString[Msg.Parameters[2]]; if (Msg.Parameters[1] == "PB") { _ef.MoveToReadyPut(endEffect, host); _ef.ExtendEndEffecter(endEffect, host, VerticalOffsetFromWafer.Above); _ef.ReleaseWaferRestraint(endEffect); } else { _ef.MoveToReadyGet(endEffect, host); _ef.ExtendEndEffecter(endEffect, host, VerticalOffsetFromWafer.Below); } }); } catch (Exception e) { Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.Error, Msg); EV.PostAlarmLog("EFEM", e.Message.ToString()); return false; } var args = new EfemActionArgs { Module = mod, CommandType = Msg.Operation, Status = ActionStatus.Completed, Data = (Msg.Data != null && Msg.Data.Count > 0) ? Msg.Data.First() : string.Empty }; CommandUpdated?.Invoke(this, args); return true; } private async Task AsyncRetract(EfemMessage Msg) { ModuleName mod = Msg.Parameters[0].Contains("LLA") ? ModuleName.PMA : ModuleName.PMB; var hand = Msg.Parameters[2] == "ARM2" ? Aitex.Sorter.Common.Hand.Blade1 : Aitex.Sorter.Common.Hand.Blade2; Singleton.Instance.EFEM.EfemDevice.SetRobotMovingInfo(RobotAction.Retracting, hand, mod); WaferPresenceState hostPresence = WaferPresenceState.Unknown, armPresence = WaferPresenceState.Unknown; bool bPlace = Msg.Parameters[1] == "P4"; try { await Task.Run(() => { string host = BrooksConst.ModuleString[Msg.Parameters[0]]; string endEffect = BrooksConst.ArmString[Msg.Parameters[2]]; if (bPlace) { _ef.MoveDownToPutWafer(endEffect, host); } else { _ef.MoveUpToGetWafer(endEffect, host); _ef.ApplyWaferRestraint(endEffect); } _ef.RetractEndEffecter(endEffect); hostPresence = _ef.MapWaferPresenceOnHost(host); armPresence = _ef.MapWaferPresenceOnHost(endEffect); }); } catch (Exception e) { Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.Error, Msg); EV.PostAlarmLog("EFEM", e.Message.ToString()); return false; } // Verify wafer existence after arm retract if (_VerifyWaferExistence) { if (bPlace) { if (armPresence != WaferPresenceState.Absent) { EV.PostAlarmLog("EFEM", $"放片后验证 Wafer 状态失败, {hand}:{armPresence}, 请检查实际{mod}和手臂{hand}上的Wafer状态"); return false; } } else { if (hostPresence != WaferPresenceState.Absent || armPresence != WaferPresenceState.Present) { EV.PostAlarmLog("EFEM", $"取片后验证 Wafer 状态失败,{hand}:{armPresence}, {mod}:{hostPresence}, 请检查实际{mod}和手臂{hand}上的Wafer状态"); return false; } } } var args = new EfemActionArgs { Module = mod, CommandType = Msg.Operation, Status = ActionStatus.Completed, Data = (Msg.Data != null && Msg.Data.Count > 0) ? Msg.Data.First() : string.Empty }; CommandUpdated?.Invoke(this, args); return true; } private async Task AsyncFlip(EfemMessage Msg) { SubstrateHostOrientation _GetReversedOrient(SubstrateHostOrientation original) { return original == SubstrateHostOrientation.FaceUp ? SubstrateHostOrientation.FaceDown : SubstrateHostOrientation.FaceUp; } bool NeedReverse = false; string strCarrierID = string.Empty; var wafer = WaferManager.Instance.GetWafer(ModuleName.Flipper, 0); try { await Task.Run(() => { SubstrateHostOrientation flipOrient; string host = BrooksConst.ModuleString["FLIPPER"]; SubstrateHostOrientation originalOrient = _ef.GetHostOrientation(host); if (originalOrient == SubstrateHostOrientation.Unknown) { _ef.ApplyWaferRestraint(host); _ef.FlipHost(host, SubstrateHostOrientation.FaceUp); _ef.ReleaseWaferRestraint(host); originalOrient = SubstrateHostOrientation.FaceUp; } if (Msg.Parameters[0] == "AlwaysReverse") { flipOrient = _GetReversedOrient(originalOrient); NeedReverse = true; } else { bool reversed = false; if (!wafer.IsEmpty) reversed = wafer.IsReversed; if ((Msg.Parameters[0] == "FaceUp" && reversed) || (Msg.Parameters[0] == "FaceDown" && !reversed)) { flipOrient = _GetReversedOrient(originalOrient); NeedReverse = true; } else { flipOrient = originalOrient; } } _ef.ApplyWaferRestraint(host); _ef.FlipHost(host, flipOrient); _ef.ReleaseWaferRestraint(host); }); } catch (Exception e) { Singleton.Instance.EFEM.PostMsg(EfemEntity.MSG.Error, Msg); EV.PostAlarmLog("EFEM", e.Message.ToString()); return false; } if (!wafer.IsEmpty && NeedReverse) { wafer.IsReversed = !wafer.IsReversed; } var args = new EfemActionArgs { Module = ModuleName.Flipper, CommandType = Msg.Operation, Status = ActionStatus.Completed, }; CommandUpdated?.Invoke(this, args); return true; } private async Task AsyncQueryLPPresence() { try { await Task.Run(() => { foreach (var lp in BrooksConst.dictLocToModule) { if (ModuleHelper.IsInstalled(lp.Value) && ModuleHelper.IsLoadPort(lp.Value)) { var lpState = _ef.GetCarrierPresenceState(lp.Key); bool bPresent = lpState == PresenceState.Present; if (bPresent != Singleton.Instance.EFEM.EfemDevice[lp.Value].HasCassette) { if (lpState == PresenceState.Present) { var argss = new EfemEventArgs { Module = lp.Value, CommandType = EfemOperation.SigStatus, EvtStr = "Carrier Arrival", DataList = new List { BrooksConst.dictModuleToString[lp.Value], "00000341", "00000000" } }; EventUpdated?.Invoke(this, argss); } else { var args = new EfemEventArgs { Module = lp.Value, CommandType = EfemOperation.SigStatus, EvtStr = "Carrier Leave", DataList = new List { BrooksConst.dictModuleToString[lp.Value], "00000342", "00000002" } }; this.EventUpdated?.Invoke(this, args); EV.PostInfoLog("EFEM", "Carrier removed on " + lp.Value + ": " + $"{lpState}"); } } } } }); } catch (Exception e) { EV.PostAlarmLog("EFEM", $"Check Loadport presence status failed: {e.Message}"); } var Args = new EfemActionArgs { Module = ModuleName.EFEM, CommandType = EfemOperation.QueryLPPresence, Status = ActionStatus.Completed, }; CommandUpdated?.Invoke(this, Args); return true; } #endregion } public class BrooksConst { public static Dictionary ModuleString = new Dictionary { { "P1", "PortA" }, { "P101", "PortA.Slot1" }, { "P102", "PortA.Slot2" }, { "P103", "PortA.Slot3" }, { "P104", "PortA.Slot4" }, { "P105", "PortA.Slot5" }, { "P106", "PortA.Slot6" }, { "P107", "PortA.Slot7" }, { "P108", "PortA.Slot8" }, { "P109", "PortA.Slot9" }, { "P110", "PortA.Slot10" }, { "P111", "PortA.Slot11" }, { "P112", "PortA.Slot12" }, { "P113", "PortA.Slot13" }, { "P114", "PortA.Slot14" }, { "P115", "PortA.Slot15" }, { "P116", "PortA.Slot16" }, { "P117", "PortA.Slot17" }, { "P118", "PortA.Slot18" }, { "P119", "PortA.Slot19" }, { "P120", "PortA.Slot20" }, { "P121", "PortA.Slot21" }, { "P122", "PortA.Slot22" }, { "P123", "PortA.Slot23" }, { "P124", "PortA.Slot24" }, { "P125", "PortA.Slot25" }, { "P126", "PortA.Slot26" }, { "P2", "PortB" }, { "P201", "PortB.Slot1" }, { "P202", "PortB.Slot2" }, { "P203", "PortB.Slot3" }, { "P204", "PortB.Slot4" }, { "P205", "PortB.Slot5" }, { "P206", "PortB.Slot6" }, { "P207", "PortB.Slot7" }, { "P208", "PortB.Slot8" }, { "P209", "PortB.Slot9" }, { "P210", "PortB.Slot10" }, { "P211", "PortB.Slot11" }, { "P212", "PortB.Slot12" }, { "P213", "PortB.Slot13" }, { "P214", "PortB.Slot14" }, { "P215", "PortB.Slot15" }, { "P216", "PortB.Slot16" }, { "P217", "PortB.Slot17" }, { "P218", "PortB.Slot18" }, { "P219", "PortB.Slot19" }, { "P220", "PortB.Slot20" }, { "P221", "PortB.Slot21" }, { "P222", "PortB.Slot22" }, { "P223", "PortB.Slot23" }, { "P224", "PortB.Slot24" }, { "P225", "PortB.Slot25" }, { "P226", "PortB.Slot26" }, { "P3", "PortC" }, { "P301", "PortC.Slot1" }, { "P302", "PortC.Slot2" }, { "P303", "PortC.Slot3" }, { "P304", "PortC.Slot4" }, { "P305", "PortC.Slot5" }, { "P306", "PortC.Slot6" }, { "P307", "PortC.Slot7" }, { "P308", "PortC.Slot8" }, { "P309", "PortC.Slot9" }, { "P310", "PortC.Slot10" }, { "P311", "PortC.Slot11" }, { "P312", "PortC.Slot12" }, { "P313", "PortC.Slot13" }, { "P314", "PortC.Slot14" }, { "P315", "PortC.Slot15" }, { "P316", "PortC.Slot16" }, { "P317", "PortC.Slot17" }, { "P318", "PortC.Slot18" }, { "P319", "PortC.Slot19" }, { "P320", "PortC.Slot20" }, { "P321", "PortC.Slot21" }, { "P322", "PortC.Slot22" }, { "P323", "PortC.Slot23" }, { "P324", "PortC.Slot24" }, { "P325", "PortC.Slot25" }, { "P326", "PortC.Slot26" }, { "BUFFER", "EFEM.Port_Buffer" }, { "BUFFER01", "EFEM.Port_Buffer.Slot1" }, { "BUFFER02", "EFEM.Port_Buffer.Slot2" }, { "BUFFER03", "EFEM.Port_Buffer.Slot3" }, { "BUFFER04", "EFEM.Port_Buffer.Slot4" }, { "BUFFER05", "EFEM.Port_Buffer.Slot5" }, { "BUFFER06", "EFEM.Port_Buffer.Slot6" }, { "BUFFER07", "EFEM.Port_Buffer.Slot7" }, { "BUFFER08", "EFEM.Port_Buffer.Slot8" }, { "BUFFER09", "EFEM.Port_Buffer.Slot9" }, { "BUFFER10", "EFEM.Port_Buffer.Slot10" }, { "BUFFER11", "EFEM.Port_Buffer.Slot11" }, { "BUFFER12", "EFEM.Port_Buffer.Slot12" }, { "BUFFER13", "EFEM.Port_Buffer.Slot13" }, { "BUFFER14", "EFEM.Port_Buffer.Slot14" }, { "BUFFER15", "EFEM.Port_Buffer.Slot15" }, { "BUFFER16", "EFEM.Port_Buffer.Slot16" }, { "BUFFER17", "EFEM.Port_Buffer.Slot17" }, { "BUFFER18", "EFEM.Port_Buffer.Slot18" }, { "BUFFER19", "EFEM.Port_Buffer.Slot19" }, { "BUFFER20", "EFEM.Port_Buffer.Slot20" }, { "BUFFER21", "EFEM.Port_Buffer.Slot21" }, { "BUFFER22", "EFEM.Port_Buffer.Slot22" }, { "BUFFER23", "EFEM.Port_Buffer.Slot23" }, { "BUFFER24", "EFEM.Port_Buffer.Slot24" }, { "BUFFER25", "EFEM.Port_Buffer.Slot25" }, //{ "ALIGN", "WaferAligner" }, // Cooling 1 //{ "ALIGN2", "WaferAligner2" }, // Cooling 2 //{ "ALIGN3", "WaferAligner3" }, // Aligher 1 //{ "ALIGN4", "WaferAligner4" }, // Aligner 2 // only for test //{ "ALIGN", "EFEM.WaferFlipper1.Chuck" }, // Cooling 1 { "FLIPPER", "EFEM.WaferFlipper1.Chuck" }, // Cooling 2 { "ALIGN4", "Aligner2" }, // Aligner 2 { "ALIGN2", "PortB.Slot20" }, // Cooling 2 { "ALIGN3", "EFEM.WaferAligner" }, // Aligher 1 }; public static readonly Dictionary ArmString = new Dictionary { ["ARM1"] = "EE2", ["ARM2"] = "EE1", ["ARM3"] = "EE1" }; public static readonly Dictionary LightTowerColorMap = new Dictionary { ["BLUE"] = LightTowerComponent.Blue, ["GREEN"] = LightTowerComponent.Green, ["AMBER"] = LightTowerComponent.Amber, ["RED"] = LightTowerComponent.Red, ["WHITE"] = LightTowerComponent.White, ["BUZZER1"] = LightTowerComponent.Buzzer, ["BUZZER2"] = LightTowerComponent.Buzzer2, ["YELLOW"] = LightTowerComponent.Amber, }; public static readonly Dictionary LightTowerIndicatorMap = new Dictionary { ["OFF"] = UiIndicatorState.Off, ["ON"] = UiIndicatorState.On, ["Pulsating"] = UiIndicatorState.Pulsating, ["Strobe"] = UiIndicatorState.Strobe, ["BLINK"] = UiIndicatorState.Pulsating, }; public static readonly Dictionary dictLPs = new Dictionary { { "PortA", ModuleName.LP1}, { "PortB", ModuleName.LP2}, { "PortC", ModuleName.LP3}, { "PortD", ModuleName.LP4}, {"EFEM.LoadPortA", ModuleName.LP1 }, {"EFEM.LoadPortB", ModuleName.LP2 }, {"EFEM.LoadPortC", ModuleName.LP3 }, {"EFEM.LoadPortD", ModuleName.LP4 }, {"EFEM", ModuleName.EFEM }, }; public static readonly Dictionary dictModuleToString = new Dictionary { {ModuleName.LP1, "P1" }, {ModuleName.LP2, "P2" }, {ModuleName.LP3, "P3" }, {ModuleName.LP4, "P4" }, }; public static readonly Dictionary dictLocToModule = new Dictionary { { "PortA", ModuleName.LP1}, { "PortB", ModuleName.LP2}, { "PortC", ModuleName.LP3}, { "PortD", ModuleName.LP4}, { "Port_Buffer", ModuleName.Buffer }, { "WaferAligner", ModuleName.Aligner1 }, { "WaferFlipper1", ModuleName.Flipper }, { "WaferEngine", ModuleName.EfemRobot }, }; private static readonly Dictionary BufferString = new Dictionary { { "BUFFER", "EFEM.PortD" }, { "BUFFER01", "EFEM.PortD.Slot1" }, { "BUFFER02", "EFEM.PortD.Slot2" }, { "BUFFER03", "EFEM.PortD.Slot3" }, { "BUFFER04", "EFEM.PortD.Slot4" }, { "BUFFER05", "EFEM.PortD.Slot5" }, { "BUFFER06", "EFEM.PortD.Slot6" }, { "BUFFER07", "EFEM.PortD.Slot7" }, { "BUFFER08", "EFEM.PortD.Slot8" }, { "BUFFER09", "EFEM.PortD.Slot9" }, { "BUFFER10", "EFEM.PortD.Slot10" }, { "BUFFER11", "EFEM.PortD.Slot11" }, { "BUFFER12", "EFEM.PortD.Slot12" }, { "BUFFER13", "EFEM.PortD.Slot13" }, { "BUFFER14", "EFEM.PortD.Slot14" }, { "BUFFER15", "EFEM.PortD.Slot15" }, { "BUFFER16", "EFEM.PortD.Slot16" }, { "BUFFER17", "EFEM.PortD.Slot17" }, { "BUFFER18", "EFEM.PortD.Slot18" }, { "BUFFER19", "EFEM.PortD.Slot19" }, { "BUFFER20", "EFEM.PortD.Slot20" }, { "BUFFER21", "EFEM.PortD.Slot21" }, { "BUFFER22", "EFEM.PortD.Slot22" }, { "BUFFER23", "EFEM.PortD.Slot23" }, { "BUFFER24", "EFEM.PortD.Slot24" }, { "BUFFER25", "EFEM.PortD.Slot25" }, }; public static string GetHostName(string para) { if (SC.GetValue("System.IsSimulatorMode") && para.Contains("BUFFER")) { return BufferString[para]; } return ModuleString[para]; } } }