using Aitex.Core.RT.Device; using Aitex.Core.RT.Device.Devices; using Aitex.Core.RT.Event; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using MECF.Framework.Common.DBCore; using MECF.Framework.Common.Equipment; using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.MFCs; using SicModules.PMs.Routines.Base; using System; using System.Collections.Generic; using System.Diagnostics; namespace SicModules.PMs.Routines { public class PMLeakCheckRoutine : PMBaseRoutine { private enum RoutineStep { RotationEnable, HeatEnable, VentPumpClose, ArSupply, SetGroupA, SetGroupB, SetGroupC, SetGroupE, SetGroupF, SetGroupH, SetGroupD, SetGroupG, SetGroupK, SetMFCMode, SetPCMode, SetM1toM17, SetPC, SetGroupJ, SetM291519to38, SetGasOut, SetTv, SetGasIn1, //V68 OpenFinal1, //V91-96 SetMfcFinal1, //M32-38 SetMfc19to26, SetTVCloseMode, SetTvPositionToZero, SetGasIn2, SetGroupJOpen, SetM18toM40, SetM17M18, OpenFinal2, CloseFinal2, SetMfcFinal2, SetEPV1, SetEPV2, SetTvMode, SetTVEnable, SetTVPressMode, SetTv1, WaitTv1, Set0M18toM40, SetM18, SetTVPositionMode, SetTVPositionMode_1, SetTVPositionMax, SetTVPositionMax_1, SetTVPressMode1, SetM2TOM40Default, SetM2toM40_1, SetM18Default, SetM18_1, SetTvOpen, SetTvModeToPress, SetTVtoCurrent, RoutinePre, SetPressureUp, SetPressureDown, WaitPressureDown, WaitPressureUp, VentPumpOpen, PressureToMax, PressureToMin, StartLoop, EndLoop, SetMfc28to31, SetReactorPress, CloseFinal1, CloseFinanl2, CloseEPV2, SetTVCloseMode2, CLoseTvvvv, SetEPVVV2, CLoseEPV1, CheckPM1000, WaitPressUpTo1000, WaitPressUpTo1020, SetPressUpOrDown1, SetPressUpOrDown2, SetMfc28to40Special, WaitPmPressureUp, SetMfc28to40Default, SetV75, SetV76, SetV751, SetV761, SetPC567Close, SetPC567Mode, SetPC567Default, OpenEPV2, WaitPressUpTo20, SetMfc291519to38, WaitPressUpTo0, SetMfc291519to38ToDefault, WaitPressDownTo20, SetPmPressureTo20, CloseMfcFinal1, CloseMfcFinal2, CloseMfc2915, CheckFinal1Open, DoLeakCheck, CalcLeakCheck, SetTVClose, CloseTV, CloseV27, CloseV28, CloseV69, CloseV70, SetGroupV25, SetV31, SetV32, SetV35V36, CloseV68, SetV92V93V95, SetV94, SetV96, SetV68, SetM32M35M37, SetM36, SetM38, CloseM32M35M37, CloseM36, CloseM38, SetV103, SetV105, CloseGasIn1, SetTVCloseMode1, CLoseTV1, SetEPV2_1, SetEPV2_2, SetTVEnable_2, TimeDelay1, TimeDelay2, TimeDelay3, TimeDelay4, TimeDelay5, TimeDelay6, TimeDelay7, TimeDelay8, TimeDelay9, TimeDelay10, TimeDelay11, TimeDelay12, TimeDelay13, TimeDelay14, TimeDelay15, TimeDelay16, TimeDelay17, LoopSetTVPressMode1, LoopSetM18toM40, LoopSetTv1, LoopSet0M18toM40, LoopSetM18Default, LoopWaitTv1, LoopSetDefault_M18toM40, LoopSetTVCloseMode, LoopSetTvPositionToZero, LoopSetEPV2, LoopWaitPressureUp, LoopSetEPV2_2, LoopSet0_M18toM40, LoopSetTVEnable_1, LoopSetTVPressMode } enum LeakCheckType { ChamberOnly, ChamberAndGasline, ChamberAndGaslineToFacility, } private ModuleName moduleName; private IoThrottleValve2 _IoThrottle; private int _rotationCheckSpeed = 0; //设置旋转速度为0后检查是否转速低于此数值 private int _rotationCloseTimeout; //旋转停止超时 private int _heatTimeOut = 5; //Heat关闭等待Di反馈超时时间 private double _pressureMax; //Loop压力上限可设置600-800) private double _pressureMin; //Loop压力下限可设置 0-400) private int _pressureLoopCount; //Loop次数 private int _pressureMinDelay; private int _pressureMaxDelay; private int _pressureMinTimeout; private int _pressureMaxTimeout; private int _IoValueOpenCloseTimeout = 10; //开关阀门超时时间 private double _pmPressureMaxDiff; //蝶阀与目标压力的差值范围(认为调整到位了) private int _throttleTimeout; //蝶阀调整到指定压力的超时时间 private int _paramContinuePumpTime; private int _paramLeakCheckTime; private double _beginPressure; private double _beginTime; private int _calTimes; //第几次计算LeakCheck的值(每60秒计算一次) private double _leakSpec; private int _routineTimeOut; //private int _EPV2OpenDelayTime = 9; private bool _useSettingValue = false; private Stopwatch _swTimer = new Stopwatch(); public int ElapsedTime { get { return _swTimer.IsRunning ? (int)(_swTimer.ElapsedMilliseconds / 1000) : 0; } } public PMLeakCheckRoutine(ModuleName module, PMModule pm1) : base(module, pm1) { Module = module.ToString(); Name = "Leak Check"; _IoThrottle = DEVICE.GetDevice($"{Module}.TV"); } internal void Init(int pumpTime, int leakCheckTime) { _paramContinuePumpTime = pumpTime; _paramLeakCheckTime = leakCheckTime; _useSettingValue = true; } internal void Init() { _useSettingValue = false; } public override Result Start(params object[] objs) { Reset(); _swTimer.Restart(); _rotationCloseTimeout = SC.GetValue($"PM.{Module}.RotationCloseTimeout"); _pmPressureMaxDiff = SC.GetValue($"PM.{Module}.ThrottlePressureMaxDiff"); _throttleTimeout = SC.GetValue($"PM.{Module}.ThrottlePressureTimeout"); _rotationCloseTimeout = SC.GetValue($"PM.{Module}.RotationCloseTimeout"); _pressureLoopCount = SC.GetValue($"PM.{Module}.LeakCheck.CyclePurgeCount"); _pressureMin = SC.GetValue($"PM.{Module}.LeakCheck.PumpBasePressure"); _pressureMinDelay = SC.GetValue($"PM.{Module}.LeakCheck.PumpDelayTime"); _pressureMinTimeout = SC.GetValue($"PM.{Module}.LeakCheck.PumpTimeout"); _pressureMax = SC.GetValue($"PM.{Module}.LeakCheck.VentBasePressure"); _pressureMaxDelay = SC.GetValue($"PM.{Module}.LeakCheck.VentDelayTime"); _pressureMaxTimeout = SC.GetValue($"PM.{Module}.LeakCheck.VentTimeout"); _routineTimeOut = SC.GetValue($"PM.{Module}.LeakCheck.RoutineTimeOut"); //_EPV2OpenDelayTime = SC.GetValue($"PM.{Module}.TimeDelayAlterEPV2Open"); if (!_useSettingValue) { _paramContinuePumpTime = SC.GetValue($"PM.{Module}.LeakCheck.ContinuePumpTime"); _paramLeakCheckTime = SC.GetValue($"PM.{Module}.LeakCheck.LeakCheckDelayTime"); } _leakSpec = SC.GetValue($"PM.{Module}.LeakCheck.LeakSpec"); if (!PmDevice.SetIOValueByGroup(IoGroupName.V70, false)) { EV.PostAlarmLog(Module, "Can not close V70-1"); return Result.FAIL; } Notify($"Start LoopCount:{_pressureLoopCount}"); return Result.RUN; } public override Result Monitor() { try { CheckRoutineTimeOut(); //关闭V76,打开V75 SetIoValueByGroup((int)RoutineStep.SetV76, IoGroupName.V76, false, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetV75, IoGroupName.V75, true, _IoValueOpenCloseTimeout); //旋转停止,加热停止 SetHeatEnable((int)RoutineStep.HeatEnable, false, _heatTimeOut); SetRotationValve((int)RoutineStep.RotationEnable, _rotationCheckSpeed, false, _rotationCloseTimeout); //3、 关闭 V72(GasBox.Vent.Pump) 。 SetIoValueByGroup((int)RoutineStep.VentPumpClose, IoGroupName.VentPump, false, _IoValueOpenCloseTimeout); //4、 打开 V31(H2.Supply)、 V32(N2Supply)。 SetIoValueByGroup((int)RoutineStep.SetV31, IoGroupName.V31, true, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetV32, IoGroupName.V32, true, _IoValueOpenCloseTimeout); //5、 打开 V35(H2N2.Line1)、 V36(H2N2.Line2),关闭 B/C/E/F/H/KValves,打开 D/G Valves; 打开 J valve。 SetIoValueByGroup((int)RoutineStep.SetV35V36, IoGroupName.V35V36, true, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetGroupB, IoGroupName.B, false, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetGroupC, IoGroupName.C, false, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetGroupE, IoGroupName.E, false, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetGroupF, IoGroupName.F, false, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetGroupH, IoGroupName.H, false, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetGroupK, IoGroupName.K, false, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetGroupD, IoGroupName.D, true, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetGroupG, IoGroupName.G, true, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.SetGroupJ, IoGroupName.J, true, _IoValueOpenCloseTimeout); //6、 M1-M17 设定为 default 值,所有 PC 设定为 default 值(PC1-PC9), M18-M40(除M30\M34\M39)) MFC 3s ramp 到 default 值。 SetMfcToDefaultByGroup((int)RoutineStep.SetM1toM17, MfcGroupName.M1toM17, 0); SetPcToDefault((int)RoutineStep.SetPC, _lstPcList); SetMfcToDefaultByGroup((int)RoutineStep.SetM18toM40, MfcGroupName.M18toM40No303439, 3); //7、打开 EPV2,等待 3s, 打开 TV enable, 压力模式,伺服压力默认设定为 0mbar; SetIoValueByGroup((int)RoutineStep.SetEPV2, IoGroupName.EPV2, true, _IoValueOpenCloseTimeout); TimeDelay((int)RoutineStep.TimeDelay1, 3); SetThrottleEnableAndWait((int)RoutineStep.SetTVEnable, _IoThrottle, 5); SetThrottleToPressModeAndWait((int)RoutineStep.SetTVPressMode, _IoThrottle, 5); SetThrottleToTargetAndNoWait((int)RoutineStep.SetTv1, _IoThrottle, _pressureMin); //8、当蝶阀设定值 ramp 到 0 后,将 M18-M40(除 M30\M34\M39)) MFC 3s ramp 到 0; SetMfcByGroup((int)RoutineStep.Set0M18toM40, MfcGroupName.M18toM40No303439, 0, 3); //9、等待腔体压力到 Pump Base Pressure(可配置),蝶阀改为位置模式,开度设定 100% WaitChamberPressDownTo((int)RoutineStep.WaitTv1, _pressureMin, _pressureMinTimeout); TimeDelay((int)RoutineStep.TimeDelay8, 3); SetThrottleToPositionMode((int)RoutineStep.SetTVPositionMode, _IoThrottle, _throttleTimeout); TimeDelay((int)RoutineStep.TimeDelay11, 3); SetThrottleSetPosition((int)RoutineStep.SetTVPositionMax, _IoThrottle, 100, _throttleTimeout); TimeDelay((int)RoutineStep.TimeDelay9, 3); //循环开始 Loop((int)RoutineStep.StartLoop, _pressureLoopCount); //M18 - M40(除 M30\M34\M39)) MFC 3s ramp 到 default 值。 //关闭蝶阀, 再关闭 EPV2,等待压力达到设定值,压力达到后,打开 EPV2 //M18 - M40(除 M30\M34\M39)) MFC 5s ramp 到 0。 //打开 TV enable, 压力模式,伺服压力默认设定为 0mbar; //等待压力到达 0(可配置) SetMfcToDefaultByGroup((int)RoutineStep.LoopSetDefault_M18toM40, MfcGroupName.M18toM40No303439, 3); SetPressureUpOrDown((int)RoutineStep.SetPressUpOrDown2, PressureUpOrDown.Uping); SetThrottleToCloseMode((int)RoutineStep.LoopSetTVCloseMode, _IoThrottle, 8); SetThrottleDisable((int)RoutineStep.LoopSetTvPositionToZero, _IoThrottle, 8); SetIoValueByGroup((int)RoutineStep.LoopSetEPV2, IoGroupName.EPV2, false, _IoValueOpenCloseTimeout); WaitThrottleToPressureAndSetMfcSpecial((int)RoutineStep.LoopWaitPressureUp, _IoThrottle, _pressureMax, _pressureMaxTimeout); SetIoValueByGroup((int)RoutineStep.LoopSetEPV2_2, IoGroupName.EPV2, true, _IoValueOpenCloseTimeout); SetMfcByGroup((int)RoutineStep.LoopSet0_M18toM40, MfcGroupName.M18toM40No303439, 0, 5); SetThrottleEnableAndWait((int)RoutineStep.LoopSetTVEnable_1, _IoThrottle, 5); SetThrottleToPressModeAndWait((int)RoutineStep.LoopSetTVPressMode, _IoThrottle, 5); SetThrottleToTargetAndNoWait((int)RoutineStep.LoopSetTv1, _IoThrottle, _pressureMin); WaitChamberPressDownTo((int)RoutineStep.LoopWaitTv1, _pressureMin, _pressureMinTimeout); EndLoop((int)RoutineStep.EndLoop); //11、 依次关闭 Final valves; //先 关 闭 V93 ( ChamberPurge.Final )、 V94 ( RotationUpPurge.Final )、 V95(ConfinementRing.Final)、 V96(HeaterWF.Final); //再关闭 V87( SHPurge.Final)、 V88( OuterGas.Final)、 V89( InnerGas.Final)、 V90( MiddleGas.Final )、 V91 ( OpticPurge.Final )、 V92 ( GasRingPurge.Final )、 V97(CarryGas.Final); SetIoValueByGroup((int)RoutineStep.CloseFinal1, IoGroupName.Final1, false, _IoValueOpenCloseTimeout); SetIoValueByGroup((int)RoutineStep.CloseFinal2, IoGroupName.Final2, false, _IoValueOpenCloseTimeout); //12、延时一定时间后(参数配置), 关闭蝶阀,再关闭 EPV2, 开始测漏记录腔体压力 P1(mbar)和时间 T1,测试时间 T(秒) 结束后, 记录腔体压力 P2 和时间 T2 //计算腔体漏率 //腔体漏率 =(P2 - P1) /(T2 - T1) *60 //所得漏率与设定范围对比,小于范围,测漏成功,否则报错提示 TimeDelay((int)RoutineStep.TimeDelay15, _paramContinuePumpTime); SetThrottleToCloseMode((int)RoutineStep.SetTVCloseMode2, _IoThrottle, 8); SetThrottleDisable((int)RoutineStep.CLoseTvvvv, _IoThrottle, 8); TimeDelay((int)RoutineStep.TimeDelay16, 1); SetIoValueByGroup((int)RoutineStep.SetEPVVV2, IoGroupName.EPV2, false, _IoValueOpenCloseTimeout); //计算漏率 DoLeakCheck((int)RoutineStep.DoLeakCheck, _paramLeakCheckTime); TimeDelay((int)RoutineStep.TimeDelay17, _paramLeakCheckTime); CalcLeakCheck((int)RoutineStep.CalcLeakCheck, _paramLeakCheckTime); //CalcLeackCheckPerMinute(_paramLeakCheckTime); } catch (RoutineBreakException) { return Result.RUN; } catch (RoutineFaildException) { return Result.FAIL; } _swTimer.Stop(); return Result.DONE; } public override void Abort() { //Stop($"{Module} leak check aborted"); _swTimer.Stop(); PmDevice._ioThrottleValve.StopRamp(); PmDevice.SetMfcStopRamp(PmDevice.GetMfcListByGroupName(MfcGroupName.All)); PmDevice.SetRotationServo(0, 0); base.Abort(); } private void CheckRoutineTimeOut() { if (_routineTimeOut > 10) { if ((int)(_swTimer.ElapsedMilliseconds / 1000) > _routineTimeOut) { EV.PostAlarmLog(Module, $"Routine TimeOut! over {_routineTimeOut} s"); throw (new RoutineFaildException()); } } } public void DoLeakCheck(int id, double time) { Tuple ret = Execute(id, () => { Notify($"Keep pressure for {time} seconds"); _beginTime = _swTimer.ElapsedMilliseconds; //_beginPressure = PmDevice.ChamberPressure; _beginPressure = PmDevice._ioThrottleValve.PressureFeedback; _calTimes = 1; return true; }); if (ret.Item1) { if (ret.Item2 == Result.FAIL) { throw (new RoutineFaildException()); } else throw (new RoutineBreakException()); } } public void CalcLeackCheckPerMinute(int time) { //大于LeakCheck时间, if ((int)((_swTimer.ElapsedMilliseconds - _beginTime) / 1000) >= time) { int leakSecond = (int)((_swTimer.ElapsedMilliseconds - _beginTime) / 1000); double endPressure = PmDevice.ChamberPressure; double leakSpan = endPressure - _beginPressure; double leakRate = (endPressure - _beginPressure) / (leakSecond / 60.0); if (leakRate > _leakSpec) { LeakCheckDataRecorder.Add(time, (int)_beginPressure, (int)endPressure, leakRate, Result.FAIL.ToString(), "", Module); EV.PostInfoLog(Module, $"Leak check result: end at {DateTime.Now.ToString("HH:mm:ss")}, start: {_beginPressure:F2}mbar, end: {endPressure:F2}mbar, using {time} seconds, leak rate: {leakRate:F2}"); } else { LeakCheckDataRecorder.Add(time, (int)_beginPressure, (int)endPressure, leakRate, Result.Succeed.ToString(), "", Module); EV.PostInfoLog(Module, $"Leak check result: end at {DateTime.Now.ToString("HH:mm:ss")}, start: {_beginPressure:F2}mbar, end: {endPressure:F2}mbar, using {time} seconds, leak rate: {leakRate:F2}"); } } else { if ((int)((_swTimer.ElapsedMilliseconds - _beginTime) / 1000) >= 60 * _calTimes) { _calTimes++; int leakSecond = (int)((_swTimer.ElapsedMilliseconds - _beginTime) / 1000); double endPressure = PmDevice.ChamberPressure; double leakSpan = endPressure - _beginPressure; double leakRate = (endPressure - _beginPressure) / (leakSecond / 60.0); if (leakRate > _leakSpec) { EV.PostInfoLog(Module, $"Leak check Failed Count {_calTimes - 1}: using {leakSecond} seconds, leak rate: {leakRate:F2} ,Rate over {_leakSpec}"); throw (new RoutineFaildException()); } EV.PostInfoLog(Module, $"Leak check Count {_calTimes - 1}: using {leakSecond} seconds, leak rate: {leakRate:F2}"); } throw (new RoutineBreakException()); } } public void CalcLeakCheck(int id, int time) { Tuple ret = Execute(id, () => { //double endPressure = PmDevice.ChamberPressure; double endPressure = PmDevice._ioThrottleValve.PressureFeedback; double leakSpan = endPressure - _beginPressure; double leakRate = (endPressure - _beginPressure) / (time / 60.0); if (leakRate > _leakSpec) { LeakCheckDataRecorder.Add(time, (int)_beginPressure, (int)endPressure, leakRate, Result.FAIL.ToString(), "", Module); EV.PostInfoLog(Module, $"Leak check result: end at {DateTime.Now.ToString("HH:mm:ss")}, start: {_beginPressure:F2}mbar, end: {endPressure:F2}mbar, using {time} seconds, leak rate: {leakRate:F2}"); return false; } else { LeakCheckDataRecorder.Add(time, (int)_beginPressure, (int)endPressure, leakRate, Result.Succeed.ToString(), "", Module); EV.PostInfoLog(Module, $"Leak check result: end at {DateTime.Now.ToString("HH:mm:ss")}, start: {_beginPressure:F2}mbar, end: {endPressure:F2}mbar, using {time} seconds, leak rate: {leakRate:F2}"); return true; } }); } } }