|
@@ -0,0 +1,386 @@
|
|
|
+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.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,
|
|
|
+ End
|
|
|
+ }
|
|
|
+ #region 内部变量
|
|
|
+ /// <summary>
|
|
|
+ /// recipe
|
|
|
+ /// </summary>
|
|
|
+ private VpwRecipe _recipe;
|
|
|
+ /// <summary>
|
|
|
+ /// 设备
|
|
|
+ /// </summary>
|
|
|
+ private VpwCellDevice _vpwCellDevice;
|
|
|
+ /// <summary>
|
|
|
+ /// Main设备
|
|
|
+ /// </summary>
|
|
|
+ private VpwMainDevice _mainDevice;
|
|
|
+ /// <summary>
|
|
|
+ /// Pump DownWarn时间
|
|
|
+ /// </summary>
|
|
|
+ private int _pumpDownWarningTime = 60000;
|
|
|
+ /// <summary>
|
|
|
+ /// Pump Down超时
|
|
|
+ /// </summary>
|
|
|
+ private int _pumpDownTimeOut = 80000;
|
|
|
+ /// <summary>
|
|
|
+ /// 开始Pump Down时间
|
|
|
+ /// </summary>
|
|
|
+ private DateTime _pumpDownTime=DateTime.MinValue;
|
|
|
+ /// <summary>
|
|
|
+ /// 是否需要重试
|
|
|
+ /// </summary>
|
|
|
+ private bool _isNeedRetry = false;
|
|
|
+ /// <summary>
|
|
|
+ /// Lid Release Pressure
|
|
|
+ /// </summary>
|
|
|
+ private int _lidReleasePressure = 730;
|
|
|
+ /// <summary>
|
|
|
+ /// Lid Release Pressure
|
|
|
+ /// </summary>
|
|
|
+ private int _lidReleasePressureTimeout = 10000;
|
|
|
+ #endregion
|
|
|
+ /// <summary>
|
|
|
+ /// 构造函数
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="module"></param>
|
|
|
+ public VpwVacuumPrewetRoutine(string module) : base(module)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 中止
|
|
|
+ /// </summary>
|
|
|
+ public void Abort()
|
|
|
+ {
|
|
|
+ Runner.Stop("Manual abort");
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 监控
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ 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)
|
|
|
+ .End(PrepareStep.End,NullFun,_delay_1ms);
|
|
|
+ return Runner.Status;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// pump valve on
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool PumpValveOn()
|
|
|
+ {
|
|
|
+ bool result = _vpwCellDevice.VacuumValveOn();
|
|
|
+ if (!result)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_VPW, "pump valve on failed", 0);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// Pump valve off
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool PumpValveOff()
|
|
|
+ {
|
|
|
+ bool result = _vpwCellDevice.VacuumValveOff();
|
|
|
+ if (!result)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_VPW, "pump valve off failed", 0);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// Pump Enable
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool PumpEnable()
|
|
|
+ {
|
|
|
+ bool result =_mainDevice.VacuumPumpEnable();
|
|
|
+ if (!result)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_VPW, "pump enable failed", 0);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _pumpDownTime = DateTime.Now;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 检验真空
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 检验Lid Release真空数值
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool CheckLidReleaseVacuum()
|
|
|
+ {
|
|
|
+ double vacuumValue = _vpwCellDevice.CommonData.VacuumPressure;
|
|
|
+ return vacuumValue >= _lidReleasePressure;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// open vent valve
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool OpenVentValve()
|
|
|
+ {
|
|
|
+ bool result = _vpwCellDevice.VentValveOn();
|
|
|
+ if (!result)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_VPW, "open vent valve failed", 0);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// close vent valve
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool CloseVentValve()
|
|
|
+ {
|
|
|
+ bool result = _vpwCellDevice.VentValveOff();
|
|
|
+ if (!result)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_VPW, "close vent valve failed", 0);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// Chamber down
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool ChamberDown()
|
|
|
+ {
|
|
|
+ bool result= _mainDevice.ChamberDown();
|
|
|
+ if (!result)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_VPW, "chamber down failed",0);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 检验Chamber是否打开
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool CheckChamberOpened()
|
|
|
+ {
|
|
|
+ return _mainDevice.CommonData.ChamberOpened && !_mainDevice.CommonData.ChamberClosed;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// Chamber up
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool ChamberUp()
|
|
|
+ {
|
|
|
+ bool result = _mainDevice.ChamberUp();
|
|
|
+ if (!result)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_VPW, "chamber up failed", 0);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 检验Chamber是否关闭
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool CheckChamberClosed()
|
|
|
+ {
|
|
|
+ return !_mainDevice.CommonData.ChamberOpened && _mainDevice.CommonData.ChamberClosed;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 检验真空
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 打开相应的cell valve
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ 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 = StartRotation();
|
|
|
+ if (!result)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_VPW, "start rotation failed", 0);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ result= count == enableCount;
|
|
|
+ if (!result)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_VPW, "open cell valve failed", 0);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 同时旋转
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private bool StartRotation()
|
|
|
+ {
|
|
|
+ int targetPosition = 0;
|
|
|
+ int maxSpeed = 0;
|
|
|
+ int second = 0;
|
|
|
+ foreach(var item in _recipe.VacuumRinseStep)
|
|
|
+ {
|
|
|
+ second += item.DurationSeconds;
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ targetPosition = maxSpeed * (second + 60 * 1000);//按最大速度*(时间+多出一分钟)
|
|
|
+ _vpwCellDevice.SetRotationSpeed(_recipe.VacuumRinseStep[0].RotationSpeed / 6);
|
|
|
+ return _vpwCellDevice.RotationProfilePosition(targetPosition);
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 启动
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="objs"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public RState Start(params object[] objs)
|
|
|
+ {
|
|
|
+ _recipe=(VpwRecipe)objs[0];
|
|
|
+ _vpwCellDevice = DEVICE.GetDevice<VpwCellDevice>(Module);
|
|
|
+ _mainDevice = DEVICE.GetDevice<VpwMainDevice>(ModuleName.VPWMain1.ToString());
|
|
|
+ _pumpDownWarningTime = SC.GetValue<int>($"{Module}.PumpDownWarningTime")*1000;
|
|
|
+ _pumpDownTimeOut = SC.GetValue<int>($"{Module}.PumpDownTimeout")*1000;
|
|
|
+ _lidReleasePressure = SC.GetValue<int>($"{Module}.LidReleasePressure");
|
|
|
+ _lidReleasePressureTimeout = SC.GetValue<int>($"{Module}.LidReleasePressureTimeout");
|
|
|
+ _isNeedRetry = false;
|
|
|
+ return Runner.Start(Module, $"{Module} prepare");
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 重试
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="step"></param>
|
|
|
+ public RState Retry(int step)
|
|
|
+ {
|
|
|
+ if (_recipe == null)
|
|
|
+ {
|
|
|
+ NotifyError(eEvent.ERR_RINSE, "recipe is null", -1);
|
|
|
+ return RState.Failed;
|
|
|
+ }
|
|
|
+ List<Enum> preStepIds = new List<Enum>();
|
|
|
+ return Runner.Retry(PrepareStep.OpenVacuumValve, preStepIds, Module, "Vacuum Prewet Retry");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|