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.CommonData.PowerSupplier; 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.Devices.PowerSupplier; using PunkHPX8_RT.Modules.Reservoir; using SecsGem.Core.ItemModel; using System; using System.Collections.Generic; using System.Diagnostics; 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 { LoopStart, InterRinse, CheckInterRinse, Entry, CheckEntry, Deposition, CheckDeposition, Reclaim, CheckReclaim, Rinse, CheckRinse, Dry, CheckDry, LoopEnd, 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; ///是否选中dummy load /// private bool _isDummyLoad; /// cycle次数 /// private int _cycle; /// /// 当前完成的Cycle次数 /// private int _currentCycle; /// /// platingcell entity /// private PlatingCellEntity _platingCellEntity; /// /// 对应reservoir entity /// private ReservoirEntity _reservoirEntity; /// /// vertical axis entity /// private PlatingCellVerticalEntity _verticalEntity; /// /// vertical 轴的位置数据 /// private BeckhoffStationAxis _verticalBeckhoffStation; /// /// recipe中是否存在电机反转 /// private bool _isRecipeContainsRevserseRotation = false; /// /// run recipe 过程中电机会停的位置(需要根据recipe计算出来) /// private List _targetPositionList = new List(); #region 电镀通电相关 /// /// 不通电 /// private bool _isZeroCurrent = false; /// /// Power step集合 /// List _powerSupplierStepPeriodDatas = new List(); /// /// 记录dep recipe中出现的最大电流,用于启动电源前切换挡位 /// private double _maxCurrent = 0; /// /// 通电总时长 /// private int _totalMicrosecond = 0; /// /// Plating启动时间 /// private DateTime _platingStartTime; #endregion #region routine /// /// interbal rinse routien /// private PlatingCellInterRinseRoutine _interRinseRoutine; /// /// entry routien /// private PlatingCellEntryRoutine _entryRoutine; /// /// entry routien /// private PlatingCellDepositionRoutine _depositionRoutine; /// /// reclaim routien /// private PlatingCellReclaimRoutine _reclaimRoutine; /// /// Rinse routien /// private PlatingCellRinseRoutine _rinseRoutine; /// /// Dry routien /// private PlatingCellDryRoutine _dryRoutine; #endregion #region 属性 #endregion #endregion /// /// 构造函数 /// /// public PlatingCellRunRecipeRoutine(string module) : base(module) { _interRinseRoutine = new PlatingCellInterRinseRoutine(module); _entryRoutine = new PlatingCellEntryRoutine(module); _depositionRoutine = new PlatingCellDepositionRoutine(module); _reclaimRoutine = new PlatingCellReclaimRoutine(module); _rinseRoutine = new PlatingCellRinseRoutine(module); _dryRoutine = new PlatingCellDryRoutine(module); } /// /// 中止 /// public void Abort() { Runner.Stop("Manual Abort"); } /// /// 监控 /// /// public RState Monitor() { Runner.LoopStart(RunRecipeStep.LoopStart, "Loop Start Cycle Run Platingcell Recipe Routine", _cycle, NullFun, _delay_1ms) //interval rinse .LoopRunIf(RunRecipeStep.InterRinse, _recipe.RinseBeforeEntryEnable, () => { return _interRinseRoutine.Start(_recipe, _targetPositionList[0]) == RState.Running; }) .LoopRunIfWithStopStatus(RunRecipeStep.CheckInterRinse, _recipe.RinseBeforeEntryEnable, CheckInterRinseEndStatus, () => CommonFunction.CheckRoutineStopState(_interRinseRoutine)) //entry .LoopRun(RunRecipeStep.Entry, () => { return _entryRoutine.Start(_recipe, _targetPositionList[0], _powerSupplierStepPeriodDatas,_platingStartTime) == RState.Running; }) .LoopRunWithStopStatus(RunRecipeStep.CheckEntry, CheckEntryEndStatus, () => CommonFunction.CheckRoutineStopState(_entryRoutine)) //Deposition .LoopRun(RunRecipeStep.Deposition, () => { return _depositionRoutine.Start(_recipe, _isZeroCurrent, _isRecipeContainsRevserseRotation,_powerSupplierStepPeriodDatas, _platingStartTime) == RState.Running; }) .LoopRunWithStopStatus(RunRecipeStep.CheckDeposition, CheckDepositionEndStatus, () => CommonFunction.CheckRoutineStopState(_depositionRoutine)) //Reclaim .LoopRun(RunRecipeStep.Reclaim, () => { return _reclaimRoutine.Start(_recipe, _isZeroCurrent) == RState.Running; }) .LoopRunWithStopStatus(RunRecipeStep.CheckReclaim, CheckReclaimEndStatus, () => CommonFunction.CheckRoutineStopState(_reclaimRoutine)) //Rinse .LoopRun(RunRecipeStep.Rinse, () => { return _rinseRoutine.Start(_recipe) == RState.Running; }) .LoopRunWithStopStatus(RunRecipeStep.CheckRinse, CheckRinseEndStatus, () => CommonFunction.CheckRoutineStopState(_rinseRoutine)) //Dry .LoopRun(RunRecipeStep.Dry, () => { return _dryRoutine.Start(_recipe) == RState.Running; }) .LoopRunWithStopStatus(RunRecipeStep.CheckDry, CheckDryEndStatus, () => CommonFunction.CheckRoutineStopState(_dryRoutine)) .LoopEnd(RunRecipeStep.LoopEnd, UpdateCycleCount, _delay_1ms) .End(RunRecipeStep.End, NullFun); return Runner.Status; } /// 统计完成的Cycle次数 /// /// private bool UpdateCycleCount() { _currentCycle += 1; return true; } /// /// 获取当前Cycle次数 /// /// public int GetCurrentCycle() { return _currentCycle; } /// /// 检查interval rinse是否完成 /// /// private bool CheckInterRinseEndStatus() { bool result = CommonFunction.CheckRoutineEndState(_interRinseRoutine); SubRoutineStep = _interRinseRoutine.CurrentStep; return result; } /// /// 检查entry是否完成 /// /// private bool CheckEntryEndStatus() { bool result = CommonFunction.CheckRoutineEndState(_entryRoutine); SubRoutineStep = _entryRoutine.CurrentStep; return result; } /// /// 检查Deposition是否完成 /// /// private bool CheckDepositionEndStatus() { bool result = CommonFunction.CheckRoutineEndState(_depositionRoutine); SubRoutineStep = _depositionRoutine.CurrentStep; return result; } /// /// 检查Reclaim是否完成 /// /// private bool CheckReclaimEndStatus() { bool result = CommonFunction.CheckRoutineEndState(_reclaimRoutine); SubRoutineStep = _reclaimRoutine.CurrentStep; return result; } /// /// 检查Rinse是否完成 /// /// private bool CheckRinseEndStatus() { bool result = CommonFunction.CheckRoutineEndState(_rinseRoutine); SubRoutineStep = _rinseRoutine.CurrentStep; return result; } /// /// 检查Dry是否完成 /// /// private bool CheckDryEndStatus() { bool result = CommonFunction.CheckRoutineEndState(_dryRoutine); SubRoutineStep = _dryRoutine.CurrentStep; return result; } /// /// 启动 /// /// /// 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) { _isDummyLoad = (bool)objs[1]; } if (objs.Length > 2) { _cycle = (int)objs[2]; } _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; } CalculatVerticalPosition(_recipe); if (!UpdatePowerStepDatas()) { NotifyError(eEvent.ERR_PLATINGCELL, $"Update Power StepDatas Failed!", 0); return RState.Failed; } _currentCycle = 0; return Runner.Start(Module, "PlatingCell Run Recipe"); } /// /// 初始化Power step步骤 /// private bool UpdatePowerStepDatas() { _isZeroCurrent = false; _isRecipeContainsRevserseRotation = false; double current = 0; _totalMicrosecond = 0; _powerSupplierStepPeriodDatas.Clear(); if (!_recipe.IsEntryTypeCold)//如果entry带上电保护,那么把上电保护的部分加到步阶电流的第一步 { PowerSupplierStepPeriodData step = new PowerSupplierStepPeriodData(); //上电保护时间(提前上电时间+延迟时间) step.Hour = 0; step.Minute = (ushort)((_recipe.PlatingDelay) / 60); step.Second = (ushort)(_recipe.PlatingDelay % 60); step.Microsecond = 110; //到达entry位置提前100ms上电,提前一丢丢 step.Voltage = _recipe.DepMaxVoltageWarning; _powerSupplierStepPeriodDatas.Add(step); } foreach (var item in _recipe.DepSteps) { PowerSupplierStepPeriodData step = new PowerSupplierStepPeriodData(); step.Current = item.CurrentValue; if(item.CurrentValue > _maxCurrent) { _maxCurrent = item.CurrentValue; } step.Hour = (ushort)(item.DurartionSeconds / 3600); step.Minute = (ushort)((item.DurartionSeconds - step.Hour * 3600) / 60); step.Second = (ushort)(item.DurartionSeconds % 60); step.Microsecond = 0; step.Voltage = _recipe.DepMaxVoltageWarning; _powerSupplierStepPeriodDatas.Add(step); current += step.Current; _totalMicrosecond += item.DurartionSeconds * 1000; } if (current == 0) { _isZeroCurrent = true; } if(_maxCurrent > 0.6) //设置电源挡位,有超过0.6A的电流则用高档,否则用中挡 { return _device.PowerSupplier.SetPowerGrade("set power grade high", new object[] { (byte)2 }); } else { return _device.PowerSupplier.SetPowerGrade("set power grade middle", new object[] { (byte)1 }); } } /// /// 根据dep recipe计算出整个电镀过程中Rotation profile position可能去到的位置 /// private void CalculatVerticalPosition(DepRecipe recipe) { foreach(var item in recipe.DepSteps) { if (item.BiDireaction) { _isRecipeContainsRevserseRotation = true; } else { continue; } } _targetPositionList.Add(12 * 60 * 60 * 500 * 6); //以500rmp 运行12个小时的位置 } /// /// 检验前置条件 /// /// 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; //} 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.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 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; } } }