using System; using Aitex.Core.Equipment.SusceptorDefine; using Aitex.Core.RT.Event; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using MECF.Framework.Common.DBCore; using VirgoCommon; //using Virgo.Common; using VirgoRT.Devices; namespace VirgoRT.Modules.PMs { public enum MonitorStepState { Continue, Failed, Break, } class PMRoutineBase : ModuleRoutine { // ----------------------------Fields-------------------------- // //private SCConfigItem scOpenGasValveTimeout = null; private int dOpenGasValveTimeout = 1; //1S //private SCConfigItem scCloseGasValveTimeout = null; public int dCloseGasValveTimeout = 2; //2s //private SCConfigItem scOpenCloseSlitValveTimeout = null; protected int valveOpenCloseTimeout = 2; //2s protected int _PressureTrip1 = 80; protected bool bUINotify; protected readonly JetPM _chamber; // --------------------------Properties------------------------ // public string Display { get; set; } public string WaferID { get; set; } // Constructor protected PMRoutineBase(JetPM chamber) { this.Module = chamber.Module.ToString(); _chamber = chamber; bUINotify = true; dOpenGasValveTimeout = SC.GetValue($"{Module}.OpenGasValveTimeout"); dCloseGasValveTimeout = SC.GetValue($"{Module}.TimeLimitOfCloseGasValve"); valveOpenCloseTimeout = SC.GetValue($"{Module}.OpenCloseSlitValveTimeout"); } public Result CheckLid() { if (!_chamber.IsLidClosed) { this.Stop("Chamber 盖子必须关"); return Result.FAIL; } return Result.RUN; } protected Result CheckSlitDoor() { if (!_chamber.IsSlitDoorClosed) { Stop("传送门必须关"); return Result.FAIL; } return Result.RUN; } protected Result CheckDryPump() { if (!_chamber.IsPumpRunning) { Stop("泵没有启动"); return Result.FAIL; } if (_chamber.HasPumpError) { Stop("泵状态有错误"); return Result.FAIL; } return Result.RUN; } public void CheckThrottleValveFullOpen(int id) { bool execute() { Notify("完全打开蝶阀"); _chamber.FullOpenTV(); return true; } bool? Check1() { if (_chamber.TVPosition >= 98) { Notify("蝶阀已经完全打开"); return true; } return false; } Tuple ret = ExecuteAndWait(id, execute, Check1, 20 * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { Stop("无法打开蝶阀"); throw new RoutineFaildException(); } if (ret.Item2 == Result.TIMEOUT) { Stop("启动蝶阀超时"); throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected Result CheckCDA() { if (!_chamber.IsCDA_OK) { Stop("CDA 压力信号不正确"); return Result.FAIL; } return Result.RUN; } protected void CloseAllValve(int id, int time) { bool execute() { Notify("关闭所有的阀门"); _chamber.CloseValves(); return true; } Tuple ret = ExecuteAndWait(id, execute, () => true, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } if (ret.Item2 == Result.TIMEOUT) { throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void SetValve(int id, ValveType vlv, bool bOpen) { bool exec() { _chamber.SetValveOnOff(vlv, bOpen); Notify($"{(bOpen ? "打开" : "关闭")} {vlv} 阀"); return true; } bool? Check1() { if (vlv == ValveType.FAST_PUMP && bOpen) return _chamber.IsFastPumpOpened; else if (vlv == ValveType.FAST_PUMP && !bOpen) return !_chamber.IsFastPumpOpened; else if (vlv == ValveType.SOFT_PUMP && bOpen) return _chamber.IsSoftPumpOpened; else if (vlv == ValveType.SOFT_PUMP && !bOpen) return !_chamber.IsSoftPumpOpened; else return true; } var res = ExecuteAndWait(id, exec, Check1, 500); if (res.Item1) { throw new RoutineBreakException(); } } protected void CheckATM2(int id, bool on, int time) { bool? check() { //if (!_chamber.IsATM) //{ // Notify("ATM is OFF"); //} return on ? _chamber.IsATM : !_chamber.IsATM; } Tuple ret = ExecuteAndWait(id, () => { Notify($"等待 ATM 信号 {(on ? "ON" : "OFF")}"); return true; }, check, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL || ret.Item2 == Result.TIMEOUT) { Stop($"ATM 信号仍然 {(_chamber.IsATM ? "ON" : "OFF")}"); throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void CheckPressure(int id, int targetPressure, bool morethan, int time) { bool? Check1() { bool res = morethan ? _chamber.ChamberPressure > targetPressure : _chamber.ChamberPressure < targetPressure; if (res) { Notify($"压力已经到达 {targetPressure:N} mTorr"); } return res; } Tuple ret = ExecuteAndWait(id, () => { Notify($"等待压力{(morethan ? "上升" : "下降")} 到 {targetPressure:N} mTorr"); return true; }, Check1, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { Stop($"当前压力 [{_chamber.ChamberPressure}], 无法到达 [{targetPressure}]"); throw new RoutineFaildException(); } if (ret.Item2 == Result.TIMEOUT) { Stop($"检测压力超时, 当前压力 [{_chamber.ChamberPressure*0.001:F2}] Torr"); throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void CheckForeline(int id, uint target, int time) { bool Func() { Notify($"Check foreline pressure, 目标 {target} mTorr"); return true; } bool? Check1() { return _chamber.ForelinePressure < target; } Tuple ret = ExecuteAndWait(id, Func, Check1, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } if (ret.Item2 == Result.TIMEOUT) { Stop($"检查Foreline 压力超时, 当前Foreline 压力值 {_chamber.ForelinePressure}"); throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void CheckVAC(int id, double targetPressure, int time) { bool? Check1() { if (_chamber.ChamberPressure < targetPressure) { Notify($"Pump below [{targetPressure}]"); return true; } return false; } Tuple ret = ExecuteAndWait(id, () => true, Check1, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } if (ret.Item2 == Result.TIMEOUT) //timeout { //Warning($"Can not pump to base pressure {target} in {time} seconds"); throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void CheckVAC(int id, int time) { Tuple ret = ExecuteAndWait(id, () => true, () => _chamber.IsVAC, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { Stop("VAC真空信号 NOT ON"); throw new RoutineFaildException(); } if (Result.TIMEOUT == ret.Item2) { Stop($"VAC 真空信号超时, 当前压力 {_chamber.ChamberPressure}"); throw new RoutineFaildException(); } throw new RoutineBreakException(); } } public void SetLiftPinUpDown(int id, bool isUp, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"设置 lift pin {_chamber.Name} " + (isUp ? "升" : "降")); if (!_chamber.SetLiftPin(isUp ? MovementPosition.Up : MovementPosition.Down, out string reason)) { Stop(reason); return false; } return true; }, () => isUp ? _chamber.CheckLiftUp() : _chamber.CheckLiftDown(), timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"无法 {(isUp ? "Up" : "Down")} lift pin in {timeout} seconds"); throw new RoutineFaildException(); } else throw new RoutineBreakException(); } } protected void End(int id) { bool Func() { double duration_min = counter.GetElapseTime(); TimeSpan ts = TimeSpan.FromMilliseconds(duration_min); string info = $"完成 in {ts.Minutes} minutes {ts.Seconds} seconds"; Notify(info); //if (bUINotify) // EV.PostPopDialogMessage(EventLevel.Information, Name, $"{Module} {info} Finished"); return true; } Tuple ret = Execute(id, Func); } public virtual void Abort() { _chamber.GeneratorPowerOn(false); _chamber.GeneratorBiasPowerOn(false); _chamber.StopAllGases(); //ProcessDataRecorder.UpdateStatus(RecipeRunGuid.ToString(), SusceptorStatus.Failed.ToString(), Module); } /// /// /// /// /// 单位:秒 public void CloseValve(int stepId, float delayTime) { bool Func() { Notify("Vent End Close Vent Valve"); _chamber.SetValveOnOff(ValveType.PURGE, false); _chamber.SetValveOnOff(ValveType.FAST_VENT, false); _chamber.SetValveOnOff(ValveType.PROCESS, false); //_chamber.OpenValve(ValveType.SOFT_PUMP, true); //_chamber.OpenValve(ValveType.FAST_PUMP, true); return true; } Tuple ret = Delay(stepId, Func, delayTime * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void StartLoop(int id, string name, int count, Action notify, Action error) { bool Func() { Notify($"{name} 循环 {LoopCounter + 1}"); return true; } Tuple ret = Loop(id, Func, count); if (ret.Item1) { if (ret.Item2 == Result.FAIL) throw new RoutineFaildException(); } } protected void EndLoop(int id, Action notify, Action error) { Tuple ret = EndLoop(id, () => true); if (ret.Item1) { if (ret.Item2 == Result.FAIL) throw new RoutineFaildException(); throw new RoutineBreakException(); } } protected void CyclePump(int id, int target, int timeLimit, bool isStopPumpOnceDone) { bool Func() { Notify($"Pumping to {target} mTorr"); _chamber.SetValveOnOff(ValveType.PROCESS, false); _chamber.SetValveOnOff(ValveType.PURGE, false); _chamber.SetValveOnOff(ValveType.FAST_VENT, false); _chamber.SetValveOnOff(ValveType.FAST_PUMP, true); return true; } bool? Check1() { if (_chamber.ChamberPressure < target) { if (isStopPumpOnceDone) { _chamber.SetValveOnOff(ValveType.FAST_PUMP, false); } return true; } return true; } Tuple ret = ExecuteAndWait(id, Func, Check1, timeLimit * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } if (ret.Item2 == Result.TIMEOUT) { Stop($"Pump 压力无法到达 {target} in time {timeLimit}"); throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void CycleVent(int id, int target, int timeLimit, bool isStopVentOnceDone) { bool Func() { Notify($"Venting to {target} mTorr"); _chamber.SetValveOnOff(ValveType.FAST_PUMP, false); _chamber.SetValveOnOff(ValveType.PROCESS, true); _chamber.SetValveOnOff(ValveType.PURGE, true); return true; } bool? Check1() { if (_chamber.ChamberPressurePressure > target) { if (isStopVentOnceDone) { _chamber.SetValveOnOff(ValveType.PROCESS, false); _chamber.SetValveOnOff(ValveType.PURGE, false); _chamber.SetValveOnOff(ValveType.FAST_VENT, false); } return true; } return false; } Tuple ret = ExecuteAndWait(id, Func, Check1, timeLimit * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"Purge 压力无法到达 {target} in purge time {timeLimit}"); if (isStopVentOnceDone) { _chamber.SetValveOnOff(ValveType.PROCESS, false); _chamber.SetValveOnOff(ValveType.PURGE, false); _chamber.SetValveOnOff(ValveType.FAST_VENT, false); } throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void CheckSubstrateTemp(int id, double target, int time, double tolerance) { bool Func() { if (_chamber.SubstrateTempFB > target) { Notify($"当前温度{_chamber.SubstrateTempFB} ℃, 大于目标 {target.ToString()} ℃"); //return true; } _chamber.HeatSubstrate(target); Notify($"检查底座温度值,当前温度{_chamber.SubstrateTempFB} ℃, 目标 {target.ToString()} ℃"); return true; } bool? Check1() { if (Math.Abs( target) <= 0.1) return true; if (Math.Abs(_chamber.SubstrateTempFB - target) <= tolerance) return true; return false; } Tuple ret = ExecuteAndWait(id, Func, Check1, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } if (ret.Item2 == Result.TIMEOUT) { Stop($"检查底座温度超时, 当前底座温度值 {_chamber.SubstrateTempFB}"); throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void CheckCoolantTemp(int id, double target, double offset, int time, double tolerance) { bool Func() { if (_chamber.CoolantOutletTempFB > target) { Notify($"水冷当前温度{_chamber.CoolantOutletTempFB} ℃, 大于目标 {target.ToString()} ℃"); //return true; } _chamber.HeatChiller(target, offset); Notify($"检查水冷温度值,当前温度{_chamber.CoolantOutletTempFB} ℃, 目标 {target.ToString()} ℃"); return true; } bool? Check1() { if (!_chamber.CheckChillerStatus()) return false; return Math.Abs(_chamber.CoolantOutletTempFB - target) <= tolerance; } Tuple ret = ExecuteAndWait(id, Func, Check1, time * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } if (ret.Item2 == Result.TIMEOUT) { if (!_chamber.CheckChillerStatus()) { Stop($"Chiller not connected or in error"); } else { Stop($"检查水冷温度超时, 当前水冷温度值 {_chamber.CoolantOutletTempFB}"); } throw new RoutineFaildException(); } throw new RoutineBreakException(); } } protected void SetSlitDoor(int id, bool isOpen, int timeout) { Tuple ret = ExecuteAndWait(id, () => { Notify($"设置传送门 {_chamber.Name} " + (isOpen ? "开" : "关")); _chamber.SetSlitDoor(isOpen, out _); return true; }, () => isOpen ? _chamber.CheckSlitDoorOpen() : _chamber.CheckSlitDoorClose(), timeout * 1000); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw new RoutineFaildException(); } else if (ret.Item2 == Result.TIMEOUT) //timeout { Stop($"无法 {(isOpen ? "开" : "关")} 传送门 in {timeout} seconds"); throw new RoutineFaildException(); } else throw new RoutineBreakException(); } } } }