using System; using System.Collections; using System.Threading.Tasks; using Aitex.Core.Common; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Device.Unit; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using Aitex.Sorter.Common; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.FAServices; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Efems.Rorzes; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts; namespace JetEfemLib.LPs { public class JetEfemLoadPort : LoadPort, IEfemLoadPortCallback { public enum LoadPortStates { Undefined = 0, NotInitialized = 1, Initializing = 2, Idle = 3, Mapping = 4, MappingStation = 5, Homing = 6, Faulted = 7, Clamping = 8, Docking = 9, Unclamping = 10, Undocking = 11, OpeningDoor = 12, ClosingDoor = 13, Loading = 15, Unloading = 16, ReadingCarrierID = 17, Querying = 18, ChangeAccessMode = 19, ChangeTransferState = 20, WritingCarrierID = 21, ClearError, SetIndicator, } private LoadportCassetteState _cassetteState; public override LoadportCassetteState CassetteState { get { return _cassetteState; } set { _cassetteState = value; } } private FoupClampState _clampState; public override FoupClampState ClampState { get { return _clampState; } set { _clampState = value; } } private FoupDockState _dockState; public override FoupDockState DockState { get { return _dockState; } set { _dockState = value; } } private FoupDoorState _doorState; public override FoupDoorState DoorState { get { return _doorState; } set { _doorState = value; } } public override bool IsAutoClampOnFoupOn { get { return SC.GetValueOrDefault($"EFEM.LoadPort.AutoClampOnFoupOn"); } } public override bool IsAutoReadCarrierID { get { return SC.GetValueOrDefault($"EFEM.LoadPort.EnableAutoCarrierIdRead"); } } private RorzeEfem _efem; public override bool IsWaferProtrude { get; set; } private RD_TRIG _trigPresentAbsent = new RD_TRIG(); private RD_TRIG _trigPresentAbsentDely = new RD_TRIG(); private RD_TRIG _trigPlacement = new RD_TRIG(); private R_TRIG _trigWaferProtrude = new R_TRIG(); private LoadPortStates _loadPortState; public WaferSize WaferSize { get; set; } public string LastMapResult { get; set; } public override bool IsBusy => _loadPortState != LoadPortStates.Idle; private DeviceTimer _deviceTimer = new DeviceTimer(); private int _timeDelayNotifyCassettePresent = 100; //ms public override WaferSize GetCurrentWaferSize() { return WaferSize; } //private bool _present4; //private bool _present6; private string _efemName; //private bool _indicatorPlaced; //private bool _indicatorError; //private bool _isIntialized; public JetEfemLoadPort(string module, string name, string efem) { base.Module = module; base.Name = name; base.Display = name; base.DeviceID = ""; _efemName = efem; IsMapWaferByLoadPort = false; _loadPortState = LoadPortStates.NotInitialized; } public override bool Initialize() { if (_efem == null && !string.IsNullOrEmpty(_efemName)) { _efem = DEVICE.GetDevice(_efemName); _efem.SetLoadPortCallback(ModuleHelper.Converter(Module), this); } //DATA.Subscribe($"{Module}.IndicatorPlaced", () => _indicatorPlaced); //DATA.Subscribe($"{Module}.IndicatorError", () => _indicatorError); DATA.Subscribe($"{Module}.IsWaferProtrude", () => IsWaferProtrude); //DATA.Subscribe($"{Module}.IsPresent4", () => _present4); //DATA.Subscribe($"{Module}.IsPresent6", () => _present6); DATA.Subscribe($"{Module}.WaferSize", () => WaferSize.ToString()); DATA.Subscribe($"{Module}.LastMapResult", () => LastMapResult); if (SC.ContainsItem("EFEM.LoadPort.TimeDelayNotifyCassettePresent")) { _timeDelayNotifyCassettePresent = SC.GetValue("EFEM.LoadPort.TimeDelayNotifyCassettePresent"); } return base.Initialize(); } public override void Reset() { base.Reset(); _trigWaferProtrude.RST = true; } public override bool IsEnableMapWafer() { return IsPlacement && !IsWaferProtrude; } public override bool IsEnableMapWafer(out string reason) { reason = string.Empty; if (_loadPortState != LoadPortStates.Idle) { reason = "Cassette is busy"; return false; } if (!IsPlacement) { reason = "Cassette not properly placed"; return false; } if (IsWaferProtrude) { reason = "Found wafer protrude"; return false; } if (CassetteState != LoadportCassetteState.Normal) { reason = "Cassette is abnormal"; return false; } return IsPlacement && !IsWaferProtrude; } public override bool IsEnableTransferWafer() { return IsEnableTransferWafer(out _); } public override bool IsEnableTransferWafer(out string reason) { if (_loadPortState != LoadPortStates.Idle) { reason = "Cassette is busy"; return false; } if (!IsPlacement) { reason = "No cassette present"; return false; } if (IsWaferProtrude) { reason = "Found wafer protrude"; return false; } if (!_isMapped) { reason = "Cassette not mapped"; return false; } if (DoorState != FoupDoorState.Open) { reason = "Cassette not open"; return false; } if (CassetteState != LoadportCassetteState.Normal) { reason = "Cassette is abnormal"; return false; } reason = ""; return true; } public virtual void NoteStatus(string data1, string data2) { uint result1 = Convert.ToUInt32(data1, 16); uint result2 = Convert.ToUInt32(data2, 16); BitArray bitData1 = new BitArray(new int[] { Convert.ToInt32(data1, 16) }); BitArray bitData2 = new BitArray(new int[] { Convert.ToInt32(data2, 16) }); //placement bit 0 //present bit 1 //access sw bit 2 //clampState bit 3 //doorState bit 4 //dockState bit 5 //wafer size 8 bit 6 //wafer size 12 bit 7 bool placement = (result1 & 0x00000001u) == 0x00000001u; bool present = !((result1 & 0x00000002u) == 0x00000002u); SetPresent(present); SetPlaced(placement); _isAccessSwPressed = (result1 & 0x00000004u) == 0x00000004u; _clampState = (result1 & 0x00000008u) == 0x00000008u ? FoupClampState.Close : FoupClampState.Open; _doorState = (result1 & 0x00000800u) == 0x00000800u ? FoupDoorState.Open : FoupDoorState.Close; _dockState = (result1 & 0x00000020u) == 0x00000020u ? FoupDockState.Docked : FoupDockState.Undocked; bool sizecheck1 = (result1 & 0x00000040u) == 0x00000040u; bool sizecheck2 = (result1 & 0x00000080u) == 0x00000080u; bool sizecheck3 = (result1 & 0x00000100u) == 0x00000100u; if (IsPlacement) { //if (isWS8 == isWS12) //{ // EV.PostAlarmLog(LPModuleName.ToString(), "Get WaferSize Data Abnormal , pls check config"); //} if (sizecheck1 && sizecheck2 && sizecheck3) { WaferSize = WaferSize.WS8; CarrierManager.Instance.UpdateWaferSize(LPModuleName, 0, WaferSize); } else if (!sizecheck1 && sizecheck2 && sizecheck3) { WaferSize = WaferSize.WS3; CarrierManager.Instance.UpdateWaferSize(LPModuleName, 0, WaferSize); } else if (sizecheck1 && sizecheck2 && !sizecheck3) { WaferSize = WaferSize.WS6; CarrierManager.Instance.UpdateWaferSize(LPModuleName, 0, WaferSize); } else if (sizecheck1 && !sizecheck2 && sizecheck3) { WaferSize = WaferSize.WS4; CarrierManager.Instance.UpdateWaferSize(LPModuleName, 0, WaferSize); } } IndicatorVALID = GetIndicatorState((result1 & 0x01000000u) == 0x01000000u); //bit24 IndicatorCS0 = GetIndicatorState((result1 & 0x02000000u) == 0x02000000u); //bit25 IndicatorCS1 = GetIndicatorState((result1 & 0x04000000u) == 0x04000000u); //bit26 IndicatorTR_REQ = GetIndicatorState((result1 & 0x10000000u) == 0x10000000u); //bit28 IndicatorBUSY = GetIndicatorState((result1 & 0x20000000u) == 0x20000000u); //bit29 IndicatorCOMPT = GetIndicatorState((result1 & 0x40000000u) == 0x40000000u); //bit30 IndicatorCONT = GetIndicatorState((result1 & 0x80000000u) == 0x80000000u); //bit31 //E84Signal.VALID = (result1 & 0x01000000u) == 0x01000000u //bit 24 //E84Signal.CS_0 = (result1 & 0x02000000u) == 0x02000000u //bit 25 //E84Signal.CS_1 = (result1 & 0x04000000u) == 0x04000000u //bit 26 //E84Signal.TR_REQ = (result1 & 0x10000000u) == 0x10000000u //bit 28 //E84Signal.BUSY = (result1 & 0x20000000u) == 0x20000000u //bit 29 //E84Signal.COMPT = (result1 & 0x40000000u) == 0x40000000u //bit 30 //E84Signal.CONT = (result1 & 0x80000000u) == 0x80000000u //bit 31 //check presence light bit 0 //check placement light bit 1 //check load light bit 2 //check unload light bit 3 //check manual mode light bit 4 //check error light bit 5 //check clamp/unclamp light bit 6 //check dock/undock light bit 7 //check access switch light bit 8 IndicatiorPresence = GetIndicatorState(bitData2[0]); IndicatiorPlacement = GetIndicatorState(bitData2[1]); IndicatiorLoad = GetIndicatorState(bitData2[2]); IndicatiorUnload = GetIndicatorState(bitData2[3]); IndicatiorManualMode = GetIndicatorState(bitData2[4]); IndicatorAlarm = GetIndicatorState(bitData2[5]); IndicatiorClampUnclamp = GetIndicatorState(bitData2[6]); IndicatiorDockUndock = GetIndicatorState(bitData2[7]); IndicatiorOpAccess = GetIndicatorState(bitData2[8]); IndicatorL_REQ = GetIndicatorState(bitData2[24]); //bit24 IndicatorU_REQ = GetIndicatorState(bitData2[25]); //bit25 IndicatorREADY = GetIndicatorState(bitData2[27]); //bit27 IndicatorHO_AVBL = GetIndicatorState(bitData2[30]); //bit30 IndicatorES = GetIndicatorState(bitData2[31]); //bit31 //E84Signal.L_REQ = bitData2[24] //bit 24 //E84Signal.U_REQ = bitData2[25] //bit 25 //E84Signal.READY = bitData2[27] //bit 27 //E84Signal.HO_AVBL = bitData2[30] //bit 30 //E84Signal.ES = bitData2[31] //bit 31 CassetteState = IsPlacement ? LoadportCassetteState.Normal : LoadportCassetteState.None; if (bitData2[5]) { Error = true; } else { if (_loadPortState == LoadPortStates.Faulted) Error = true; else Error = false; } } /* *Report the wafer presence of all slots. 0 =No wafer 1 =Wafer presence 2 =Abnormal thickness (Wafer is thick) 3 =Cross slotted wafer 4 =Front down wafer 7 =Multiple wafers are in the same slot 8 =Abnormal thickness (Wafer is thin) */ public virtual void NoteSlotMap(string slotMap) { slotMap = slotMap.Replace('3', '2'); slotMap = slotMap.Replace('4', 'W'); slotMap = slotMap.Replace('7', 'W'); slotMap = slotMap.Replace('8', 'W'); slotMap = slotMap.Replace('2', 'W'); LastMapResult = slotMap; base.OnSlotMapRead(slotMap); } private IndicatorState GetIndicatorState(bool flag) { if (flag) return IndicatorState.ON; else return IndicatorState.OFF; } public override void ResetData() { _isMapped = false; _isLoaded = false; } public void NoteComplete() { //if(_loadPortState == LoadPortStates.Homing) // _isIntialized = true; if (_loadPortState == LoadPortStates.Clamping) EV.Notify(EventPortClamped, new SerializableDictionary() { {DataVariables.PortID,PortId} }); if (_loadPortState == LoadPortStates.Unclamping) EV.Notify(EventPortUnClamped, new SerializableDictionary() { {DataVariables.PortID,PortId} }); _loadPortState = LoadPortStates.Idle; } public void NoteCancel(string error) { IsBusy = false; EV.PostAlarmLog(Module, $"{Module} is canceled since {error}"); } public void NoteFailed(string error) { IsBusy = false; EV.PostAlarmLog(Module, $"{Module} is failed since {error}"); } public void NoteCarrierID(string carrierID) { base.OnCarrierIdRead(ModuleHelper.Converter(Module), Name, carrierID); } public void NoteWRITETAG(string cid) { base.ProceedSetCarrierID(cid); } public override bool FALoad(out string reason) //map and loads { reason = ""; OP.DoOperation($"{Name}.Load"); return true; } public override bool FAUnload(out string reason) { reason = ""; OP.DoOperation($"{Name}.Unload"); return true; } public override bool Home(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } _loadPortState = LoadPortStates.Homing; //_isIntialized = false; _isMapped = false; if (!_efem.HomeLoadPort(Module, out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } _isLoaded = false; return true; } public override bool ClearError(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } //_loadPortState = LoadPortStates.ClearError; //if (!_efem.ClearAlarm(Module, out reason)) //{ // _loadPortState = LoadPortStates.Faulted; // return false; //} return true; } public override bool Clamp(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!IsPlacement) { reason = "no carrier at load port"; return false; } if (ClampState == FoupClampState.Close) { return true; } _loadPortState = LoadPortStates.Clamping; if (!_efem.ClampCarrier(Module, out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } return true; } public override bool Unclamp(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!IsPlacement) { reason = "no carrier at load port"; return false; } //if(DoorState != FoupDoorState.Close) //{ // reason = "cassette not closed"; // return false; //} //if(DockState != FoupDockState.Undocked) //{ // reason = "cassette not undocked"; // return false; //} if (ClampState == FoupClampState.Open) { return true; } _loadPortState = LoadPortStates.Unclamping; if (!_efem.UnclampCarrier(Module, out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } _isMapped = false; return true; } public override bool Dock(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!IsPlacement) { reason = "no carrier at load port"; return false; } //if (ClampState != FoupClampState.Close) //{ // reason = "cassette not clamped"; // return false; //} if (DockState == FoupDockState.Docked) { return true; } _loadPortState = LoadPortStates.Docking; if (!_efem.MoveCarrierPort(Module, "Dock", out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } return true; } public override bool Undock(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!IsPlacement) { reason = "no carrier at load port"; return false; } //if (DoorState != FoupDoorState.Close) //{ // reason = "cassette not closed"; // return false; //} if (DockState == FoupDockState.Undocked) { return true; } _loadPortState = LoadPortStates.Undocking; if (!_efem.MoveCarrierPort(Module, "Undock", out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } _isMapped = false; return true; } public override bool OpenDoor(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!IsPlacement) { reason = "no carrier at load port"; return false; } //if (ClampState != FoupClampState.Close) //{ // reason = "cassette not clamped"; // return false; //} //if (DockState != FoupDockState.Docked) //{ // reason = "cassette not docked"; // return false; //} if (DoorState == FoupDoorState.Open) { return true; } _loadPortState = LoadPortStates.OpeningDoor; if (!_efem.OpenCarrierDoor(Module, out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } return true; } public override bool CloseDoor(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!IsPlacement) { reason = "no carrier at load port"; return false; } //if (ClampState != FoupClampState.Close) //{ // reason = "cassette not clamped"; // return false; //} //if (DockState != FoupDockState.Docked) //{ // reason = "cassette not docked"; // return false; //} if (DoorState == FoupDoorState.Close) { return true; } _loadPortState = LoadPortStates.ClosingDoor; if (!_efem.CloseCarrierDoor(Module, out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } _isMapped = false; return true; } public override bool ReadRfId(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!IsPlacement) { reason = "no carrier at load port"; return false; } //_loadPortState = LoadPortStates.ReadingCarrierID; if (!_efem.ReadCarrierId(Module, out string carrierId, out reason)) { EV.PostAlarmLog(Module, "Execute ReadRfid Failed " + reason); _loadPortState = LoadPortStates.Faulted; return false; } return true; } public override bool WriteRfId(string carrierId, out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!IsPlacement) { reason = "no carrier at load port"; return false; } //_loadPortState = LoadPortStates.WritingCarrierID; if (!_efem.WriteCarrierId(Module, carrierId, out reason)) { SerializableDictionary dvid = new SerializableDictionary(); dvid["PortID"] = PortId; dvid[PORT_CTGRY] = PortCategory; EV.Notify(EventCarrierIdWriteFailed, dvid); EV.PostAlarmLog(Module, "Execute WriteRfid Failed " + reason); _loadPortState = LoadPortStates.Faulted; return false; } return true; } public override bool ChangeAccessMode(bool auto, out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } _loadPortState = LoadPortStates.ChangeAccessMode; //if (!_efem.ChangeLoadPortAccessMode(ModuleHelper.Converter(Module), auto ? LPAccessMode.AUTO.ToString() : LPAccessMode.MANUAL.ToString(), out reason)) if (!_efem.SetLoadPortLight(ModuleHelper.Converter(Module), IndicatorType.AccessManual, auto ? IndicatorState.OFF : IndicatorState.ON, out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } return true; } public override bool GetAccessMode(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!_efem.GetLoadPortAccessMode(ModuleHelper.Converter(Module), out reason)) { return false; } return true; } public override bool SetIndicator(IndicatorType light, IndicatorState state) { if (_efem == null || !_efem.Connection.IsConnected) { return false; } if (!LoadPortIndicatorLightMap.ContainsKey(light)) { EV.PostWarningLog(Module, $"Not supported indicator {light}"); return false; } _loadPortState = LoadPortStates.SetIndicator; if (!_efem.SetLoadPortLight(ModuleHelper.Converter(Module), light, state, out string reason)) { _loadPortState = LoadPortStates.Faulted; LOG.Write(reason); return false; } return true; } public override bool QueryState(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } _loadPortState = LoadPortStates.Querying; if (!_efem.GetLoadPortStatus(Module, out _cassetteState, out _clampState, out _dockState, out _doorState, out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } return true; } public override bool QueryWaferMap(out string reason) { reason = string.Empty; if (_efem == null || !_efem.Connection.IsConnected) { reason = "efem not connected"; return false; } if (!IsPlacement) { reason = "no carrier at load port"; return false; } if (_efem.CheckIsBusy(ModuleName.EfemRobot)) { reason = "efem robot is busy"; return false; } //if (ClampState != FoupClampState.Close) //{ // reason = "cassette not clamped"; // return false; //} //if (DockState != FoupDockState.Docked) //{ // reason = "cassette not docked"; // return false; //} if (DoorState != FoupDoorState.Open) { reason = "cassette not open"; return false; } _loadPortState = LoadPortStates.Mapping; if (!_efem.MapCarrier(Module, out string slotMap, out reason)) { _loadPortState = LoadPortStates.Faulted; return false; } return true; } public override bool GetMapInfo(out string reason) { reason = string.Empty; if (!IsPlacement) { reason = "no carrier at load port"; return false; } _loadPortState = LoadPortStates.Querying; if (!_efem.QueryMapResult(Module, out reason, false)) { _loadPortState = LoadPortStates.Faulted; return false; } return true; } public override bool Stop(out string reason) { reason = string.Empty; _loadPortState = LoadPortStates.Idle; return true; } public void CarrierProcessStartEventNotify() { EV.Notify(UniversalEvents.CarrierProcessStart, new SerializableDictionary() { { DataVariables.PortID, Module}, { DataVariables.CarrierID, _carrierId}, }); } public void CarrierProcessCompleteEventNotify() { EV.Notify(UniversalEvents.CarrierProcessComplete, new SerializableDictionary() { { DataVariables.PortID, Module}, { DataVariables.CarrierID, _carrierId}, }); } public void WriteLoadPortAccessModeSuccess() { Task.Delay(200).ContinueWith(x=>GetAccessMode(out string reason)); } } }