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