using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.Routine; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Alarm; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.RecipeCenter; using MECF.Framework.Common.Routine; using MECF.Framework.Common.SubstrateTrackings; using PunkHPX8_Core; using PunkHPX8_RT.Devices.AXIS; using PunkHPX8_RT.Devices.VpwCell; using PunkHPX8_RT.Devices.VpwMain; using PunkHPX8_RT.Modules.VpwMain; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PunkHPX8_RT.Modules.VpwCell { public class VpwVacuumPrewetRoutine : RoutineBase, IRoutine { private enum PrepareStep { OpenVacuumValve, EnableVacuumPump, CheckVacuum, CloseVacuumValve, OpenVentValve, CheckLidReleaseVacuum, ChamberDown, CloseVentValve, ChamberUp, LastOpenVacuumValve, LastCheckVacuum, DryerHoldTime, OpenCellValve, LoopStart, LoopRun, LoopEnd, End } #region 内部变量 /// /// recipe /// private VpwRecipe _recipe; /// /// 设备 /// private VpwCellDevice _vpwCellDevice; /// /// Main设备 /// private VpwMainDevice _mainDevice; /// /// Pump DownWarn时间 /// private int _pumpDownWarningTime = 60000; /// /// Pump Down超时 /// private int _pumpDownTimeOut = 80000; /// /// 开始Pump Down时间 /// private DateTime _pumpDownTime=DateTime.MinValue; /// /// 是否需要重试 /// private bool _isNeedRetry = false; /// /// Lid Release Pressure /// private int _lidReleasePressure = 730; /// /// Lid Release Pressure /// private int _lidReleasePressureTimeout = 10000; /// /// 总时长 /// private int _totalMicrosecond = 0; /// /// 步骤 /// private int _stepIndex = 0; /// /// 启动步骤时间 /// private DateTime _startStepTime = DateTime.Now; #endregion /// /// 构造函数 /// /// public VpwVacuumPrewetRoutine(string module) : base(module) { } /// /// 中止 /// public void Abort() { Runner.Stop("Manual abort"); _mainDevice.VPWBoostPumpTarget = VPWBoostPumpTarget.Pressure; } /// /// 监控 /// /// public RState Monitor() { Runner.Run(PrepareStep.OpenVacuumValve, PumpValveOn, _delay_1ms) .Run(PrepareStep.EnableVacuumPump, PumpEnable, _delay_1ms) .Wait(PrepareStep.CheckVacuum, CheckVacuumValue, _pumpDownTimeOut + 1000) .RunIf(PrepareStep.CloseVacuumValve, _isNeedRetry, PumpValveOff, _delay_1ms) .RunIf(PrepareStep.OpenVentValve, _isNeedRetry, OpenVentValve, _delay_1ms) .WaitIf(PrepareStep.CheckLidReleaseVacuum, _isNeedRetry, CheckLidReleaseVacuum, _lidReleasePressureTimeout) .RunIf(PrepareStep.ChamberDown, _isNeedRetry, ChamberDown, CheckChamberOpened, _delay_10s) .RunIf(PrepareStep.CloseVentValve, _isNeedRetry, CloseVentValve, _delay_1ms) .RunIf(PrepareStep.ChamberUp, _isNeedRetry, ChamberUp, CheckChamberClosed, _delay_10s) .RunIf(PrepareStep.LastOpenVacuumValve, _isNeedRetry, PumpValveOn, _delay_1ms) .WaitIf(PrepareStep.LastCheckVacuum, _isNeedRetry,LastCheckVacuumValue, _pumpDownTimeOut) .Delay(PrepareStep.DryerHoldTime,_recipe.DryHoldTime*1000) .Run(PrepareStep.OpenCellValve,OpenCellValve,_delay_1ms) .LoopStart(PrepareStep.LoopStart,"Loop Step",_recipe.VacuumRinseStep.Count,NullFun,_delay_1ms) .LoopRunWithStopStatus(PrepareStep.LoopRun, CheckStepComplete, () => { return false; }, _totalMicrosecond + 60 * 1000)//总时长再延迟1分种 .LoopEnd(PrepareStep.LoopEnd,NullFun,_delay_1ms) .End(PrepareStep.End,NullFun,_delay_1ms); return Runner.Status; } /// /// pump valve on /// /// private bool PumpValveOn() { bool result = _vpwCellDevice.VacuumValveOn(); if (!result) { NotifyError(eEvent.ERR_VPW, "pump valve on failed", 0); } return result; } /// /// Pump valve off /// /// private bool PumpValveOff() { bool result = _vpwCellDevice.VacuumValveOff(); if (!result) { NotifyError(eEvent.ERR_VPW, "pump valve off failed", 0); } return result; } /// /// Pump Enable /// /// private bool PumpEnable() { bool result =_mainDevice.VacuumPumpEnable(); if (!result) { NotifyError(eEvent.ERR_VPW, "pump enable failed", 0); } else { _pumpDownTime = DateTime.Now; } return result; } /// /// 检验真空 /// /// private bool CheckVacuumValue() { double vacuumValue = _vpwCellDevice.CommonData.VacuumPressure; if (vacuumValue >= _recipe.VacuumTarget) { return true; } if (DateTime.Now.Subtract(_pumpDownTime).TotalMilliseconds >= _pumpDownWarningTime) { AlarmListManager.Instance.AddWarn(Module, "vacuum value", $"vacuum value {vacuumValue} is less than {_recipe.VacuumTarget}"); } if (DateTime.Now.Subtract(_pumpDownTime).TotalMilliseconds >= _pumpDownTimeOut) { _isNeedRetry = true; } return false; } /// /// 检验Lid Release真空数值 /// /// private bool CheckLidReleaseVacuum() { double vacuumValue = _vpwCellDevice.CommonData.VacuumPressure; return vacuumValue >= _lidReleasePressure; } /// /// open vent valve /// /// private bool OpenVentValve() { bool result = _vpwCellDevice.VentValveOn(); if (!result) { NotifyError(eEvent.ERR_VPW, "open vent valve failed", 0); } return result; } /// /// close vent valve /// /// private bool CloseVentValve() { bool result = _vpwCellDevice.VentValveOff(); if (!result) { NotifyError(eEvent.ERR_VPW, "close vent valve failed", 0); } return result; } /// /// Chamber down /// /// private bool ChamberDown() { bool result= _mainDevice.ChamberDown(); if (!result) { NotifyError(eEvent.ERR_VPW, "chamber down failed",0); } return result; } /// /// 检验Chamber是否打开 /// /// private bool CheckChamberOpened() { return !_mainDevice.CommonData.ChamberOpened && _mainDevice.CommonData.ChamberClosed; } /// /// Chamber up /// /// private bool ChamberUp() { bool result = _mainDevice.ChamberUp(); if (!result) { NotifyError(eEvent.ERR_VPW, "chamber up failed", 0); } return result; } /// /// 检验Chamber是否关闭 /// /// private bool CheckChamberClosed() { return _mainDevice.CommonData.ChamberOpened && !_mainDevice.CommonData.ChamberClosed; } /// /// 检验真空 /// /// private bool LastCheckVacuumValue() { double vacuumValue = _vpwCellDevice.CommonData.VacuumPressure; if (vacuumValue >= _recipe.VacuumTarget) { return true; } if (DateTime.Now.Subtract(_pumpDownTime).TotalMilliseconds >= _pumpDownWarningTime) { AlarmListManager.Instance.AddWarn(Module, "vacuum value", $"vacuum value {vacuumValue} is less than {_recipe.VacuumTarget}"); } return false; } /// /// 打开相应的cell valve /// /// private bool OpenCellValve() { int count = 0; int enableCount = 0; if (_recipe.VacuumPrewetDripEnable) { count += _vpwCellDevice.FlowDripOn()?1:0; enableCount++; } if (_recipe.VacuumPrewetLargeEnable) { count += _vpwCellDevice.FlowLargeOn() ? 1 : 0; enableCount++; } if (_recipe.VacuumPrewetSmallEnable) { count += _vpwCellDevice.FlowSmallOn() ? 1 : 0; enableCount++; } bool result= count == enableCount; if (!result) { NotifyError(eEvent.ERR_VPW, "open cell valve failed", 0); } //boost pump _mainDevice.VPWBoostPumpTarget = VPWBoostPumpTarget.CellFlow; _mainDevice.BoostTargetFlow = _recipe.VacuumPrewetFlowSetPoint; _mainDevice.CommonData.BoosterPumpSpeedAuto = true; _mainDevice.CellFlow = _vpwCellDevice.CommonData.DiwFlow; if (!_mainDevice.BoosterPumpSpeed()) { NotifyError(eEvent.ERR_VPW, "boost pump speed failed", 0); return false; } if (!_mainDevice.BoosterPumpEnableOperation("",null)) { NotifyError(eEvent.ERR_VPW, "pump enable error",0); return false; } _mainDevice.CommonData.BoosterPumpStatusContent = "Auto:On"; result = StartRotation(); if (!result) { NotifyError(eEvent.ERR_VPW, "start rotation failed", 0); return false; } _startStepTime = DateTime.Now; _stepIndex = 0; return result; } /// /// 同时旋转 /// /// private bool StartRotation() { int targetPosition = 0; int maxSpeed = 0; int second = 0; foreach(var item in _recipe.VacuumRinseStep) { second += item.DurationSeconds; _totalMicrosecond += second * 1000; int speed = item.RotationSpeed; if (maxSpeed < speed) { maxSpeed = speed; } } foreach(var item in _recipe.VentRinseStep) { second += item.DurationSeconds; int speed = item.RotationSpeed; if (maxSpeed < speed) { maxSpeed = speed; } } foreach(var item in _recipe.ExtendCleanRinseStep) { second += item.DurationSeconds; int speed = item.RotationSpeed; if (maxSpeed < speed) { maxSpeed = speed; } } second += _recipe.SpinTime; if (maxSpeed < _recipe.SpinSpeed) { maxSpeed= _recipe.SpinSpeed; } targetPosition = maxSpeed * (second + 60);//按最大速度*(时间+多出一分钟) _vpwCellDevice.SetRotationSpeed(_recipe.VacuumRinseStep[0].RotationSpeed * 6); return _vpwCellDevice.RotationProfilePosition(targetPosition); } /// /// 检验步骤是否完成 /// /// private bool CheckStepComplete() { _mainDevice.CellFlow = _vpwCellDevice.CommonData.DiwFlow; if (_stepIndex >= _recipe.VacuumRinseStep.Count) { LOG.WriteLog(eEvent.INFO_METAL, Module, $"vacuum step {_stepIndex} is over step count {_recipe.VacuumRinseStep.Count}"); return true; } int length = _recipe.VacuumRinseStep[_stepIndex].DurationSeconds; if (DateTime.Now.Subtract(_startStepTime).TotalSeconds >= length) { _stepIndex++; _startStepTime = DateTime.Now; if (_stepIndex >= _recipe.VacuumRinseStep.Count) { LOG.WriteLog(eEvent.INFO_METAL, Module, $"vaccum step {_stepIndex} is over step count {_recipe.VacuumRinseStep.Count}"); return true; } bool result = _vpwCellDevice.ChangeRotationSpeed(_recipe.VacuumRinseStep[_stepIndex].RotationSpeed*6); if (result) { LOG.WriteLog(eEvent.INFO_METAL, Module, $"vacuum step {_stepIndex} complete"); } return result; } int firstDelay = SC.GetValue($"{Module}.FlowCheckDelay") * 1000; if (DateTime.Now.Subtract(_startStepTime).TotalMilliseconds >= firstDelay) { bool abnormal = CheckDisable(); if (abnormal) { return false; } } return false; } /// /// 检验数据 /// /// private bool CheckDisable() { double flow = _vpwCellDevice.CommonData.DiwFlow; double lowError = _recipe.VacuumPrewetFlowSetPoint * (1 - (double)_recipe.VacuumPrewetFlowErrorPercent / 100); double upError = _recipe.VacuumPrewetFlowSetPoint * (1 + (double)_recipe.VacuumPrewetFlowErrorPercent / 100); double lowWarn = _recipe.VacuumPrewetFlowSetPoint * (1 - (double)_recipe.VacuumPrewetFlowWarningPercent / 100); double upWarn = _recipe.VacuumPrewetFlowSetPoint * (1 + (double)_recipe.VacuumPrewetFlowWarningPercent / 100); if (flow upError) { NotifyError(eEvent.ERR_VPW, $"{Module} cell flow {flow} is up than {upError} ", 0); Abort(); return true; } if ((flow <= upError && flow >= upWarn) || (flow >= lowError && flow <= lowWarn)) { string str = $"{Module} cell flow {flow} is in warning"; if (AlarmListManager.Instance.AddWarn(Module, $"{Module} cell flow", str)) { LOG.WriteLog(eEvent.WARN_VPW, Module, str); } } bool isSimulatorMode = SC.GetValue("System.IsSimulatorMode"); if (!isSimulatorMode) { if (!_vpwCellDevice.CheckRotationRunning()) { NotifyError(eEvent.ERR_VPW, $"{Module} rotation is stopped", 0); Abort(); return true; } } return false; } /// /// 启动 /// /// /// public RState Start(params object[] objs) { _recipe=(VpwRecipe)objs[0]; _vpwCellDevice = DEVICE.GetDevice(Module); _mainDevice = DEVICE.GetDevice(ModuleName.VPWMain1.ToString()); _pumpDownWarningTime = SC.GetValue($"{Module}.PumpDownWarningTime")*1000; _pumpDownTimeOut = SC.GetValue($"{Module}.PumpDownTimeout")*1000; _lidReleasePressure = SC.GetValue($"{Module}.LidReleasePressure"); _lidReleasePressureTimeout = SC.GetValue($"{Module}.LidReleasePressureTimeout"); _isNeedRetry = false; _totalMicrosecond = 0; _stepIndex = 0; return Runner.Start(Module, $"{Module} vacuum prewet"); } /// /// 重试 /// /// public RState Retry(int step) { if (_recipe == null) { NotifyError(eEvent.ERR_VPW, "recipe is null", -1); return RState.Failed; } List preStepIds = new List(); return Runner.Retry(PrepareStep.OpenVacuumValve, preStepIds, Module, "Vacuum Prewet Retry"); } } }