using Aitex.Core.RT.Device; using Aitex.Core.RT.Fsm; using Aitex.Core.RT.Log; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using Aitex.Core.Utilities; using MECF.Framework.Common.Beckhoff.AxisProvider; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.RecipeCenter; using MECF.Framework.Common.Utilities; using CyberX8_Core; using CyberX8_RT.Backends; using CyberX8_RT.Devices.AXIS; using CyberX8_RT.Devices.Facilities; using CyberX8_RT.Devices.Loader; using CyberX8_RT.Devices.SRD; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Timers; using System.Windows.Threading; using Aitex.Core.RT.Routine; namespace CyberX8_RT.Modules.SRD { /// /// RunWafer状态机 /// public class RunWaferRecipeStateMachine : Entity, IEntity { #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 内部变量 /// /// 模块名称 /// private string _module; /// /// 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是否Home /// private bool _armIsHomed; /// /// Arm重试次数 /// private int _armRetryTimes = 0; /// /// ARM正在执行Home /// private bool _armHoming = false; /// /// 是否正在用水 /// private bool _isUsingWater = false; /// /// 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; /// /// exhaust进入时间 /// private int _exhaustFanTime; /// /// 旋转停止时间 /// private int _rotationStopTime; /// /// 是否执行Rotation Stop /// private bool _isExecuteRotationStop; /// /// 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; /// /// PresenceTest记录次数 /// private int _presenceTestCount; /// /// 当前次数 /// private int _currentCount; /// /// Rinse时间=Max(FrontRinseTime, BackRinseTime) 单位s /// private double _rinseTime; /// /// Rinse中另一个水阀开关状态 /// private bool _isAnotherWaterOn; /// /// PresenceTest是否完成 /// private bool _isTestComplete = true; /// /// Rotation是否执行Position /// private bool _isRotationExecutePosition = false; /// /// PresenceTest进入时间 /// private int _presenceTestEnterTime; #endregion #region 属性 /// /// 状态 /// public string State { get { return ((RunWaferState)fsm.State).ToString(); } } #endregion /// /// 构造函数 /// /// public RunWaferRecipeStateMachine(string module) { _module = module; this.fsm = new StateMachine($"{module}_RunWaferStateMachine", (int)RunWaferState.RunWafer_Complete, 10); fsm.EnableRepeatedMsg(true); AnyStateTransition(RunWaferMsg.Init, EnterRunWaferStart, RunWaferState.RunWafer_Start); AnyStateTransition(RunWaferMsg.Error, EnterError, RunWaferState.Error); Transition(RunWaferState.RunWafer_Start, RunWaferMsg.RunWafer_Start, RunWaferStartCheckStatus, RunWaferState.RunWafer_CheckFacilities); Transition(RunWaferState.RunWafer_CheckFacilities, FSM_MSG.TIMER, CheckFacilities, RunWaferState.RunWafer_PreparingExhaustOff); Transition(RunWaferState.RunWafer_PreparingExhaustOff, FSM_MSG.TIMER, PreparingExhaustOff, RunWaferState.RunWafer_WaitExhaustOff); Transition(RunWaferState.RunWafer_WaitExhaustOff, FSM_MSG.TIMER, WaitExhaustOff, RunWaferState.RunWafer_EngageChuckVacuum); Transition(RunWaferState.RunWafer_EngageChuckVacuum, FSM_MSG.TIMER, EngageChuckVacuum, RunWaferState.RunWafer_CheckVacuum); Transition(RunWaferState.RunWafer_CheckVacuum, FSM_MSG.TIMER, CheckVacuum, RunWaferState.RunWafer_CloseTheDoor); Transition(RunWaferState.RunWafer_CloseTheDoor, FSM_MSG.TIMER,CloseDoor,RunWaferState.RunWafer_CheckDoorClosed); Transition(RunWaferState.RunWafer_CheckDoorClosed, FSM_MSG.TIMER, CheckDoorClosed, RunWaferState.RunWafer_ArmToHome); Transition(RunWaferState.RunWafer_ArmToHome, FSM_MSG.TIMER,ArmToHome, RunWaferState.RunWafer_Diverting_CheckArmHome); Transition(RunWaferState.RunWafer_Diverting_CheckArmHome, FSM_MSG.TIMER, CheckArmHome, RunWaferState.RunWafer_Diverting_CheckOtherSRD); Transition(RunWaferState.RunWafer_Diverting_CheckOtherSRD, FSM_MSG.TIMER, CheckOtherSRD, RunWaferState.RunWafer_Diverting_WaterOn); Transition(RunWaferState.RunWafer_Diverting_WaterOn, FSM_MSG.TIMER, WaterOn, RunWaferState.RunWafer_Diverting_WithFlowCheck); Transition(RunWaferState.RunWafer_Diverting_WithFlowCheck, FSM_MSG.TIMER, CheckFlow, RunWaferState.RunWafer_Washing_ArmToCenter); Transition(RunWaferState.RunWafer_Washing_ArmToCenter, FSM_MSG.TIMER, ArmToCenter, RunWaferState.RunWafer_Washing_CheckArmCenter); Transition(RunWaferState.RunWafer_Washing_CheckArmCenter, FSM_MSG.TIMER, CheckArmToCenter, RunWaferState.RunWafer_Washing_PoolingFrontSide); Transition(RunWaferState.RunWafer_Washing_PoolingFrontSide, FSM_MSG.TIMER, PoolingFrontSideWaterOn, RunWaferState.RunWafer_Washing_PoolingWithFlowCheck); Transition(RunWaferState.RunWafer_Washing_PoolingWithFlowCheck, FSM_MSG.TIMER, PoolingCheckFlow, RunWaferState.RunWafer_Washing_StartRotation); Transition(RunWaferState.RunWafer_Washing_StartRotation, FSM_MSG.TIMER, StartRotation, RunWaferState.RunWafer_Washing_PreFlowCheck); Transition(RunWaferState.RunWafer_Washing_PreFlowCheck, FSM_MSG.TIMER, WashingPreFlowCheck, RunWaferState.RunWafer_Washing_Finished); Transition(RunWaferState.RunWafer_Washing_Finished, FSM_MSG.TIMER, WashingFinished, RunWaferState.RunWafer_Drying_PreN2Time); Transition(RunWaferState.RunWafer_Drying_PreN2Time, FSM_MSG.TIMER, CheckArmMotion, RunWaferState.RunWafer_Drying_ExhaustFanDelay); Transition(RunWaferState.RunWafer_Drying_ExhaustFanDelay, FSM_MSG.TIMER, ExhaustFanDelay, RunWaferState.RunWafer_Drying_N2On); Transition(RunWaferState.RunWafer_Drying_N2On, FSM_MSG.TIMER, N2On, RunWaferState.RunWafer_Drying_PreWaferPresenceCheck); Transition(RunWaferState.RunWafer_Drying_PreWaferPresenceCheck, FSM_MSG.TIMER, PreWaferPresenceCheck, RunWaferState.RunWafer_Drying_WaferPresenceCheck); Transition(RunWaferState.RunWafer_Drying_WaferPresenceCheck, FSM_MSG.TIMER, WaferPresenceCheck, RunWaferState.RunWafer_Drying_PostN2Time); Transition(RunWaferState.RunWafer_Drying_PostN2Time, FSM_MSG.TIMER, PostN2Time, RunWaferState.RunWafer_Drying_CheckRotationFinished); Transition(RunWaferState.RunWafer_Drying_CheckRotationFinished, FSM_MSG.TIMER, CheckRotationFinished, RunWaferState.RunWafer_CheckArmHome); Transition(RunWaferState.RunWafer_CheckArmHome, FSM_MSG.TIMER, LastCheckArmHomed, RunWaferState.RunWafer_Complete); //PresenceTest Transition(RunWaferState.RunWafer_Complete, RunWaferMsg.PreWaferPresenceCheck, RunWaferStartCheckStatus, RunWaferState.RunWafer_Drying_PreWaferPresenceCheck); EnumLoop.ForEach((item) => { fsm.MapState((int)item, item.ToString()); }); EnumLoop.ForEach((item) => { fsm.MapMessage((int)item, item.ToString()); }); } private bool EnterError(object param) { //关闭风扇 if (_srdCommon.CommonData.ExhaustOn) { bool result = _srdCommon.ExhaustOffAction("", null); if (!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "EnterError: Exhaust Off is failed"); } } //关闭WaterAbove if (_srdCommon.CommonData.WaterAbove) { bool result = _srdCommon.WaterAboveOff(); if (!result) { LOG.WriteLog(eEvent.INFO_SRD, _module, "EnterError: Water Above Off is failed"); } } //关闭WaterBelow if (_srdCommon.CommonData.WaterBelow) { bool result = _srdCommon.WaterBelowOff(); if (!result) { LOG.WriteLog(eEvent.INFO_SRD, _module, "EnterError: Water Below Off is failed"); } } return true; } private bool EnterRunWaferStart(object param) { _isRotationExecutePosition = false; return true; } #region 状态方法 /// /// 启动 /// /// /// private bool RunWaferStartCheckStatus(object param) { _startTime = Environment.TickCount; if(param!=null) { object[] parameters= (object[])param; _srdRecipe=(SrdRecipe)parameters[0]; } if(_srdRecipe==null) { PostMsg(RunWaferMsg.Error); LOG.WriteLog(eEvent.ERR_SRD, _module, "srd recipe is null"); return false; } _armAxis = DEVICE.GetDevice($"{_module}.Arm"); if(!_armAxis.IsHomed) { PostMsg(RunWaferMsg.Error); LOG.WriteLog(eEvent.ERR_SRD, _module, "Arm is not homed"); return false; } _rotationAxis = DEVICE.GetDevice($"{_module}.Rotation"); if (!_rotationAxis.IsHomed) { PostMsg(RunWaferMsg.Error); LOG.WriteLog(eEvent.ERR_SRD, _module, "Rotation is not homed"); return false; } _srdCommon = DEVICE.GetDevice($"{_module}.Common"); _totalSRDDevice = DEVICE.GetDevice("SRD"); if (_srdCommon.IsWaferPresence) { if (_srdCommon.WaferPresence != "WellPlaced") { PostMsg(RunWaferMsg.Error); LOG.WriteLog(eEvent.ERR_SRD, _module, "Wafer Presence is not WellPlaced"); return false; } } 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) { PostMsg(RunWaferMsg.Error); LOG.WriteLog(eEvent.ERR_SRD, _module, $"{_module}.Rotation Provider is not exist"); return false; } _armProviderAxis = BeckhoffAxisProviderManager.Instance.GetAxisProvider($"{_module}.Arm"); if (_armProviderAxis == null) { PostMsg(RunWaferMsg.Error); LOG.WriteLog(eEvent.ERR_SRD, _module, $"{_module}.Arm Provider is not exist"); return false; } _waferPresenceCheckAccelDecelPercentage = SC.GetValue("SRD.WaferPresenceCheckAccelDecelPercentage"); _waferPresenceSpeedInRPMs = SC.GetValue("SRD.WaferPresenceCheckSpeedInRPMs"); _waferPresenceDistance = SC.GetValue("SRD.WaferPresenceCheckDistanceInDegrees"); return true; } /// /// 检查Facilities /// /// /// private bool CheckFacilities(object param) { if (_srdCommon.CommonData.FluidContainment) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Fluid Containment sensor is On"); PostMsg(RunWaferMsg.Error); return false; } if(!_systemFacilities.LoaderDiEnable) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Load DI Is Disable"); PostMsg(RunWaferMsg.Error); return false; } return true; } /// /// 关闭Exhaust风机 /// /// /// private bool PreparingExhaustOff(object param) { bool result = _srdCommon.ExhaustOffAction("", null); if (!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Preparing Exhaust Off is failed"); PostMsg(RunWaferMsg.Error); return false; } return true; } /// /// 等待Exhaust风机关闭状态 /// /// /// private bool WaitExhaustOff(object param) { if (_srdCommon.Status==RState.Failed||_srdCommon.Status==RState.Timeout) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Waiting Exhaust Off is failed"); PostMsg(RunWaferMsg.Error); return false; } return _srdCommon.Status == RState.End && !_srdCommon.CommonData.ExhaustOn; } /// /// Chuck Vacuum /// /// /// private bool EngageChuckVacuum(object param) { if (_srdCommon.IsWaferPresence) { bool result = _srdCommon.ChuckVacuumOnAction("", null); if (!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Chuck Vacuum On Action is failed"); PostMsg(RunWaferMsg.Error); } return result; } else { LOG.WriteLog(eEvent.INFO_SRD, _module, "EngageChuckVacuum has been ignored"); return true; } } /// /// 检查真空状态 /// /// /// private bool CheckVacuum(object param) { if (_srdCommon.IsWaferPresence) { if (_srdCommon.Status == RState.Failed || _srdCommon.Status == RState.Timeout) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Check Vacuum is failed"); PostMsg(RunWaferMsg.Error); return false; } return _srdCommon.Status == RState.End && !_srdCommon.CommonData.ChuckVacuum; } else { LOG.WriteLog(eEvent.INFO_SRD, _module, "CheckVacuum has been ignored"); return true; } } /// /// Close Door /// /// /// private bool CloseDoor(object param) { if (_srdCommon.CommonData.DoorOpened) { bool result = _srdCommon.DoorCloseAction("", null); if (!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Door Close Action is failed"); PostMsg(RunWaferMsg.Error); return result; } } return true; } /// /// 检验DoorClosed /// /// /// private bool CheckDoorClosed(object param) { if (_srdCommon.Status == RState.Failed || _srdCommon.Status == RState.Timeout) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Check Door Closed is failed"); PostMsg(RunWaferMsg.Error); return false; } return _srdCommon.Status == RState.End && _srdCommon.CommonData.DoorClosed; } /// /// Arm To Home /// /// private bool ArmToHome(object param) { if (!_armHoming) { _armAxis.Home(false); _armHoming = true; return false; } else { if(_armAxis.Status != RState.End) { return false; } } _armHoming = false; _armIsHomed = _armAxis.IsHomed; return true; } /// /// 检验ARM,发现失败,则重试 /// /// /// private bool CheckArmHome(object param) { if (_armIsHomed) { return true; } else { if(_armRetryTimes /// 检验另外一个SRD是否在用水 /// /// /// private bool CheckOtherSRD(object param) { if (_otherSrdEntity == null) { return true; } return !_otherSrdEntity.IsUsingWater; } /// /// 打开Above water /// /// /// private bool WaterOn(object param) { 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 { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Above On is failed"); PostMsg(RunWaferMsg.Error); } return result; } return false; } else { return true; } } /// /// 检验水压 /// /// /// private bool CheckFlow(object param) { if (_srdRecipe.FrontDivertTime==0) { return true; } else { int ticks = Environment.TickCount - _enterTime; if(ticks<=_divertingFlowCheckTimeSpan) { if(_totalSRDDevice.WaterPressure>_srdRecipe.MaxDivertPlusPoolPressure) { LOG.WriteLog(eEvent.ERR_SRD, _module,$"Water Pressure {_totalSRDDevice} is over {_srdRecipe.MaxDivertPlusPoolPressure}"); PostMsg(RunWaferMsg.Error); return false; } } else { if (ticks >= _srdRecipe.FrontDivertTime*1000) { if (_srdCommon.CommonData.WaterAbove) { bool result = _srdCommon.WaterAboveOff(); if (result) { LOG.WriteLog(eEvent.INFO_SRD, _module, "Water Above off"); } else { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Above On is failed"); PostMsg(RunWaferMsg.Error); } return result; } } } } return false; } /// /// Arm运动至Center /// /// /// private bool ArmToCenter(object param) { bool result= _armAxis.PositionStation("Center"); if(!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Arm to Center is failed"); PostMsg(RunWaferMsg.Error); } return result; } /// /// check Arm是否运动至Center /// /// /// private bool CheckArmToCenter(object param) { if (_armAxis.Status==RState.End) { return true; } else if(_armAxis.Status==RState.Failed) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Check Arm to Center is failed"); PostMsg(RunWaferMsg.Error); return false; } return false; } /// /// 打开Above water /// /// /// private bool PoolingFrontSideWaterOn(object param) { 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; if (_isUsingWater) { _isUsingWater = true; } } else { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Above On is failed"); PostMsg((int)RunWaferMsg.Error); } return result; } return true; } else { return true; } } /// /// 检验水压 /// /// /// private bool PoolingCheckFlow(object param) { if (_srdRecipe.FrontPoolTime == 0) { return true; } else { int ticks = Environment.TickCount - _enterTime; if (ticks <= _poolingFlowCheckTimeSpan) { if (_totalSRDDevice.WaterPressure > _srdRecipe.MaxWashPressure) { LOG.WriteLog(eEvent.ERR_SRD, _module, $"Water Pressure {_totalSRDDevice.WaterPressure} is over {_srdRecipe.MaxWashPressure}"); PostMsg((int)RunWaferMsg.Error); return false; } if (_totalSRDDevice.WaterPressure < _srdRecipe.MinWaterPressure) { LOG.WriteLog(eEvent.ERR_SRD, _module, $"Water Pressure {_totalSRDDevice.WaterPressure} is less {_srdRecipe.MinWaterPressure}"); PostMsg((int)RunWaferMsg.Error); return false; } } else { if (ticks >= _srdRecipe.FrontPoolTime * 1000) { return true; } } } return false; } /// /// 开始旋转 /// /// /// private bool StartRotation(object param) { if (_srdCommon.CommonData.DoorOpened) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Door is not closed. Can't do rotation"); PostMsg(RunWaferMsg.Error); 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) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Start Rotation is failed"); PostMsg(RunWaferMsg.Error); 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()) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Above Off is failed"); PostMsg((int)RunWaferMsg.Error); return false; } LOG.WriteLog(eEvent.INFO_SRD, _module, "Water Above Off"); } //打开WaterBelow if (!_srdCommon.CommonData.WaterBelow) { if (!_srdCommon.WaterBelowOn()) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Below On is failed"); PostMsg((int)RunWaferMsg.Error); 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()) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Above Off is failed"); PostMsg((int)RunWaferMsg.Error); return false; } LOG.WriteLog(eEvent.INFO_SRD, _module, "Water Above On"); } //关闭WaterBelow if (_srdCommon.CommonData.WaterBelow) { //打开WaterBelow if (!_srdCommon.WaterBelowOff()) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Below On is failed"); PostMsg((int)RunWaferMsg.Error); 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; } } /// /// 检验水压 /// /// /// private bool WashingPreFlowCheck(object param) { 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) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Above Off is failed"); PostMsg((int)RunWaferMsg.Error); return false; } _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) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Below On is failed"); PostMsg((int)RunWaferMsg.Error); return false; } LOG.WriteLog(eEvent.INFO_SRD, _module, "Water Below On"); } } } if (ticks >= _rinseTime * 1000) { //达到RinseTime完成Wash return true; } else if (ticks > _washingFlowCheckTimeSpan) { if (_totalSRDDevice.WaterPressure > _srdRecipe.MaxWashPressure) { LOG.WriteLog(eEvent.ERR_SRD, _module, $"Water Pressure {_totalSRDDevice.WaterPressure} is over {_srdRecipe.MaxWashPressure}"); PostMsg((int)RunWaferMsg.Error); return false; } if (_totalSRDDevice.WaterPressure < _srdRecipe.MinWaterPressure) { LOG.WriteLog(eEvent.ERR_SRD, _module, $"Water Pressure {_totalSRDDevice.WaterPressure} is less {_srdRecipe.MinWaterPressure}"); PostMsg((int)RunWaferMsg.Error); return false; } } else { return false; } return false; } /// /// Washing结束 /// /// /// private bool WashingFinished(object param) { if (_srdCommon.CommonData.WaterAbove) { if(!_srdCommon.WaterAboveOff()) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Above Off is failed"); PostMsg(RunWaferMsg.Error); return false; } } if(_srdCommon.CommonData.WaterBelow) { if(!_srdCommon.WaterBelowOff()) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Water Below Off is failed"); PostMsg(RunWaferMsg.Error); return false; } } _isUsingWater = false; if(_n2Enabled) { bool result= _armAxis.PositionStation("Center"); if(!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Arm to Center is failed"); PostMsg(RunWaferMsg.Error); } return result; } else { bool result= _armAxis.PositionStation("Home"); if (!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Arm To Home is failed"); PostMsg(RunWaferMsg.Error); } return result; } } /// /// 检验Arm是否运动到位 /// /// private bool CheckArmMotion(object param) { //Arm是否运动到位 if (_armAxis.Status==RState.End) { //调整速度为 drySpeed bool result= _rotationAxis.ChangeSpeed(_drySpeed); if(!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Change Speed to Dry Speed is failed"); return false; } if(_n2Enabled) { //todo 打开N2 Above和N2 Below } _exhaustFanTime = Environment.TickCount; return true; } else if(_armAxis.Status==RState.Failed) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Arm Axis Status is in Failed"); PostMsg(RunWaferMsg.Error); return false; } return false; } /// /// Exhaust delay /// /// /// private bool ExhaustFanDelay(object param) { int ticks = Environment.TickCount - _exhaustFanTime; if (ticks >= _srdRecipe.ExhaustFanDelay * 1000) { bool result = _srdCommon.ExhaustOn(); if(!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Exhaust On failed"); PostMsg(RunWaferMsg.Error); return false; } _enterTime = Environment.TickCount; return true; } return false; } /// /// N2 On /// /// /// private bool N2On(object param) { if (_n2Enabled) { //todo 关闭N2Above和N2 Below } int ticks = Environment.TickCount - _enterTime; if(ticks > _srdRecipe.BackN2DryTime * 1000) return true; return false; } /// /// Pre WaferPresence Check /// /// private bool PreWaferPresenceCheck(object param) { if (!_isExecuteRotationStop) { //停止Rotation bool result= _rotationAxis.StopPositionOperation(); LOG.WriteLog(eEvent.INFO_SRD, _module, "Stop Rotation is done"); _rotationStopTime = Environment.TickCount; _isExecuteRotationStop = true; if(!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Stop Rotation is failed"); PostMsg(RunWaferMsg.Error); } } else { int ticks=Environment.TickCount-_rotationStopTime; if(ticks>=5*1000)//固定时间5秒,确认Rotation是否已经停下 { if(!_rotationAxis.IsRun && _rotationAxis.Status == RState.End) { _isExecuteRotationStop = false; return true; } else { LOG.WriteLog(eEvent.ERR_SRD, _module, "SRD Rotation Stop time span is over 5 seconds"); PostMsg(RunWaferMsg.Error); return false; } } } return false; } /// /// Wafer Presence Check /// /// /// private bool WaferPresenceCheck(object param) { 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 (!_isRotationExecutePosition) { if (_srdCommon.CommonData.DoorOpened) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Door is not closed. Can't do rotation"); PostMsg(RunWaferMsg.Error); return false; } bool result = _rotationAxis.ProfilePosition(targetPosition, profileVelocity * SPEED_RATIO, acceleration, deceleration); if (!result) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Start Rotation is failed"); PostMsg(RunWaferMsg.Error); } _isRotationExecutePosition = true; if (_srdCommon.IsWaferPresence && _presenceTestEnabled) { //PresenceTest记录次数=(目标位置/目标转速)*1000ms /500ms _presenceTestCount = (int)Math.Floor(_waferPresenceDistance / degree * 1000 / 500); LOG.WriteLog(eEvent.INFO_SRD, _module, $"Presence Test Count is about {_presenceTestCount} times"); //当前test次数归零 _currentCount = 0; //开始计时 _presenceTestEnterTime = Environment.TickCount; _isTestComplete = false; LOG.WriteLog(eEvent.INFO_SRD, _module, "Presence Test Timer is started"); } return false; } else { //PresenceTestEnable开启则进行测试 if (!_isTestComplete && _srdCommon.IsWaferPresence && _presenceTestEnabled) { int ticks = Environment.TickCount - _presenceTestEnterTime; //500ms检测一次 if(ticks >= 500) { if (_srdCommon.WaferPresence == "WellPlaced") { _currentCount++; LOG.WriteLog(eEvent.INFO_SRD, _module, $"The {_currentCount}th Presence Test is successful"); //更新PresenceTestEnterTime _presenceTestEnterTime = Environment.TickCount; if(_currentCount >= _presenceTestCount) { //PresenceTest通过 _isTestComplete = true; LOG.WriteLog(eEvent.INFO_SRD, _module, $"The Presence Test of {_module} is all successful"); } else { return false; } } else { LOG.WriteLog(eEvent.ERR_SRD, _module, $"The {_currentCount + 1}th Presence Test is failed"); LOG.WriteLog(eEvent.ERR_SRD, _module, $"The Presence Test of {_module} is failed"); PostMsg(RunWaferMsg.Error); return false; } } else { return false; } } if (_rotationAxis.Status!=RState.End) { return false; } } return true; } /// /// Post N2 Time(Stop rotation ,home rotation) /// /// /// private bool PostN2Time(object param) { bool homeResult = _rotationAxis.Home(false); if(!homeResult) { LOG.WriteLog(eEvent.ERR_SRD, _module, $"{_module}.Arm is not homed"); PostMsg(RunWaferMsg.Error); return false; } return true; } /// /// 检验Rotation是否Homed /// /// /// private bool CheckRotationFinished(object param) { //关闭排风扇 if (_srdCommon.CommonData.ExhaustOn && _srdCommon.Status != RState.Running) { bool result1 = _srdCommon.ExhaustOffAction("", null); if (!result1) { LOG.WriteLog(eEvent.ERR_SRD, _module, "Preparing Exhaust Off is failed"); PostMsg(RunWaferMsg.Error); } } bool result= _rotationAxis.IsHomed && _rotationAxis.Status == RState.End; if(_rotationAxis.Status!=RState.Running) { if(!_rotationAxis.IsHomed) { LOG.WriteLog(eEvent.ERR_SRD, _module, $"{_module}.rotation is not homed"); } return true; } return false; } /// /// 检验 /// /// /// private bool LastCheckArmHomed(object param) { string currentLocation = _armAxis.CurrentStation; bool armHomed= _armAxis.IsHomed; if(!armHomed) { LOG.WriteLog(eEvent.ERR_SRD, _module, $"{_module}.Arm is not homed"); PostMsg(RunWaferMsg.Error); return false; } if (!currentLocation.Contains("Home")) { LOG.WriteLog(eEvent.ERR_SRD, _module, $"{_module}.Arm is not in home station"); PostMsg(RunWaferMsg.Error); return false; } LOG.WriteLog(eEvent.INFO_SRD, _module, $"Run Wafer State Machine 状态 {RunWaferState.RunWafer_Start}==>{RunWaferState.RunWafer_Complete} Total Time[{Environment.TickCount - _startTime}]"); return true; } #endregion /// /// 停止 /// public void Stop() { base.Terminate(); } public bool Check(int msg, out string reason, params object[] args) { reason = ""; return false; } #region State Msg枚举 public enum RunWaferState { None, Error, 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_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_N2On, RunWafer_Drying_PreWaferPresenceCheck, RunWafer_Drying_WaferPresenceCheck, RunWafer_Drying_PostN2Time, RunWafer_Drying_CheckRotationFinished, RunWafer_CheckArmHome, RunWafer_Complete } public enum RunWaferMsg { Init, Error, RunWafer_Start, CheckFacilities, PreparingExhaustOff, WaitExhaustOff, EngageChuckVacuum, CloseTheDoor, ArmToHome, CheckOtherSRD, DivertingWaterAboveOn, ArmToCenter, PoolingFrontWaterAboveOn, StartRotation, Washing_Finished, N2On, PreWaferPresenceCheck, WaferPresenceCheck, PostN2Time, CheckArmHome, Abort } #endregion } }