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