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; using static Mono.Security.X509.X520; namespace PunkHPX8_RT.Modules.PlatingCell { public class PlatingCellRunRecipeRoutine : RoutineBase, IRoutine { private enum RunRecipeStep { Delay, VerticalGotoRinse, CheckVerticalGotoRinse, InterRinse, CheckInterRinse, RotationStartEntry, RotationChangeToEntrySpeed, AngleTilt, VerticalGotoEntry, WaitEntryCurrentProtectedFromRinse, WaitEntryCurrentProtectedFromHome, EntryCurrentProtected, CheckVertical, End } #region 常量 private const int ALL_DAY_MILLOSECONDS = 24 * 60 * 60 * 1000; /// /// ROTATION电机转速比例 /// private const int SPEED_RATIO = 1; #endregion #region 内部变量 /// /// recipe /// private DepRecipe _recipe; /// /// 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; /// /// 对应reservoir entity /// private ReservoirEntity _reservoirEntity; /// /// interbal rinse routien /// private PlatingCellInterRinseRoutine _interRinseRoutine; /// /// vertical axis entity /// private PlatingCellVerticalEntity _verticalEntity; /// /// vertical 轴的位置数据 /// private BeckhoffStationAxis _verticalBeckhoffStation; /// /// recipe中是否存在电机反转 /// private bool _isRecipeContainsRevserseRotation; /// /// run recipe 过程中电机会停的位置(需要根据recipe计算出来) /// private List _targetPositionList = new List(); #endregion /// /// 构造函数 /// /// public PlatingCellRunRecipeRoutine(string module) : base(module) { _interRinseRoutine = new PlatingCellInterRinseRoutine(module); } /// /// 中止 /// public void Abort() { Runner.Stop("Manual Abort"); } /// /// 监控 /// /// public RState Monitor() { //vertical去rinse位置 Runner.RunIf(RunRecipeStep.VerticalGotoRinse, _recipe.RinseBeforeEntryEnable, () => { return StartVertical("Rinse",_recipe.IntervalRinseZoffset); }, _delay_1ms) .WaitWithStopConditionIf(RunRecipeStep.CheckVerticalGotoRinse, _recipe.RinseBeforeEntryEnable, CheckVerticalEnd, CheckVerticalError) //执行interval rinse .RunIf(RunRecipeStep.InterRinse, _recipe.RinseBeforeEntryEnable, () => { return _interRinseRoutine.Start(_recipe, _rotationAxis, _device, _rotationProviderAxis, _targetPositionList[0]) == RState.Running; }) .WaitWithStopConditionIf(RunRecipeStep.CheckInterRinse, _recipe.RinseBeforeEntryEnable, CheckInterRinseEndStatus, () => CommonFunction.CheckRoutineStopState(_interRinseRoutine)) //启动Rotation/Rotation 设置为entry 转速 .RunIf(RunRecipeStep.RotationStartEntry, !_recipe.RinseBeforeEntryEnable, RotationStartEntry, _delay_1ms) //没有intercal rinse 在entry开始的时候启动rotation .RunIf(RunRecipeStep.RotationChangeToEntrySpeed, _recipe.RinseBeforeEntryEnable, () => { return ChangeSpeed(_recipe.EntrySpinSpeed); }, _delay_1ms) //有intercal rinse 直接变速 //Angle tilt 操作 .Run(RunRecipeStep.AngleTilt, _device.HeadtTiltAction, () => { return _device.PlatingCellDeviceData.HeadTilt; }, _delay_1s) .Run(RunRecipeStep.VerticalGotoEntry, () => { return StartVertical("Entry", _recipe.EntryZoffset); }, _delay_1ms) .DelayIf(RunRecipeStep.WaitEntryCurrentProtectedFromRinse, !_recipe.RinseBeforeEntryEnable,CalculateVerticaMoveTime("Rinse","Entry") - 100 > 0 ? CalculateVerticaMoveTime("Rinse", "Entry"):0) .DelayIf(RunRecipeStep.WaitEntryCurrentProtectedFromHome, _recipe.RinseBeforeEntryEnable,CalculateVerticaMoveTime("Home","Entry") - 100 > 0 ? CalculateVerticaMoveTime("Home", "Entry") : 0) .End(RunRecipeStep.End, NullFun); return Runner.Status; } /// /// 计算vertical 从一个位置移动到另一个位置用时 /// /// /// /// 返回值单位毫秒 private int CalculateVerticaMoveTime(string sourceLocation,string destinationLocation) { Station sourceStation = _verticalBeckhoffStation.Stations.FirstOrDefault(p => p.Name == $"{_verticalEntity.Module}.{sourceLocation}"); Station destinationStation = _verticalBeckhoffStation.Stations.FirstOrDefault(p => p.Name == $"{_verticalEntity.Module}.{destinationLocation}"); Double.TryParse(sourceStation.Position, out double sourcePosition); Double.TryParse(destinationStation.Position, out double destinationPosition); double time = Math.Abs(destinationPosition - sourcePosition) / _verticalEntity.MotionData.ProfileVelocity * 10; if (time <= 0) { NotifyError(eEvent.WARN_PLATINGCELL, "Calculate Vertica Move Time is 0", 0); return 0; } return (int)time; } /// /// change speed /// /// private bool ChangeSpeed(int speed) //参数speed单位是rmp { double realSpeed = BeckhoffVelocityUtil.ConvertVelocityToDegPerSecondByRPM(speed); bool result = _rotationAxis.ChangeSpeed((int)realSpeed); if (!result) { NotifyError(eEvent.ERR_PLATINGCELL, "Change Speed failed", 0); return false; } return true; } private bool CheckInterRinseEndStatus() { bool result = CommonFunction.CheckRoutineEndState(_interRinseRoutine); SubRoutineStep = _interRinseRoutine.CurrentStep; return result; } /// /// rotation 从entry步骤开始旋转 /// /// private bool RotationStartEntry() { bool result = _rotationAxis.ProfilePosition(_targetPositionList[0], _recipe.IntervalRinseSpeed * SPEED_RATIO, 0, 0); if (!result) { NotifyError(eEvent.ERR_PLATINGCELL, "Start Rotation is failed", 0); return false; } return true; } /// /// vertical 运行 /// /// 目标位置名称 /// 偏移量 /// private bool StartVertical(string positionName,double offset) { double position = 0; Station station = _verticalBeckhoffStation.Stations.FirstOrDefault(p => p.Name == $"{_verticalEntity.Module}.{positionName}"); if (station != null) { if(!Double.TryParse(station.Position, out position)) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "vertical station position is error"); return false; } } else { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, $"vertical station {_verticalEntity.Module}.{positionName} is null"); return false; } return _verticalEntity.CheckToPostMessage(Aitex.Core.RT.Log.eEvent.INFO_PLATINGCELL, Module, (int)PlatingCellVerticalEntity.VerticalMsg.Position, position + offset); } /// /// 检验垂直电机是否运动完成 /// /// private bool CheckVerticalEnd() { return _verticalEntity.IsIdle; } /// /// 检验垂直是否出现错误 /// /// private bool CheckVerticalError() { return _verticalEntity.IsError; } /// /// 启动 /// /// /// public RState Start(params object[] objs) { _recipe = objs[0] as DepRecipe; 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; } //获取vertical entity string vertical = ModuleMatcherManager.Instance.GetPlatingVerticalByCell(Module); _verticalEntity = Singleton.Instance.GetModule(vertical); //获取platingcell eneity _platingCellEntity = Singleton.Instance.GetModule(Module); //获取对应reservoir eneity string reservoir = ReservoirItemManager.Instance.GetReservoirByPlatingCell(Module); _reservoirEntity = Singleton.Instance.GetModule(reservoir); //获取vertical station信息对象 _verticalBeckhoffStation = BeckhoffStationLocationManager.Instance.GetStationAxis($"{_verticalEntity.Module}", "Vertical"); if (!CheckPreCondition()) { return RState.Failed; } _currentCycle = 0; return Runner.Start(Module, "Run Recipe"); } /// /// 检验前置条件 /// /// private bool CheckPreCondition() { if (_recipe == null) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Recipe is null"); return false; } //if (_recipe.DepSteps.Count == 0) //{ // LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Recipe DepSteps count is 0"); // return false; //} CheckAxisHome(); CheckFacility(); CheckModuleAndReservoir(); 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.IsIdle) { 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 errro 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 errro range"); return false; } if (systemFacilities.FacilitiesDataDic["DiWaterPressure"].IsError) { LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module, "Facility Diw Pressure value is in errro range"); return false; } return true; } } }