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