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
LoopCheckVerticalReclaimStation,
ReclaimStartRotation,
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.LoopCheckVerticalReclaimStation, _matchPlatingCellEntity.IsInRecipe,
() => CheckVerticalInStation("Reclaim", _matchPlatingCellDepDeprecipe.ReclaimZoffset), () => { return _matchPlatingCellEntity.IsError; })
.LoopRunIf(RunRecipeStep.ReclaimStartRotation, _matchPlatingCellEntity.IsInRecipe && !_recipe.RinseBeforeEntryEnable, () => { return StartReclaimRotation(LARGETARGETPOSITION); }, _delay_1ms)
.LoopRunIf(RunRecipeStep.ReclaimChangeRotationSpeed, _matchPlatingCellEntity.IsInRecipe && _recipe.RinseBeforeEntryEnable, () => { 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开始旋转以Reclaim时的转速
///
///
///
private bool StartReclaimRotation(int targetPosition)
{
bool result = _rotationAxis.ProfilePosition(targetPosition, _recipe.ReclaimSpeed * 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 > 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;
}
//获取相匹配的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;
}
}
}