using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; 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.OperationCenter; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Mainframe.LLs; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadLocks; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.LoadPorts.TDK; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.PMs; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Servo.NAIS; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.TMs; using SicPM.Devices; namespace Mainframe.TMs { public class TMSlitValveRoutine : TMBaseRoutine { enum RoutineStep { ChamberBalance, OpenTMToLLVent, OpenTMToPMV70, CheckPressureCondition, SetSlitValve, SetSlowVentValve, SetM40, LLRoutine, Delay, Delay1, Delay2, Delay3, Delay4, CloseTMToLLVent, CloseTMToPMV70, PumpDownToBase, CheckConfinementIsDown, SetConfinementRingUp, SetConfinementRingDown, SetPostTransfer, SetPmPreTrasfer, SetV77, SetV77Close, SetTmMfc, WaitTempBelow900, WaitPVTempBelowSet, CheckPressureCondition1, WaitPMIdle } private int _timeout; private SicTM _tm; private LoadLock _ll; private IoValve PMToTm_V70; private IoPressure _pmPT1; private IoConfinementRing _confinementRing; private SicPM.Devices.SicServo _sicServo; private NAISServo _naisServo; SicPM.Devices.IoInterLock _pmIoInterLock; SicPM.Devices.IoTC _tc1; private string _paramTarget; private bool _paramIsOpen; private bool _confinementIsDown = false; //private TMPumpWithTurboRoutine _pumpDownRoutine; private TMPressureBalanceRoutine _balanceRoutine; private TMPressureBalancePidRoutine _pidBalanceRoutine; private TMPressureBalancePidRoutine _pidAwaysRoutine; private LoadLockServoTo _llVentTo; private IoMFC _m40; private bool _needPressureBalance; private bool _userPidBalance; private int _timeOutV70; private int _timeOutV85; private int _rotationStopTimeout = 120; private double _maxPressureDiffOpenSlitValve; private bool _isAtmMode; private bool _isLockLock; private bool _isPMA; private int _tmV77DelayTime = 5; private double _tmMfcFlow = 10; private bool _pmPostTrasferNeedEnableHeat = true; private bool _preTransferPSUEnable = false; //private SCConfigItem _scPVInnerTempLimit; //private SCConfigItem _scPVMiddleTempLimit; //private SCConfigItem _scPVOuterTempLimit; private double _pmPVInnerTempLimit = 0; private double _pmPVMiddleTempLimit = 0; private double _pmPVOuterTempLimit = 0; public TMSlitValveRoutine() { Module = ModuleName.TM.ToString(); Name = "Slit Valve"; _tm = DEVICE.GetDevice($"{ ModuleName.System.ToString()}.{ ModuleName.TM.ToString()}"); _ll = DEVICE.GetDevice($"{ModuleName.LoadLock}.{ModuleName.LoadLock}"); PMToTm_V70 = DEVICE.GetDevice("PM1.V70"); _m40 = DEVICE.GetDevice($"TM.Mfc40"); _confinementRing = DEVICE.GetDevice("PM1.ConfinementRing"); _sicServo= DEVICE.GetDevice("PM1.PMServo"); _pmIoInterLock = DEVICE.GetDevice($"PM1.PMInterLock"); _tc1= DEVICE.GetDevice($"PM1.TC1"); if (SC.GetConfigItem("NAISServo.EnableDevice").BoolValue) { _naisServo = DEVICE.GetDevice($"PM1.NAISServo"); } } public void Init(string module,bool isOpen,bool needEnableHeat) { _pmPostTrasferNeedEnableHeat = needEnableHeat; Init(module, isOpen); } public void Init(string module, bool isOpen) { _paramTarget = module; _paramIsOpen = isOpen; Name = isOpen ? "Open Slit Valve" : "Close Slit Valve"; //_pumpDownRoutine = new TMPumpWithTurboRoutine(); _balanceRoutine = new TMPressureBalanceRoutine(); _pidBalanceRoutine = new TMPressureBalancePidRoutine(); _pidAwaysRoutine = new TMPressureBalancePidRoutine(); _llVentTo = new LoadLockServoTo(ModuleName.LoadLock); _balanceRoutine.Init(ModuleHelper.Converter(module)); _pidBalanceRoutine.Init(ModuleHelper.Converter(module)); _pidAwaysRoutine.Init(ModuleHelper.Converter(module), true); _needPressureBalance = SC.GetValue("TM.NeedPressureBalance"); _userPidBalance= SC.GetValue("TM.PressureBalanceUsePid"); } public override Result Start(params object[] objs) { Reset(); if ((_paramIsOpen && TMDevice.CheckSlitValveOpen(ModuleHelper.Converter(_paramTarget))) || (!_paramIsOpen && TMDevice.CheckSlitValveClose(ModuleHelper.Converter(_paramTarget)))) { string message = _paramIsOpen ? "open" : "close"; if (TMDevice.GetSlitValve(ModuleHelper.Converter(_paramTarget)) != null) EV.PostWarningLog(Module, $"{_paramTarget} slit valve already {message}"); return Result.DONE; } _tm.CloseAllVentPumpValue(); _isLockLock = ModuleHelper.IsLoadLock(_paramTarget); _isPMA = ModuleHelper.Converter(_paramTarget) == ModuleName.PM1 || ModuleHelper.Converter(_paramTarget) == ModuleName.PMA; if (_paramIsOpen) { bool isAtmMode = SC.GetValue("System.IsATMMode"); if (ModuleHelper.IsLoadLock(_paramTarget)) { LoadLock ll = DEVICE.GetDevice($"{_paramTarget}.{_paramTarget}"); if (isAtmMode) { if (!ll.CheckAtm()) { EV.PostWarningLog(Module, $"can not open slit valve, running in ATM mode, but {_paramTarget} not in ATM"); return Result.FAIL; } } else { if (!ll.CheckVacuum()) { EV.PostWarningLog(Module, $"can not open slit valve, {_paramTarget} not in vacuum"); return Result.FAIL; } } } if (ModuleHelper.IsPm(_paramTarget)) { //PM pm = DEVICE.GetDevice(_paramTarget); _pmPT1 = DEVICE.GetDevice($"{_paramTarget}.PT1"); double atmBase = SC.GetValue($"PM.AtmPressureBase"); double vacBase = SC.GetValue($"PM.VacuumPressureBase"); if (WaferManager.Instance.CheckHasWafer(ModuleName.PM1, 0)) { _pmPVInnerTempLimit = SC.GetValue($"PM.PM1.Heater.PickPVInnerTempLimit"); _pmPVMiddleTempLimit = SC.GetValue($"PM.PM1.Heater.PickPVMiddleTempLimit"); _pmPVOuterTempLimit = SC.GetValue($"PM.PM1.Heater.PickPVOuterTempLimit"); } else { _pmPVInnerTempLimit = SC.GetValue($"PM.PM1.Heater.PlacePVInnerTempLimit"); _pmPVMiddleTempLimit = SC.GetValue($"PM.PM1.Heater.PlacePVMiddleTempLimit"); _pmPVOuterTempLimit = SC.GetValue($"PM.PM1.Heater.PlacePVOuterTempLimit"); } if (isAtmMode) { //if (!pm.CheckAtm()) if (_pmPT1.FeedBack < atmBase) { EV.PostWarningLog(Module, $"can not open slit valve, running in ATM mode, but {_paramTarget} not in ATM"); return Result.FAIL; } } else { //if (!pm.CheckVacuum()) if (_pmPT1.FeedBack > vacBase) { EV.PostWarningLog(Module, $"can not open slit valve, {_paramTarget} not in vacuum"); return Result.FAIL; } } } ModuleName[] slitValveModules = new ModuleName[] { //ModuleName.LLA, ModuleName.LLB, ModuleName.PM1, // ModuleName.PM2, ModuleName.PM3, ModuleName.PM4 ModuleName.LoadLock,ModuleName.PM1, }; foreach (var slitValveModule in slitValveModules) { if (slitValveModule.ToString() == _paramTarget) continue; if (!_tm.CheckSlitValveClose(slitValveModule)) { EV.PostWarningLog(Module, $"can not open slit valve {_paramTarget}, {slitValveModule} slit valve not closed, can not open at same time"); return Result.FAIL; } } } if (ModuleHelper.IsLoadLock(_paramTarget)) { _needPressureBalance = SC.GetValue("TM.PressureBalance.EnableLL"); } else if (ModuleHelper.IsPm(_paramTarget)) { _needPressureBalance = SC.GetValue($"TM.PressureBalance.Enable{_paramTarget}"); } else { EV.PostAlarmLog(Module, $"did not define balance enable option for {_paramTarget}"); return Result.FAIL; } _maxPressureDiffOpenSlitValve = SC.GetValue("TM.MaxPressureDiffOpenSlitValve"); _timeout = SC.GetValue("System.SlitValveMotionTimeout"); _isAtmMode = SC.GetValue("System.IsATMMode"); _timeOutV70 = SC.GetValue($"TM.V70Timeout"); _timeOutV85 = SC.GetValue($"TM.V85Timeout"); _tmV77DelayTime= SC.GetValue($"TM.OpenSlitValveDelayTimeAfterV77"); _tmMfcFlow = SC.GetValue($"TM.MFCFlowWhenV77Open"); _preTransferPSUEnable = SC.GetValue($"PM.PM1.PreTransferPSUEnable"); Notify("Start"); return Result.RUN; } public override Result Monitor() { try { if (_isLockLock) { if (_paramIsOpen) { if (_userPidBalance) { ExecuteRoutine((int)RoutineStep.ChamberBalance, _pidBalanceRoutine); } else { ExecuteRoutine((int)RoutineStep.ChamberBalance, _balanceRoutine); } if (_needPressureBalance && !_isAtmMode) { TimeDelay((int)RoutineStep.Delay2, 1); ExecuteRoutine((int)RoutineStep.LLRoutine, _llVentTo); SetTmToLoadLockVent((int)RoutineStep.OpenTMToLLVent, true, _tm, _paramTarget, _timeOutV85); } CheckPressureCondition((int)RoutineStep.CheckPressureCondition, _tm, _paramTarget); } SetSlitValve((int)RoutineStep.SetSlitValve, TMDevice, _paramTarget, _paramIsOpen, _timeout); SetTmToLoadLockVent((int)RoutineStep.CloseTMToLLVent, false, _tm, _paramTarget, _timeOutV85); } else if (_isPMA) { if (_paramIsOpen) { SetPreTransfer((int)RoutineStep.SetPmPreTrasfer, _rotationStopTimeout);//旋转停止,加热停止 if (!_preTransferPSUEnable) { WaitPVTempratureBelowSet((int)RoutineStep.WaitPVTempBelowSet, 600); } WaitTempratureBelow900((int)RoutineStep.WaitTempBelow900, 600); if (_needPressureBalance && !_isAtmMode) { if (_userPidBalance) { ExecuteRoutine((int)RoutineStep.ChamberBalance, _pidBalanceRoutine); } else { ExecuteRoutine((int)RoutineStep.ChamberBalance, _balanceRoutine); } SetTmMfc((int)RoutineStep.SetTmMfc, _tmMfcFlow); SetPmToTmV70((int)RoutineStep.OpenTMToPMV70, true, _tm, _paramTarget, _timeOutV70); SetSlowVentValve((int)RoutineStep.SetV77, _tm, _paramIsOpen, _timeout); TimeDelay((int)RoutineStep.Delay1, _tmV77DelayTime); //5秒可配置 } CheckPressureCondition((int)RoutineStep.CheckPressureCondition, _tm, _paramTarget); } SetSlitValve((int)RoutineStep.SetSlitValve, TMDevice, _paramTarget, _paramIsOpen, _timeout); if (!_paramIsOpen) { //关闭闸板阀需要关闭V77 SetSlowVentValve((int)RoutineStep.SetV77Close, _tm, _paramIsOpen, _timeout); } SetPmToTmV70((int)RoutineStep.CloseTMToPMV70, false, _tm, _paramTarget, _timeOutV70); TimeDelay((int)RoutineStep.Delay2, 2); if (_paramIsOpen) { WaitPMIdle((int)RoutineStep.WaitPMIdle, 20); SetConfinementRingDown((int)RoutineStep.SetConfinementRingDown, 80); //隔热罩下降 TimeDelay((int)RoutineStep.Delay3, 2); } if (!_paramIsOpen) { SetPostTransfer((int)RoutineStep.SetPostTransfer, _pmPostTrasferNeedEnableHeat); TimeDelay((int)RoutineStep.Delay4, 2); } } } catch (RoutineBreakException) { return Result.RUN; } catch (RoutineFaildException) { return Result.FAIL; } Notify("Finished"); return Result.DONE; } public override void Abort() { PMToTm_V70.TurnValve(false, out string reason); _tm.CloseAllVentPumpValue(); } /// /// 打开或关闭V85 /// /// /// /// private void SetTmToLoadLockVent(int id,bool isOpen, TM tm, string module, int timeDelay) { Tuple ret = ExecuteAndWait(id, () => { Notify((isOpen ? "Open" : "Close") + " TM to LoadLock Vent"); if (!_tm.SetTmToLLVent(isOpen, out string reason)) { Stop(reason); return false; } return true; }, () => { double tmPressure = tm.ChamberPressure; double targetPressure = 0.0; if (ModuleHelper.IsLoadLock(_paramTarget)) { targetPressure = _ll.ChamberPressure; } else { Stop($"{module} not define pressure condition"); return false; } return Math.Abs(tmPressure - targetPressure) <= _maxPressureDiffOpenSlitValve; }, timeDelay * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"can not complete in {timeDelay} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetPmToTmV70(int id, bool isOpen, TM tm, string module, int timeDelay) { Tuple ret = ExecuteAndWait(id, () => { Notify($"set V70 " + (isOpen ? "Open" : "Close")); if (!PMToTm_V70.TurnValve(isOpen, out string reason)) { Stop(reason); return false; } return true; }, () => { double tmPressure = tm.ChamberPressure; double targetPressure = 0.0; if (ModuleHelper.IsPm(_paramTarget)) { targetPressure = DEVICE.GetDevice($"{module}.PT1").FeedBack; } else { Stop($"{module} not define pressure condition"); return false; } return Math.Abs(tmPressure - targetPressure) <= _maxPressureDiffOpenSlitValve; }, timeDelay * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"can not complete in {timeDelay} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetSlitValve(int id, TM tm, string module, bool isOpen, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"set slit valve {module} " + (isOpen ? "Open" : "Close")); if (!tm.SetSlitValve(ModuleHelper.Converter(module), isOpen, out string reason)) { Stop(reason); return false; } return true; }, () => { return isOpen ? tm.CheckSlitValveOpen(ModuleHelper.Converter(module)) : tm.CheckSlitValveClose(ModuleHelper.Converter(module)); }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"can not complete in {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void CheckPressureCondition(int id, TM tm, string target) { Tuple ret = Execute(id, () => { Notify($"check pressure condition to open {target} slit valve"); double tmPressure = tm.ChamberPressure; double targetPressure = 0.0; if (ModuleHelper.IsLoadLock(_paramTarget)) { targetPressure = _ll.ChamberPressure; } else if (ModuleHelper.IsPm(_paramTarget)) { targetPressure = DEVICE.GetDevice($"{target}.PT1").FeedBack; } else { Stop($"{target} not define pressure condition"); return false; } double pressureDiff = Math.Abs(tmPressure - targetPressure); if (pressureDiff > _maxPressureDiffOpenSlitValve) { Stop($"pressure difference {pressureDiff:F3} between TM and {target} exceed tolerance {_maxPressureDiffOpenSlitValve}"); return false; } return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetSlowVentValve(int id, SicTM tm, bool isOpen, int timeout) { Tuple ret = ExecuteAndWait(id, () => { string op = isOpen ? "Open" : "Close"; Notify($"{op} Slow Vent Valve"); if (!tm.SetSlowVentValve(isOpen, out string reason)) { Stop(reason); return false; } return true; }, () => { return tm.CheckSlowVentValve(isOpen); }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"Set Slow Vent Valve timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetTmMfc(int id, double flow) { Tuple ret = Execute(id, () => { Notify($"Set TM MFC flow to {flow} "); _tm.SetVentMfc(flow, out string reason); return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetConfinementRingUp(int id, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"Set Confinement RingUp"); OP.DoOperation($"{_paramTarget}.ServoUp"); return true; }, () => { if (_naisServo != null) { return _confinementRing.IsUp && _naisServo.IsStbOff; } else { return _confinementRing.IsUp; } }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"Set Confinement RingUp timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void WaitPMIdle(int id,int timeout) { Tuple ret = ExecuteAndWait(id, () => { return true; }, () => { string pm1Status= DATA.Poll($"PM1.Status") == null ? "" : DATA.Poll($"PM1.Status").ToString(); return pm1Status == "ProcessIdle" || pm1Status == "Idle"; }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"Wait PM Idle timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetConfinementRingDown(int id, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"Set Confinement RingDown"); OP.DoOperation($"{_paramTarget}.ServoDown"); return true; }, () => { return _confinementRing.IsDown; }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"Set Confinement RingDown timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void CheckConfinementIsDown(int id) { Tuple ret = Execute(id, () => { _confinementIsDown = _confinementRing.IsDown; Notify("Servo Statue is " + (_confinementIsDown ? "Down" : "Up")); return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetPostTransfer(int id,bool postTransferEnableHeat) { Tuple ret = Execute(id, () => { Notify($"Set PostTransfer"); OP.DoOperation($"{_paramTarget}.PostTransfer",new object[] { postTransferEnableHeat }); return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void SetPreTransfer(int id, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"Set PreTransfer"); OP.DoOperation($"{_paramTarget}.PreTransfer"); return true; }, () => { return _sicServo.ActualSpeedFeedback == 0; }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"Set PreTransfer timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } private void WaitTempratureBelow900(int id, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"Wait DiHeaterTempBelow900CSW"); return true; }, () => { if (_pmIoInterLock != null) { return _pmIoInterLock.DiHeaterTempBelow900CSW; } else { return true; } }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) { Stop($"Wait PM Temprature below 900 timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } private void WaitPVTempratureBelowSet(int id, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"Wait PV1Temp below{_pmPVInnerTempLimit}℃ and PV2Temp below{_pmPVMiddleTempLimit}℃ and PV3Temp below{_pmPVOuterTempLimit}℃"); return true; },() => { if (_tc1 != null && _pmPVOuterTempLimit>0 && _pmPVMiddleTempLimit>0 && _pmPVOuterTempLimit>0) { return _tc1.L1PVFeedBack < _pmPVInnerTempLimit && _tc1.L2PVFeedBack < _pmPVMiddleTempLimit && _tc1.L3PVFeedBack < _pmPVOuterTempLimit; } else { return true; } }, timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else if (ret.Item2 == Result.TIMEOUT) { Stop($"Wait PM Temprature below 900 timeout, over {timeout} seconds"); throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } } }