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");
}
}
}