using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.Routine; using Aitex.Core.Util; using MECF.Framework.Common.Beckhoff.AxisProvider; using MECF.Framework.Common.Beckhoff.Station; using MECF.Framework.Common.RecipeCenter; using MECF.Framework.Common.Routine; using MECF.Framework.Common.SubstrateTrackings; using MECF.Framework.Common.ToolLayout; using MECF.Framework.Common.Utilities; using PunkHPX8_Core; using PunkHPX8_RT.Devices.AXIS; using PunkHPX8_RT.Devices.Facilities; using PunkHPX8_RT.Devices.PlatingCell; using PunkHPX8_RT.Modules.Reservoir; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PunkHPX8_RT.Modules.PlatingCell { public class DummyRinseRunRecipeRoutine : RoutineBase, IRoutine { private enum RunRecipeStep { LoopStart, //interval rinse LoopCheckVerticalIntervalRinseStation, IntervalRinseOpenRinseValve, StartRotation, WaitRotation, IntervalRinseCloseRinseValve, //reclaim LoopCheckVerticalRelciamStation, ReclaimChangeRotationSpeed, ReclaimRotationDelay, //rinse LoopCheckVerticalRinseStation, RinseOpenRinseValve, RinseChangeRotationSpeed, RinseRotationDelay, RinseCloseRinseValve, //Dry LoopCheckVerticalDryStation, DryChangeRotationSpeed, DryRotationDelay, RotationStop, CheckRotationStoped, LoopEnd, End } #region 常量 private const int ALL_DAY_MILLOSECONDS = 24 * 60 * 60 * 1000; /// /// ROTATION电机转速比例 /// private const int SPEED_RATIO = 1; /// /// 电机以500rmp 运行12个小时的位置 /// private const int LARGETARGETPOSITION = 12 * 60 * 60 * 500 * 6; #endregion #region 内部变量 /// /// recipe /// private DqdrRecipe _recipe; /// /// 匹配的platingcell的dep recipe /// private DepRecipe _matchPlatingCellDepDeprecipe; /// /// Platingcell device /// private PlatingCellDevice _device; /// /// Rotation axis /// private JetAxisBase _rotationAxis; /// ///rotation Provider对象 /// private BeckhoffProviderAxis _rotationProviderAxis; /// cycle次数 /// private int _cycle; /// /// 当前完成的Cycle次数 /// private int _currentCycle; /// /// platingcell entity /// private PlatingCellEntity _platingCellEntity; /// /// 另一边的platingcell entity /// private PlatingCellEntity _matchPlatingCellEntity; /// /// 对应reservoir entity /// private ReservoirEntity _reservoirEntity; /// /// vertical axis entity /// private PlatingCellVerticalEntity _verticalEntity; /// /// run recipe 过程中电机会停的位置(需要根据recipe计算出来) /// #region 属性 #endregion #endregion /// /// 构造函数 /// /// public DummyRinseRunRecipeRoutine(string module) : base(module) { } /// /// 中止 /// public void Abort() { Runner.Stop("Manual Abort"); } /// /// 监控 /// /// public RState Monitor() { Runner.LoopStart(RunRecipeStep.LoopStart, "Loop Start Cycle Run DummyRinse Recipe Routine", _cycle, NullFun, _delay_1ms) //interval risne .LoopRunIfWithStopStatus(RunRecipeStep.LoopCheckVerticalIntervalRinseStation, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, () => CheckVerticalInStation("Rinse", _matchPlatingCellDepDeprecipe.IntervalRinseZoffset), () => { return _matchPlatingCellEntity.IsError; }) .LoopRunIf(RunRecipeStep.IntervalRinseOpenRinseValve, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, _device.RinseEnableAction, _delay_1ms) .LoopRunIf(RunRecipeStep.StartRotation, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, () => { return StartRotation(LARGETARGETPOSITION); }, _delay_1ms) .LoopDelayIf(RunRecipeStep.WaitRotation, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, _recipe.IntervalRinseTime * 1000) .LoopRunIf(RunRecipeStep.IntervalRinseCloseRinseValve, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, _device.RinseDisableAction, _delay_1ms) //Reclaim .LoopRunIfWithStopStatus(RunRecipeStep.LoopCheckVerticalIntervalRinseStation, _matchPlatingCellEntity.IsInRecipe, () => CheckVerticalInStation("Reclaim", _matchPlatingCellDepDeprecipe.ReclaimZoffset), () => { return _matchPlatingCellEntity.IsError; }) .LoopRunIf(RunRecipeStep.ReclaimChangeRotationSpeed, _matchPlatingCellEntity.IsInRecipe , () => { return ChangeRotationSpeed(_recipe.ReclaimSpeed); }, _delay_1ms) .LoopDelayIf(RunRecipeStep.ReclaimRotationDelay, _matchPlatingCellEntity.IsInRecipe , _recipe.ReclaimTime * 1000) //Rinse .LoopRunIfWithStopStatus(RunRecipeStep.LoopCheckVerticalRinseStation, _matchPlatingCellEntity.IsInRecipe, () => CheckVerticalInStation("Rinse", _matchPlatingCellDepDeprecipe.RinseZoffset), () => { return _matchPlatingCellEntity.IsError; }) .LoopRunIf(RunRecipeStep.RinseOpenRinseValve, _matchPlatingCellEntity.IsInRecipe, _device.RinseEnableAction, _delay_1ms) .LoopRunIf(RunRecipeStep.RinseChangeRotationSpeed, _matchPlatingCellEntity.IsInRecipe, () => { return ChangeRotationSpeed(_recipe.RinseSpeed); }, _delay_1ms) .LoopDelayIf(RunRecipeStep.RinseRotationDelay, _matchPlatingCellEntity.IsInRecipe, _recipe.RinseTime * 1000) .LoopRunIf(RunRecipeStep.RinseCloseRinseValve, _matchPlatingCellEntity.IsInRecipe, _device.RinseDisableAction, _delay_1ms) //Dry .LoopRunIfWithStopStatus(RunRecipeStep.LoopCheckVerticalDryStation, _matchPlatingCellEntity.IsInRecipe && _matchPlatingCellDepDeprecipe.RinseZoffset != _matchPlatingCellDepDeprecipe.DryZoffset, () => CheckVerticalInStation("Rinse", _matchPlatingCellDepDeprecipe.DryZoffset), () => { return _matchPlatingCellEntity.IsError; }) .LoopRunIf(RunRecipeStep.DryChangeRotationSpeed, _matchPlatingCellEntity.IsInRecipe, () => { return ChangeRotationSpeed(_recipe.DrySpeed); }, _delay_1ms) .LoopDelayIf(RunRecipeStep.DryRotationDelay, _matchPlatingCellEntity.IsInRecipe, _recipe.DryTime * 1000) .LoopRun(RunRecipeStep.RotationStop, _rotationAxis.StopPositionOperation, _delay_1ms) .LoopRunWithStopStatus(RunRecipeStep.CheckRotationStoped, CheckRotationPositionStatus, CheckRotationPositionRunStop) .LoopEnd(RunRecipeStep.LoopEnd, UpdateCycleCount, _delay_1ms) .End(RunRecipeStep.End, NullFun); return Runner.Status; } /// /// 查询vertical是否到达某个位置 /// /// private bool CheckVerticalInStation(string station,double offset) { return _verticalEntity.ChecVerticalInPosition(station, offset); } /// /// rotation开始旋转 /// /// /// private bool StartRotation(int targetPosition) { bool result = _rotationAxis.ProfilePosition(targetPosition, _recipe.IntervalRinseSpeed * SPEED_RATIO * 6, 0, 0); //rpm->deg/s if (!result) { NotifyError(eEvent.ERR_PLATINGCELL, "Start Rotation is failed", 0); return false; } return true; } /// /// rotation改变速度 /// /// /// private bool ChangeRotationSpeed(int speed) { double _scale = _rotationAxis.ScaleFactor; speed = (int)Math.Round(_scale * BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(speed), 0); return _rotationAxis.ChangeSpeed(speed); } /// /// 检验Rotation移动状态 /// /// private bool CheckRotationPositionStatus() { return _rotationAxis.Status == RState.End; } /// /// 检验Rotation是否运动失败 /// /// private bool CheckRotationPositionRunStop() { return _rotationAxis.Status == RState.Failed || _rotationAxis.Status == RState.Timeout; } /// 统计完成的Cycle次数 /// /// private bool UpdateCycleCount() { _currentCycle += 1; return true; } /// /// 获取当前Cycle次数 /// /// public int GetCurrentCycle() { return _currentCycle; } /// /// 启动 /// /// /// public RState Start(params object[] objs) { _recipe = objs[0] as DqdrRecipe; if (_recipe == null) { LOG.WriteLog(eEvent.ERR_METAL, Module, "recipe is null"); return RState.Failed; } if (objs.Length > 1) { _cycle = (int)objs[1]; } _device = DEVICE.GetDevice(Module); _rotationAxis = DEVICE.GetDevice($"{Module}.Rotation"); _rotationProviderAxis = BeckhoffAxisProviderManager.Instance.GetAxisProvider($"{Module}.Rotation"); if (_rotationProviderAxis == null) { NotifyError(eEvent.ERR_PLATINGCELL, $"{Module}.Rotation Provider is not exist", 0); return RState.Failed; } //获取相匹配的platingcell 的 vertical entity string MatchModule = ModuleMatcherManager.Instance.GetMatcherByModule(Module); string vertical = ModuleMatcherManager.Instance.GetPlatingVerticalByCell(MatchModule); _verticalEntity = Singleton.Instance.GetModule(vertical); //获取platingcell eneity _platingCellEntity = Singleton.Instance.GetModule(Module); //获取match的platingcell的dep recipe _matchPlatingCellEntity = Singleton.Instance.GetModule(MatchModule); _matchPlatingCellDepDeprecipe = _matchPlatingCellEntity.CurrentRecipe; //获取对应reservoir eneity string reservoir = ReservoirItemManager.Instance.GetReservoirByPlatingCell(Module); _reservoirEntity = Singleton.Instance.GetModule(reservoir); if (!CheckPreCondition()) { return RState.Failed; } _currentCycle = 0; return Runner.Start(Module, "PlatingCell Run DummyRecipe Recipe"); } /// /// 检验前置条件 /// /// private bool CheckPreCondition() { if (_recipe == null) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Recipe is null"); return false; } if (!CheckAxisHome()) { NotifyError(eEvent.ERR_PLATINGCELL, "Check Axis home error", 0); return false; } if (!CheckFacility()) { NotifyError(eEvent.ERR_PLATINGCELL, "Check facility error", 0); return false; } if (!CheckModuleAndReservoir()) { NotifyError(eEvent.ERR_PLATINGCELL, "Check ModuleAndReservoir error", 0); return false; } return true; } private bool CheckModuleAndReservoir() { if (!_platingCellEntity.IsIdle) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, $"{Module} is not initialized"); return false; } if (!_reservoirEntity.IsIdle) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, $"Releated reseroivr is not initialized"); return false; } if (!_reservoirEntity.TemperatureReached) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, $"Releated reseroivr temperature is not reached"); return false; } if ("Manual".Equals(_reservoirEntity.PersistentValue.OperatingMode) && !WaferManager.Instance.CheckHasWafer(Module, 0)) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, $"Run recipe in manual must has wafer!"); return false; } return true; } /// /// 检查马达是否上电且home /// /// private bool CheckAxisHome() { if (!_rotationAxis.IsSwitchOn) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Rotation Axis is off"); return false; } if (!_rotationAxis.IsHomed) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Rotation Axis is not home"); return false; } if (!_verticalEntity.AxisIsHome) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Vertical Axis is not home"); return false; } return true; } /// /// 检查facility /// /// private bool CheckFacility() { SystemFacilities systemFacilities = DEVICE.GetDevice("System.Facilities"); if (systemFacilities == null) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Facility is null"); return false; } if (!systemFacilities.CDAEnable) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Facility CDA is off"); return false; } if (!systemFacilities.N2Enable) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Facility N2 is off"); return false; } if (!systemFacilities.DIFillEnable) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Facility DIW is off"); return false; } if (systemFacilities.FacilitiesDataDic["CDA1Pressure"].IsError || systemFacilities.FacilitiesDataDic["CDA2Pressure"].IsError) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Facility CDA Data is in error range"); return false; } if (systemFacilities.FacilitiesDataDic["Nitrogen1APressure"].IsError || systemFacilities.FacilitiesDataDic["Nitrogen1BPressure"].IsError || systemFacilities.FacilitiesDataDic["Nitrogen2APressure"].IsError || systemFacilities.FacilitiesDataDic["Nitrogen2BPressure"].IsError) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Facility N2 Data is in error range"); return false; } if (systemFacilities.FacilitiesDataDic["DiWaterPressure"].IsError) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Facility Diw Pressure value is in error range"); return false; } return true; } } }