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 CyberX8_Core;
using CyberX8_RT.Devices.AXIS;
using CyberX8_RT.Devices.Facilities;
using CyberX8_RT.Devices.SRD;
using MECF.Framework.Common.Beckhoff.AxisProvider;
using MECF.Framework.Common.RecipeCenter;
using MECF.Framework.Common.Routine;
using MECF.Framework.Common.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
using static CyberX8_RT.Modules.SRD.RunWaferRecipeStateMachine;
namespace CyberX8_RT.Modules.SRD
{
public class SRDRunWaferRecipeRoutine : RoutineBase, IRoutine
{
private enum RunStep
{
RunWafer_Start,
RunWafer_CheckFacilities,
RunWafer_PreparingExhaustOff,
RunWafer_WaitExhaustOff,
RunWafer_EngageChuckVacuum,
RunWafer_CheckVacuum,
RunWafer_CloseTheDoor,
RunWafer_CheckDoorClosed,
RunWafer_ArmToHome,
RunWafer_Diverting_CheckArmHome,
RunWafer_Diverting_CheckOtherSRD,
RunWafer_Diverting_WaterOn,
RunWafer_Diverting_WithFlowCheck,
RunWafer_Diverting_WaterAboveOff,
RunWafer_Washing_ArmToCenter,
RunWafer_Washing_CheckArmCenter,
RunWafer_Washing_PoolingFrontSide,
RunWafer_Washing_PoolingWithFlowCheck,
RunWafer_Washing_StartRotation,
RunWafer_Washing_PreFlowCheck,
RunWafer_Washing_Finished,
RunWafer_Drying_PreN2Time,
RunWafer_Drying_ExhaustFanDelay,
RunWafer_Drying_ExhaustFanOn,
RunWafer_Drying_N2On,
RunWafer_Drying_StopRotation,
RunWafer_Drying_PreWaferPresenceCheck,
RunWafer_Drying_RotationStartMotion,
RunWafer_Drying_WaferPresenceCheck,
RunWafer_Drying_PostN2Time,
RunWafer_Drying_CheckRotationFinished,
RunWafer_CheckArmHome,
End
}
#region 常量
private const int MAX_ARM_HOME_RETRIES = 3;
///
/// 旋转增加时长
///
private const int ROTATION_PLUS_TIME = 10;
///
/// ROTATION电机转速比例
///
private const int SPEED_RATIO = 10;
#endregion
#region 内部变量
///
/// Arm Axis
///
private JetAxisBase _armAxis;
///
/// Rotation Axis
///
private JetAxisBase _rotationAxis;
///
/// SRD Common
///
private SrdCommonDevice _srdCommon;
///
/// Total SRD
///
private TotalSRDDevice _totalSRDDevice;
///
/// 另外SRD实例
///
private SRDEntity _otherSrdEntity;
///
/// Loader Common
///
private SystemFacilities _systemFacilities;
///
/// Arm重试次数
///
private int _armRetryTimes = 0;
///
/// Recipe
///
private SrdRecipe _srdRecipe;
///
/// 记时
///
private int _enterTime;
///
/// Diverting Flow时长
///
private int _divertingFlowCheckTimeSpan;
///
/// Pooling Flow时长
///
private int _poolingFlowCheckTimeSpan;
///
/// Washing Flow时长
///
private int _washingFlowCheckTimeSpan;
///
/// SRD rotation Provider对象
///
private BeckhoffProviderAxis _rotationProviderAxis;
///
/// SRD arm Provider对象
///
private BeckhoffProviderAxis _armProviderAxis;
///
/// 转换增加的时间
///
private int _rotationPlusSecond = ROTATION_PLUS_TIME;
///
/// N2 Enabled
///
private bool _n2Enabled = false;
///
/// Dry速度
///
private int _drySpeed;
///
/// Wafer Presence Accel/Decel比例
///
private int _waferPresenceCheckAccelDecelPercentage;
///
/// Wafer Presence Speed
///
private int _waferPresenceSpeedInRPMs;
///
/// Wafer Presence distance
///
private int _waferPresenceDistance;
///
/// 状态机进入时间
///
private int _startTime;
///
/// Wafer Presence Test功能是否启用
///
private bool _presenceTestEnabled;
///
/// Rinse时间=Max(FrontRinseTime, BackRinseTime) 单位s
///
private double _rinseTime;
///
/// Rinse中另一个水阀开关状态
///
private bool _isAnotherWaterOn;
///
/// exhaust进入时间
///
private int _exhaustFanTime;
///
/// 是否正在用水
///
private bool _isUsingWater;
///
/// Presence Test Flag
///
private bool _presenceTestFlag = false;
#endregion
#region 属性
///
/// 是否正在用水
///
public bool IsUsingWater { get { return _isUsingWater; } }
#endregion
///
/// 构造函数
///
///
public SRDRunWaferRecipeRoutine(string module) : base(module)
{
}
///
/// 中止
///
public void Abort()
{
Runner.Stop("SRD RunWaferRecipe Abort");
}
///
/// 监控
///
///
public RState Monitor()
{
Runner.RunIf(RunStep.RunWafer_Start, !_presenceTestFlag, RunWaferStartCheckStatus, _delay_1ms)
.RunIf(RunStep.RunWafer_CheckFacilities, !_presenceTestFlag, CheckFacilities, _delay_1ms)
.RunIf(RunStep.RunWafer_PreparingExhaustOff, !_presenceTestFlag, PreparingExhaustOff, _delay_1ms)
.WaitWithStopConditionIf(RunStep.RunWafer_WaitExhaustOff, !_presenceTestFlag, PreparingExhaustOffEndStatus, PreparingExhaustOffStopStatus, _delay_5s)
.RunIf(RunStep.RunWafer_EngageChuckVacuum, !_presenceTestFlag, EngageChuckVacuum, _delay_1ms)
.WaitWithStopConditionIf(RunStep.RunWafer_CheckVacuum, !_presenceTestFlag, CheckChuckVacuumEndStatus, CheckChuckVacuumStopStatus, _delay_5s)
.RunIf(RunStep.RunWafer_CloseTheDoor, !_presenceTestFlag, CloseDoor, _delay_1ms)
.WaitWithStopConditionIf(RunStep.RunWafer_CheckDoorClosed, !_presenceTestFlag, CheckDoorClosedEndStatus, CheckDoorClosedStopStatus, _delay_5s)
.RunIf(RunStep.RunWafer_ArmToHome, !_presenceTestFlag, ArmToHome, _delay_1ms)
.WaitWithStopConditionIf(RunStep.RunWafer_CheckArmHome, !_presenceTestFlag, CheckArmEndStatus,CheckArmStopStatus)
.WaitIf(RunStep.RunWafer_Diverting_CheckOtherSRD, !_presenceTestFlag, CheckOtherSRD,_delay_60s)
.RunIf(RunStep.RunWafer_Diverting_WaterOn, !_presenceTestFlag, WaterOn,_delay_1ms)
.WaitWithStopConditionIf(RunStep.RunWafer_Diverting_WithFlowCheck, !_presenceTestFlag, CheckFlowEndStatus,CheckFlowStopStatus)
.RunIf(RunStep.RunWafer_Diverting_WaterAboveOff, !_presenceTestFlag, WaterAboveOff,_delay_1ms)
.RunIf(RunStep.RunWafer_Washing_ArmToCenter, !_presenceTestFlag, ArmToCenter, _delay_1ms)
.WaitWithStopConditionIf(RunStep.RunWafer_Washing_CheckArmCenter, !_presenceTestFlag, CheckArmToCenterEndStatus,CheckArmToCenterStopStatus,_delay_60s)
.RunIf(RunStep.RunWafer_Washing_PoolingFrontSide, !_presenceTestFlag, PoolingFrontSideWaterOn,_delay_1ms)
.WaitWithStopConditionIf(RunStep.RunWafer_Washing_PoolingWithFlowCheck, !_presenceTestFlag, PoolingCheckFlowEndStatus,PoolingCheckFlowStopStatus)
.RunIf(RunStep.RunWafer_Washing_StartRotation, !_presenceTestFlag, StartRotation,_delay_1ms)
.WaitWithStopConditionIf(RunStep.RunWafer_Washing_PreFlowCheck, !_presenceTestFlag, WashingPreFlowCheckEndStatus,WashingPreFlowCheckStopStatus)
.RunIf(RunStep.RunWafer_Washing_Finished, !_presenceTestFlag, WashingFinished,_delay_1ms)
.WaitWithStopConditionIf(RunStep.RunWafer_Drying_PreN2Time, !_presenceTestFlag, CheckArmMotionEndStatus,CheckArmMotionStopStatus)
.DelayIf(RunStep.RunWafer_Drying_ExhaustFanDelay, !_presenceTestFlag, _srdRecipe.ExhaustFanDelay*1000)
.RunIf(RunStep.RunWafer_Drying_ExhaustFanOn, !_presenceTestFlag, ExhaustFanOn,_delay_1ms)
.DelayIf(RunStep.RunWafer_Drying_N2On, !_presenceTestFlag, _srdRecipe.BackN2DryTime*1000)
.RunIf(RunStep.RunWafer_Drying_StopRotation, !_presenceTestFlag, StopRotation,_delay_1ms)
//5s检验Rotation是否停止
.Wait(RunStep.RunWafer_Drying_PreWaferPresenceCheck, CheckRotationStopEndStatus,_delay_5s)
//Rotation开始运动至指定角度
.Run(RunStep.RunWafer_Drying_RotationStartMotion,RotationMotion,_delay_1ms)
//Rotation过程中Wafer Presence check
.WaitWithStopCondition(RunStep.RunWafer_Drying_WaferPresenceCheck,RotationMotionEndStatus,RotationMotionStopStatus)
//Rotation重新Home
.Run(RunStep.RunWafer_Drying_PostN2Time,PostN2Time,_delay_1ms)
//检验Rotation Home状态
.WaitWithStopCondition(RunStep.RunWafer_Drying_CheckRotationFinished,CheckRotationHomedThenExhaust,CheckRotationHomedStopStatus)
.Run(RunStep.RunWafer_CheckArmHome, LastCheckArmHomed,_delay_1ms)
.End(RunStep.End, NullFun, _delay_1ms);
return Runner.Status;
}
///
/// 启动
///
///
///
private bool RunWaferStartCheckStatus()
{
_startTime = Environment.TickCount;
return true;
}
///
/// 检查Facilities
///
///
///
private bool CheckFacilities()
{
if (_srdCommon.CommonData.FluidContainment)
{
NotifyError(eEvent.ERR_SRD, "Fluid Containment sensor is On", 0);
return false;
}
if (!_systemFacilities.LoaderDiEnable)
{
NotifyError(eEvent.ERR_SRD, "Load DI Is Disable",0);
return false;
}
return true;
}
///
/// 关闭Exhaust风机
///
///
///
private bool PreparingExhaustOff()
{
bool result = _srdCommon.ExhaustOffAction("", null);
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Preparing Exhaust Off is failed", 0);
return false;
}
return true;
}
///
/// 检验关闭Exhaust风机结束状态
///
///
private bool PreparingExhaustOffEndStatus()
{
return !_srdCommon.CommonData.ExhaustOn;
}
///
/// 检验关闭Exhaust风机停止状态
///
///
private bool PreparingExhaustOffStopStatus()
{
//if (_srdCommon.Status == RState.Failed || _srdCommon.Status == RState.Timeout)
//{
// NotifyError(eEvent.ERR_SRD, "Waiting Exhaust Off is failed");
// return true;
//}
return false;
}
///
/// Chuck Vacuum
///
///
///
private bool EngageChuckVacuum()
{
if (_srdCommon.IsWaferPresence)
{
bool result = _srdCommon.ChuckVacuumOnAction("", null);
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Chuck Vacuum On Action is failed",0);
}
return result;
}
else
{
LOG.WriteLog(eEvent.INFO_SRD, Module, "EngageChuckVacuum has been ignored");
return true;
}
}
///
/// 检验ChuckVacuum结束状态
///
///
private bool CheckChuckVacuumEndStatus()
{
if (_srdCommon.IsWaferPresence)
{
return _srdCommon.Status == RState.End && !_srdCommon.CommonData.ChuckVacuum;
}
else
{
LOG.WriteLog(eEvent.INFO_SRD, Module, "CheckVacuum has been ignored");
return true;
}
}
///
/// 检验ChuckVacuum停止状态
///
///
private bool CheckChuckVacuumStopStatus()
{
if (_srdCommon.IsWaferPresence)
{
if (_srdCommon.Status == RState.Failed || _srdCommon.Status == RState.Timeout)
{
NotifyError(eEvent.ERR_SRD, "Check Vacuum is failed", 0);
return true;
}
return false;
}
else
{
return false;
}
}
///
/// Close Door
///
///
///
private bool CloseDoor()
{
if (_srdCommon.CommonData.DoorOpened)
{
bool result = _srdCommon.DoorCloseAction("", null);
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Door Close Action is failed",0);
return result;
}
}
return true;
}
///
/// 检验DoorClosed结束状态
///
///
///
private bool CheckDoorClosedEndStatus()
{
return _srdCommon.Status == RState.End && _srdCommon.CommonData.DoorClosed;
}
///
/// 检验DoorClosed结束状态
///
///
///
private bool CheckDoorClosedStopStatus()
{
if (_srdCommon.Status == RState.Failed || _srdCommon.Status == RState.Timeout)
{
NotifyError(eEvent.ERR_SRD, "Check Door Closed is failed", 0);
return true;
}
return false;
}
///
/// Arm To Home
///
///
private bool ArmToHome()
{
_armAxis.Home(false);
return true;
}
///
/// 检验Arm home结束状态
///
///
private bool CheckArmEndStatus()
{
if (_armAxis.IsHomed && _armAxis.Status == RState.End)
{
_armRetryTimes = 0;
return true;
}
return false;
}
///
/// 检验Arm停止状态
///
///
private bool CheckArmStopStatus()
{
if (_armAxis.Status == RState.Failed || _armAxis.Status == RState.Timeout)
{
if (_armRetryTimes < MAX_ARM_HOME_RETRIES)
{
_armAxis.Home(false);
_armRetryTimes++;
}
else
{
NotifyError(eEvent.ERR_SRD, $"Arm Home Retry Home {_armRetryTimes + 1} times is over {MAX_ARM_HOME_RETRIES}",0);
return true;
}
}
return false;
}
///
/// 检验另外一个SRD是否在用水
///
///
///
private bool CheckOtherSRD()
{
return (_otherSrdEntity == null || !_otherSrdEntity.IsUsingWater);
}
///
/// 打开Above water
///
///
///
private bool WaterOn()
{
if (_srdRecipe.FrontDivertTime > 0)
{
if (_srdRecipe.FrontDivertTime > _srdRecipe.DivertPlusPoolDelay)
{
_divertingFlowCheckTimeSpan = _srdRecipe.DivertPlusPoolDelay * 1000;
}
else
{
_divertingFlowCheckTimeSpan = _srdRecipe.FrontDivertTime * 1000;
}
if (!_srdCommon.CommonData.WaterAbove)
{
bool result = _srdCommon.WaterAboveOn();
if (result)
{
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Above On");
_isUsingWater = true;
_enterTime = Environment.TickCount;
}
else
{
NotifyError(eEvent.ERR_SRD, "Water Above On is failed", 0);
}
return result;
}
return true;
}
else
{
if (_srdCommon.CommonData.WaterAbove)
{
bool result = _srdCommon.WaterAboveOff();
if (result)
{
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Above Off");
_isUsingWater = false;
_enterTime = Environment.TickCount;
}
else
{
NotifyError(eEvent.ERR_SRD, "Water Above Off is failed", 0);
}
return result;
}
return true;
}
}
///
/// 检验流量结束状态
///
///
private bool CheckFlowEndStatus()
{
if (_srdRecipe.FrontDivertTime == 0)
{
return true;
}
int ticks = Environment.TickCount - _enterTime;
if (ticks >= _srdRecipe.FrontDivertTime * 1000)
{
return true;
}
return false;
}
///
/// 检验水压
///
///
///
private bool CheckFlowStopStatus()
{
int ticks = Environment.TickCount - _enterTime;
if (ticks <= _divertingFlowCheckTimeSpan)
{
if (_totalSRDDevice.WaterPressure > _srdRecipe.MaxDivertPlusPoolPressure)
{
NotifyError(eEvent.ERR_SRD, $"Water Pressure {_totalSRDDevice} is over {_srdRecipe.MaxDivertPlusPoolPressure}",0);
return true;
}
}
return false;
}
///
/// WaterAbove Off
///
///
private bool WaterAboveOff()
{
if (_srdCommon.CommonData.WaterAbove)
{
bool result = _srdCommon.WaterAboveOff();
_isUsingWater = false;
if (result)
{
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Above off");
}
else
{
NotifyError(eEvent.ERR_SRD, "Water Above On is failed", 0);
}
return result;
}
return true;
}
///
/// Arm运动至Center
///
///
///
private bool ArmToCenter()
{
bool result = _armAxis.PositionStation("Center");
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Arm to Center is failed", 0);
}
return result;
}
///
/// check Arm是否运动至Center
///
///
///
private bool CheckArmToCenterEndStatus()
{
return _armAxis.Status == RState.End;
}
///
/// check Arm是否运动至Center停止状态
///
///
private bool CheckArmToCenterStopStatus()
{
if (_armAxis.Status == RState.Failed||_armAxis.Status==RState.Timeout)
{
NotifyError(eEvent.ERR_SRD, "Check Arm to Center is failed", 0);
return true;
}
return false;
}
///
/// 打开Above water
///
///
///
private bool PoolingFrontSideWaterOn()
{
if (_srdRecipe.FrontPoolTime > 0)
{
if (_srdRecipe.FrontPoolTime > _srdRecipe.DivertPlusPoolDelay)
{
_poolingFlowCheckTimeSpan = _srdRecipe.DivertPlusPoolDelay * 1000;
}
else
{
_poolingFlowCheckTimeSpan = _srdRecipe.FrontDivertTime * 1000;
}
if (!_srdCommon.CommonData.WaterAbove)
{
bool result = _srdCommon.WaterAboveOn();
if (result)
{
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Above On");
_enterTime = Environment.TickCount;
_isUsingWater = true;
}
else
{
NotifyError(eEvent.ERR_SRD, "Water Above On is failed",0);
}
return result;
}
return true;
}
else
{
return true;
}
}
///
/// 检验Pooling流量结束状态
///
///
private bool PoolingCheckFlowEndStatus()
{
if (_srdRecipe.FrontPoolTime == 0)
{
return true;
}
int ticks = Environment.TickCount - _enterTime;
if (ticks >= _srdRecipe.FrontPoolTime * 1000)
{
return true;
}
return false;
}
///
/// 检验Pooling流量停止状态
///
///
///
private bool PoolingCheckFlowStopStatus()
{
int ticks = Environment.TickCount - _enterTime;
if (ticks <= _poolingFlowCheckTimeSpan)
{
if (_totalSRDDevice.WaterPressure > _srdRecipe.MaxWashPressure)
{
NotifyError(eEvent.ERR_SRD, $"Water Pressure {_totalSRDDevice.WaterPressure} is over {_srdRecipe.MaxWashPressure}", 0);
return true;
}
if (_totalSRDDevice.WaterPressure < _srdRecipe.MinWaterPressure)
{
NotifyError(eEvent.ERR_SRD, $"Water Pressure {_totalSRDDevice.WaterPressure} is less {_srdRecipe.MinWaterPressure}",0);
return true;
}
}
return false;
}
///
/// 开始旋转
///
///
///
private bool StartRotation()
{
if (_srdCommon.CommonData.DoorOpened)
{
NotifyError(eEvent.ERR_SRD, "Door is not closed. Can't do rotation", 0);
return false;
}
double _scale = _rotationProviderAxis.ScaleFactor;
bool above = _srdRecipe.FrontRinseTime > _srdRecipe.BackRinseTime;
int timespan = above ? _srdRecipe.FrontRinseTime : _srdRecipe.BackRinseTime;
//rinse 目标位置
double rinsePosition = timespan * BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.RinseSpeed);
//dry目标位置
double dryPosition = BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.DrySpeed) * _srdRecipe.BackN2DryTime;
//为了让 rotation 不停止,增加了旋转时间(覆盖Arm运动时间)
double plusPosition = BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.DrySpeed) * _rotationPlusSecond;
int targetPosition = (int)Math.Round((rinsePosition + dryPosition + plusPosition) * _scale, 0);
int rotationSpeed = (int)Math.Round(_scale * BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.RinseSpeed), 0);
_drySpeed = (int)Math.Round(_scale * BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_srdRecipe.DrySpeed * SPEED_RATIO), 0);
bool result = _rotationAxis.ProfilePosition(targetPosition, rotationSpeed * SPEED_RATIO, 0, 0);
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Start Rotation is failed",0);
return false;
}
LOG.WriteLog(eEvent.INFO_SRD, Module, "Start Rotation");
//如果BackRinseTime大,则先开WaterBelow后开WaterAbove
if (_srdRecipe.BackRinseTime > _srdRecipe.FrontRinseTime)
{
_rinseTime = _srdRecipe.BackRinseTime;
//关闭WaterAbove
if (_srdCommon.CommonData.WaterAbove)
{
if (!_srdCommon.WaterAboveOff())
{
NotifyError(eEvent.ERR_SRD, "Water Above Off is failed", 0);
return false;
}
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Above Off");
}
//打开WaterBelow
if (!_srdCommon.CommonData.WaterBelow)
{
if (!_srdCommon.WaterBelowOn())
{
NotifyError(eEvent.ERR_SRD, "Water Below On is failed",0);
return false;
}
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Below On");
}
//Rinse开始时间
_enterTime = Environment.TickCount;
//另一个水阀状态变为未开(即WaterAbove)
_isAnotherWaterOn = false;
//计算水压检测滞后时间
if (_srdRecipe.BackRinseTime > _srdRecipe.FlowCheckDelay)
{
_washingFlowCheckTimeSpan = _srdRecipe.FlowCheckDelay * 1000;
}
else
{
_washingFlowCheckTimeSpan = _srdRecipe.BackRinseTime * 1000;
}
return true;
}
else
{
_rinseTime = _srdRecipe.FrontRinseTime;
//如果FrontRinseTime大,则先开WaterAbove后开WaterBelow
//打开WaterAbove
if (!_srdCommon.CommonData.WaterAbove)
{
if (!_srdCommon.WaterAboveOn())
{
NotifyError(eEvent.ERR_SRD, "Water Above Off is failed", 0);
return false;
}
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Above On");
}
//关闭WaterBelow
if (_srdCommon.CommonData.WaterBelow)
{
//打开WaterBelow
if (!_srdCommon.WaterBelowOff())
{
NotifyError(eEvent.ERR_SRD, "Water Below On is failed",0);
return false;
}
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Below Off");
}
//另一个水阀状态变为未开(即WaterBelow)
_isAnotherWaterOn = false;
//Rinse开始时间
_enterTime = Environment.TickCount;
//计算水压检测滞后时间
if (_srdRecipe.FrontRinseTime > _srdRecipe.FlowCheckDelay)
{
_washingFlowCheckTimeSpan = _srdRecipe.FlowCheckDelay * 1000;
}
else
{
_washingFlowCheckTimeSpan = _srdRecipe.BackRinseTime * 1000;
}
return true;
}
}
///
/// Washing PreFlow 流量结束状态
///
///
///
private bool WashingPreFlowCheckEndStatus()
{
int ticks = Environment.TickCount - _enterTime;
if (ticks >= _rinseTime * 1000)
{
//达到RinseTime完成Wash
return true;
}
return false;
}
///
/// Washing PreFlow 流量停止状态
///
///
private bool WashingPreFlowCheckStopStatus()
{
int ticks = Environment.TickCount - _enterTime;
//打开另一个未开的水阀
if (!_isAnotherWaterOn)
{
//延迟abs(BackRinseTime - FrontRinseTime)秒打开另一个水阀
if (_srdRecipe.BackRinseTime > _srdRecipe.FrontRinseTime)
{
//若BackRinseTime > FrontRinseTime,则延迟BackRinseTime - FrontRinseTime秒打开Water Above
if (ticks >= _rinseTime * 1000 - _srdRecipe.FrontRinseTime * 1000 && !_srdCommon.CommonData.WaterAbove)
{
bool result = _srdCommon.WaterAboveOn();
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Water Above Off is failed", 0);
return true;
}
_isAnotherWaterOn = true;
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Above On");
}
}
else
{
//若FrontRinseTime > BackRinseTime,则延迟FrontRinseTime - BackRinseTime秒打开Water Below
if (ticks >= _rinseTime * 1000 - _srdRecipe.BackRinseTime * 1000 && !_srdCommon.CommonData.WaterBelow)
{
bool result = _srdCommon.WaterBelowOn();
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Water Below On is failed",0);
return true;
}
LOG.WriteLog(eEvent.INFO_SRD, Module, "Water Below On");
}
}
}
//测水压
if (ticks > _washingFlowCheckTimeSpan)
{
if (_totalSRDDevice.WaterPressure > _srdRecipe.MaxWashPressure)
{
NotifyError(eEvent.ERR_SRD, $"Water Pressure {_totalSRDDevice.WaterPressure} is over {_srdRecipe.MaxWashPressure}", 0);
return true;
}
if (_totalSRDDevice.WaterPressure < _srdRecipe.MinWaterPressure)
{
NotifyError(eEvent.ERR_SRD, $"Water Pressure {_totalSRDDevice.WaterPressure} is less {_srdRecipe.MinWaterPressure}",0);
return true;
}
}
return false;
}
///
/// Washing结束
///
///
///
private bool WashingFinished()
{
if (_srdCommon.CommonData.WaterAbove)
{
if (!_srdCommon.WaterAboveOff())
{
NotifyError(eEvent.ERR_SRD, "Water Above Off is failed",0);
return false;
}
}
if (_srdCommon.CommonData.WaterBelow)
{
if (!_srdCommon.WaterBelowOff())
{
NotifyError(eEvent.ERR_SRD, "Water Below Off is failed", 0);
return false;
}
}
_isUsingWater = false;
if (_n2Enabled)
{
bool result = _armAxis.PositionStation("Center");
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Arm to Center is failed",0);
}
return result;
}
else
{
bool result = _armAxis.PositionStation("Home");
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Arm To Home is failed", 0);
}
return result;
}
}
///
/// 检验Arm是否运动到位
///
///
private bool CheckArmMotionEndStatus()
{
//Arm是否运动到位
if (_armAxis.Status == RState.End)
{
//调整速度为 drySpeed
bool result = _rotationAxis.ChangeSpeed(_drySpeed);
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Change Speed to Dry Speed is failed",0);
return false;
}
if (_n2Enabled)
{
//todo 打开N2 Above和N2 Below
}
_exhaustFanTime = Environment.TickCount;
return true;
}
return false;
}
///
/// 检验Arm是否运动到位
///
///
private bool CheckArmMotionStopStatus()
{
if (_armAxis.Status == RState.Failed||_armAxis.Status==RState.Timeout)
{
NotifyError(eEvent.ERR_SRD, "Arm Axis Status is in Failed", 0);
return true;
}
return false;
}
///
/// Exhaust delay
///
///
///
private bool ExhaustFanOn()
{
bool result = _srdCommon.ExhaustOn();
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Exhaust On failed",0);
return false;
}
if (_n2Enabled)
{
//todo 关闭N2Above和N2 Below
}
return true;
}
///
/// 停止旋转
///
///
private bool StopRotation()
{
bool result = _rotationAxis.StopPositionOperation();
LOG.WriteLog(eEvent.INFO_SRD, Module, "Stop Rotation is done");
return result;
}
///
/// 检验Rotation是否停止
///
///
private bool CheckRotationStopEndStatus()
{
if (!_rotationAxis.IsRun && _rotationAxis.Status == RState.End)
{
return true;
}
return false;
}
///
/// Rotation运行指定角度
///
///
private bool RotationMotion()
{
double scale = _rotationProviderAxis.ScaleFactor;
int currentRotation = (int)Math.Round(_rotationAxis.MotionData.MotorPosition * scale, 0);
//Presence Test目标位置(单位为°)
int targetPosition = (int)Math.Round(scale * _waferPresenceDistance, 0) + currentRotation;
//转速单位转换 RPM(r/min) to degree/s
double degree = BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(_waferPresenceSpeedInRPMs);
//Presence Test目标转速
int profileVelocity = (int)Math.Round(scale * degree, 0);
//加速度
int acceleration = (int)Math.Round(_rotationAxis.ProfileAcceleration * _waferPresenceCheckAccelDecelPercentage / 100, 0);
//减速度
int deceleration = (int)Math.Round(_rotationAxis.ProfileDeceleration * _waferPresenceCheckAccelDecelPercentage / 100, 0);
if (_srdCommon.CommonData.DoorOpened)
{
NotifyError(eEvent.ERR_SRD, "Door is not closed. Can't do rotation", 0);
return false;
}
bool result = _rotationAxis.ProfilePosition(targetPosition, profileVelocity * SPEED_RATIO, acceleration, deceleration);
if (!result)
{
NotifyError(eEvent.ERR_SRD, "Start Rotation is failed",0);
return false;
}
return true;
}
///
/// Rotation运动结束状态
///
///
private bool RotationMotionEndStatus()
{
return _rotationAxis.Status == RState.End;
}
///
/// Rotation运动
///
///
private bool RotationMotionStopStatus()
{
bool stopResult = _rotationAxis.Status == RState.Failed || _rotationAxis.Status == RState.Timeout;
if (!stopResult)
{
if (_presenceTestEnabled && _srdCommon.IsWaferPresence)
{
if (_srdCommon.WaferPresence != "WellPlaced")
{
NotifyError(eEvent.ERR_SRD, $"Rotation Motioning wafer presence is {_srdCommon.WaferPresence}",0);
return true;
}
}
}
else
{
return true;
}
return false;
}
///
/// Post N2 Time(Stop rotation ,home rotation)
///
///
///
private bool PostN2Time()
{
bool homeResult = _rotationAxis.Home(false);
if (!homeResult)
{
NotifyError(eEvent.ERR_SRD, $"{Module}.Arm is not homed", 0);
return false;
}
return true;
}
///
/// 检验Rotation是否Homed,Home后关闭排风扇
///
///
///
private bool CheckRotationHomedThenExhaust()
{
bool result = _rotationAxis.IsHomed && _rotationAxis.Status == RState.End;
if(result)
{
//关闭排风扇
if (_srdCommon.CommonData.ExhaustOn)
{
_srdCommon.ExhaustOffAction("", null);
}
}
return result;
}
///
/// 检验Rotation Home 停止状态
///
///
private bool CheckRotationHomedStopStatus()
{
return _rotationAxis.Status == RState.Failed || _rotationAxis.Status == RState.Timeout;
}
///
/// 检验
///
///
///
private bool LastCheckArmHomed()
{
string currentLocation = _armAxis.CurrentStation;
bool armHomed = _armAxis.IsHomed;
if (!armHomed)
{
NotifyError(eEvent.ERR_SRD, $"{Module}.Arm is not homed", 0);
return false;
}
if (!currentLocation.Contains("Home"))
{
NotifyError(eEvent.ERR_SRD, $"{Module}.Arm is not in home station", 0);
return false;
}
return true;
}
///
/// 启动
///
///
///
public RState Start(params object[] objs)
{
_isUsingWater = false;
if (objs.Length >= 2 && (bool)objs[1])
{
_presenceTestFlag = true;
}
else
{
_presenceTestFlag = false;
}
_srdRecipe = (SrdRecipe)objs[0];
if (_srdRecipe == null)
{
NotifyError(eEvent.ERR_SRD, "srd recipe is null", 0);
return RState.Failed;
}
_armAxis = DEVICE.GetDevice($"{Module}.Arm");
if (!_armAxis.IsHomed)
{
NotifyError(eEvent.ERR_SRD, "Arm is not homed", 0);
return RState.Failed;
}
_rotationAxis = DEVICE.GetDevice($"{Module}.Rotation");
if (!_rotationAxis.IsHomed)
{
NotifyError(eEvent.ERR_SRD, "Rotation is not homed",0);
return RState.Failed;
}
_srdCommon = DEVICE.GetDevice($"{Module}.Common");
_totalSRDDevice = DEVICE.GetDevice("SRD");
if (_srdCommon.IsWaferPresence)
{
if (_srdCommon.WaferPresence != "WellPlaced")
{
NotifyError(eEvent.ERR_SRD, "Wafer Presence is not WellPlaced", 0);
return RState.Failed;
}
}
else
{
LOG.WriteLog(eEvent.INFO_SRD, Module, "Wafer Presence Test has been ignored");
}
if (SC.ContainsItem("SRD.SRDRotationPlusSecond"))
{
_rotationPlusSecond = SC.GetValue("SRD.SRDRotationPlusSecond");
}
if (SC.ContainsItem("SRD.N2Enabled"))
{
_n2Enabled = SC.GetValue("SRD.N2Enabled");
}
//Wafer Presence Test
if (SC.ContainsItem($"SRD.{Module}EnablePresenceCheckvalue"))
{
_presenceTestEnabled = SC.GetValue($"SRD.{Module}EnablePresenceCheckvalue");
}
_systemFacilities = DEVICE.GetDevice("System.Facilities");
string otherSRD = Module == "SRD1" ? "SRD2" : "SRD1";
_otherSrdEntity = Singleton.Instance.GetModule(otherSRD);
_rotationProviderAxis = BeckhoffAxisProviderManager.Instance.GetAxisProvider($"{Module}.Rotation");
if (_rotationProviderAxis == null)
{
NotifyError(eEvent.ERR_SRD, $"{Module}.Rotation Provider is not exist", 0);
return RState.Failed;
}
_armProviderAxis = BeckhoffAxisProviderManager.Instance.GetAxisProvider($"{Module}.Arm");
if (_armProviderAxis == null)
{
NotifyError(eEvent.ERR_SRD, $"{Module}.Arm Provider is not exist",0);
return RState.Failed;
}
_waferPresenceCheckAccelDecelPercentage = SC.GetValue("SRD.WaferPresenceCheckAccelDecelPercentage");
_waferPresenceSpeedInRPMs = SC.GetValue("SRD.WaferPresenceCheckSpeedInRPMs");
_waferPresenceDistance = SC.GetValue("SRD.WaferPresenceCheckDistanceInDegrees");
return Runner.Start(Module, "Start Run Wafer");
}
}
}