using Aitex.Core.RT.Device;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using CyberX8_Core;
using CyberX8_RT.Devices.Facilities;
using CyberX8_RT.Devices.Metal;
using CyberX8_RT.Devices.PowerSupplier;
using CyberX8_RT.Devices.Reservoir;
using CyberX8_RT.Devices.Temperature;
using MECF.Framework.Common.Alarm;
using MECF.Framework.Common.CommonData;
using MECF.Framework.Common.CommonData.Metal;
using MECF.Framework.Common.CommonData.PowerSupplier;
using MECF.Framework.Common.Persistent.Reservoirs;
using MECF.Framework.Common.RecipeCenter;
using MECF.Framework.Common.Routine;
using MECF.Framework.Common.ToolLayout;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace CyberX8_RT.Modules.Metal
{
public class ReservoirRunRecipeRoutine : RoutineBase,IRoutine
{
#region 常量
private const int LOTTRACK_TIME = 1000;
private const string CDA_1_PRESSURE_VALUE = "CDA1Pressure";
private const string CDA_2_PRESSURE_VALUE = "CDA2Pressure";
private const string STRATUS = "Stratus";
#endregion
private enum RecipeStep
{
PlatingDelay,
PlatingDelayCheck,
HotPlating,
WaitPlatingDelay,
RunPowerStep,
RunPowerStepWait,
LoopStart,
LoopCheckRun,
LoopEnd,
StopLinmot,
StopPowerSuppliers,
SwitchToNormal,
WaferHolderUnclampOn,
End
}
#region 常量
private const string SIDE_A = "SideA";
private const string SIDE_B = "SideB";
#endregion
#region 内部变量
///
/// recipe
///
private DepRecipe _recipe;
///
/// Plate Delay时间
///
private DateTime _platingDelayTime = DateTime.Now;
///
/// 启动步骤时间
///
private DateTime _startStepTime = DateTime.Now;
///
/// 电量步骤计数
///
private Stopwatch _stepWatch = new Stopwatch();
///
/// Power 集合
///
List _powerSupplierStepPeriodDatas = new List();
///
/// 单面
///
private string _side;
///
/// 步骤索引
///
private int _stepIndex = 0;
///
/// 设备
///
private MetalCellDevice _device;
///
/// 设备Entity
///
private MetalEntity _metalEntity;
///
/// A面电量
///
private double _anodeAUsage;
///
/// B面电量
///
private double _anodeBUsage;
///
/// 是否启动recipe步骤
///
private bool _startRecipeStep = false;
///
/// lock track time
///
private DateTime _lotTackTime = DateTime.Now;
///
/// LotTrack数据
///
private List _datas = new List();
///
/// LotTrack文件头数据
///
private LotTrackFileHeaderCommonData _header = new LotTrackFileHeaderCommonData();
///
/// Facilities
///
private SystemFacilities _facilities;
///
/// StandardHot Reservoir Device
///
private StandardHotReservoirDevice _standardHotReservoirDevice;
///
/// StandardHot Metal Device
///
private StandardHotMetalDevice _standardHotMetalDevice;
///
/// CompactMembran Reservoir Device
///
private CompactMembranReservoirDevice _compactMembranReservoirDevice;
///
/// CompactMembran Reservoir Metal
///
private CompactMembranMetalDevice _compactMembranMetalDevice;
///
/// MetalType
///
private string _metalType;
///
/// TC device
///
private TemperatureController _temperatureController;
///
/// Persistent value
///
private MetalPersistentValue _persistentValue;
///
/// PlatingDelay计时
///
private DateTime _hotPlatingRunTime;
///
/// 是否处于warning状态
///
private bool _isVotlageWarningA = false;
private bool _isVotlageWarningB = false;
private bool _isCurrentWarningA = false;
private bool _isCurrentWarningB = false;
#endregion
#region 属性
///
/// A面电量
///
public double AnodeAUsage { get { return _anodeAUsage; } }
///
/// B面电量
///
public double AnodeBUsage { get { return _anodeBUsage; } }
///
/// LotTrack数据
///
public List MetalLotTrackDatas { get { return _datas; } }
///
/// LotTrack文件头数据
///
public LotTrackFileHeaderCommonData MetalLotTrackHeaderDatas { get { return _header; } }
#endregion
///
/// 构造函数
///
public ReservoirRunRecipeRoutine(string moduleName):base(moduleName)
{
}
///
/// 中止
///
public void Abort()
{
if (_device != null)
{
_device.SideAPowerSupplier.DisableOperation("", null);
_device.SideBPowerSupplier.DisableOperation("", null);
_device.SideAPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
_device.SideBPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
if (_device.IsLinmotMotorOn)
{
_device.StopLinmot();
}
}
Runner.Stop("Manual Abort");
}
///
/// 监控
///
///
public RState Monitor()
{
LottrackRecord();
Runner.Run(RecipeStep.PlatingDelay, PlatingDelay, _delay_1ms)
.WaitWithStopCondition(RecipeStep.PlatingDelayCheck,()=>{ return _device.CheckLinmotRoutineEnd(); }, () => { return _device.CheckLinmotRoutineError(); } )
.RunIf(RecipeStep.HotPlating, _recipe.HotPlatingCurrentOn, HotPlating, _delay_1ms)
.RunIf(RecipeStep.WaitPlatingDelay, !_recipe.HotPlatingCurrentOn, NullFun, WaitPlatingDelay, _recipe.PlatingDelaySeconds * 1000 + 10000)
.RunIf(RecipeStep.RunPowerStep, !_recipe.HotPlatingCurrentOn, StartPowerStep, _delay_1ms)
.WaitWithStopCondition(RecipeStep.RunPowerStepWait,CheckRecipeStepEndStatus,CheckRecipeStepStopStatus,_delay_5s)
.LoopStart(RecipeStep.LoopStart, "Loop update linmot speed", _powerSupplierStepPeriodDatas.Count, NullFun, _delay_1ms)
.LoopRunWithStopStatus(RecipeStep.LoopCheckRun, CheckStepComplete, () => { return false; })
.LoopEnd(RecipeStep.LoopEnd, NullFun, _delay_1ms)
.Run(RecipeStep.StopLinmot, StopLinmot, _delay_1ms)
.Run(RecipeStep.StopPowerSuppliers, StopPowerSupplier, _delay_1ms)
.Run(RecipeStep.SwitchToNormal, SwitchToNormal, _delay_1ms)
.End(RecipeStep.End, NullFun, _delay_1ms);
return Runner.Status;
}
///
/// 记录Lottrack
///
private void LottrackRecord()
{
//记录Lottrack
if (DateTime.Now.Subtract(_lotTackTime).TotalMilliseconds >= LOTTRACK_TIME)
{
AddLotTrackData();
_lotTackTime = DateTime.Now;
}
}
///
/// 获取Lot Track数据
///
///
public void AddLotTrackData()
{
MetalLotTrackData data = new MetalLotTrackData();
if(_metalType == STRATUS)
{
data.Flow = _standardHotMetalDevice.MetalDeviceData.CellFlow;
data.ANLevel = 0;
data.CALevel = _standardHotReservoirDevice.ReservoirData.Level;
data.CAPumpSpeed = 0;
}
else
{
data.Flow = _compactMembranMetalDevice.MetalDeviceData.CellFlow;
data.ANLevel = _compactMembranReservoirDevice.ReservoirData.ANLevel;
data.CALevel = _compactMembranReservoirDevice.ReservoirData.CALevel;
data.CAPumpSpeed = _compactMembranReservoirDevice.ReservoirData.CAPumpSpeed;
}
data.RunTime = 0;
data.ClampCycleEngaged = _recipe.CycleClampsEnable;
data.Temperature = _temperatureController.TemperatureData.ReserviorTemperature;
data.TimeStamp = DateTime.Now;
data.PowerSupplyA = _device.SideAPowerSupplier.Name;
data.PowerSupplyB = _device.SideBPowerSupplier.Name;
data.PosVoltageA = _device.SideAPowerSupplier.PowerSupplierData.Voltage;
data.PosCurrentA = _device.SideAPowerSupplier.PowerSupplierData.Current;
data.PosVoltageB = _device.SideBPowerSupplier.PowerSupplierData.Voltage;
data.PosCurrentB = _device.SideBPowerSupplier.PowerSupplierData.Current;
data.CDA_1_Pressure = _facilities.GetCommonLimitDataByName(CDA_1_PRESSURE_VALUE).Value;
data.CDA_2_Pressure = _facilities.GetCommonLimitDataByName(CDA_2_PRESSURE_VALUE).Value;
int maxStep = _powerSupplierStepPeriodDatas.Count;
if (_stepIndex < maxStep)
{
data.StepNum = _stepIndex + 1;
int length = _powerSupplierStepPeriodDatas[_stepIndex].Hour * 3600 + _powerSupplierStepPeriodDatas[_stepIndex].Minute * 60 +
_powerSupplierStepPeriodDatas[_stepIndex].Second;
data.DurationRef = length;
data.ShearPlateSpeed = _recipe.CurrentRampProfileSteps[_stepIndex].ShearPlateSpeed;
data.CurrentSP = _recipe.CurrentRampProfileSteps[_stepIndex].ForwardAmps;
}
else
{
data.StepNum = maxStep;
int length = _powerSupplierStepPeriodDatas[maxStep - 1].Hour * 3600 + _powerSupplierStepPeriodDatas[maxStep - 1].Minute * 60 +
_powerSupplierStepPeriodDatas[maxStep - 1].Second;
data.DurationRef = length;
data.ShearPlateSpeed = _recipe.CurrentRampProfileSteps[maxStep - 1].ShearPlateSpeed;
data.CurrentSP = _recipe.CurrentRampProfileSteps[maxStep - 1].ForwardAmps;
}
RecipeStep step = (RecipeStep)Runner.CurrentStep;
if (step <= RecipeStep.WaitPlatingDelay)
{
if (!_recipe.HotPlatingCurrentOn)
{
data.RunTime = DateTime.Now.Subtract(_hotPlatingRunTime).TotalSeconds;
data.DurationRef = _recipe.PlatingDelaySeconds;
data.StepNum = 0;
}
else
{
data.RunTime = 0;
data.DurationRef = _recipe.PlatingDelaySeconds;
data.StepNum = 0;
}
}
else
{
if (_recipe.HotPlatingCurrentOn)
{
if(DateTime.Now.Subtract(_hotPlatingRunTime).TotalSeconds <= _recipe.PlatingDelaySeconds)
{
data.RunTime = DateTime.Now.Subtract(_hotPlatingRunTime).TotalSeconds;
data.DurationRef = _recipe.PlatingDelaySeconds;
data.StepNum = 0;
}
else
{
if(data.StepNum == 1) data.DurationRef -= _recipe.PlatingDelaySeconds;
data.RunTime = (data.StepNum == 1)?(DateTime.Now.Subtract(_startStepTime).TotalSeconds - _recipe.PlatingDelaySeconds): DateTime.Now.Subtract(_startStepTime).TotalSeconds;
}
}
else
{
data.RunTime = DateTime.Now.Subtract(_startStepTime).TotalSeconds;
}
}
_datas.Add(data);
}
///
/// Plate Delay
///
///
private bool PlatingDelay()
{
double speed = _recipe.CurrentRampProfileSteps[0].ShearPlateSpeed;
bool result = _device.StartCurveMotion((int)speed);
if (result)
{
_platingDelayTime = DateTime.Now;
if(!_recipe.HotPlatingCurrentOn) _hotPlatingRunTime = DateTime.Now;
}
return result;
}
///
/// Hot Plating
///
///
private bool HotPlating()
{
UpdateHotPlatingStepDatas();
return StartPowerStep();
}
///
/// 启动PowerSupplier
///
///
private bool StartPowerStep()
{
if (string.IsNullOrEmpty(_side))
{
bool result = StartPowerStep(_device.SideAPowerSupplier);
if (result)
{
result = StartPowerStep(_device.SideBPowerSupplier);
if (!result)
{
_device.SideAPowerSupplier.DisableOperation("", null);
_device.SideBPowerSupplier.DisableOperation("", null);
return false;
}
else
{
_startStepTime = DateTime.Now;
_hotPlatingRunTime = DateTime.Now;
_stepWatch.Restart();
_startRecipeStep = true;
return true;
}
}
else
{
_device.SideAPowerSupplier.DisableOperation("", null);
return false;
}
}
else
{
CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
bool result = StartPowerStep(cellPowerSupplier);
if (!result)
{
cellPowerSupplier.DisableOperation("", null);
_stepWatch.Restart();
return false;
}
_startStepTime = DateTime.Now;
_hotPlatingRunTime = DateTime.Now;
_startRecipeStep = true;
return true;
}
}
///
/// 检验Powerstep是否启动完成
///
///
private bool CheckRecipeStepEndStatus()
{
if (_startRecipeStep)
{
if (string.IsNullOrEmpty(_side))
{
bool resultA = _device.SideAPowerSupplier.Status == RState.End;
bool resultB=_device.SideBPowerSupplier.Status == RState.End;
return resultA && resultB;
}
else
{
CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
return cellPowerSupplier.Status == RState.End;
}
}
return true;
}
///
/// 检验Powerstep是否启动完成
///
///
private bool CheckRecipeStepStopStatus()
{
if (_startRecipeStep)
{
if (string.IsNullOrEmpty(_side))
{
bool resultA = _device.SideAPowerSupplier.Status == RState.Failed||_device.SideAPowerSupplier.Status==RState.Timeout;
bool resultB = _device.SideBPowerSupplier.Status == RState.Failed||_device.SideBPowerSupplier.Status==RState.Timeout;
return resultA && resultB;
}
else
{
CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
return cellPowerSupplier.Status == RState.Failed||cellPowerSupplier.Status==RState.Timeout;
}
}
return false;
}
///
/// 获取单面PowerSupplier
///
///
private CellPowerSupplier GetSidePowerSupplier()
{
if (_side == SIDE_A)
{
return _device.SideAPowerSupplier;
}
else
{
return _device.SideBPowerSupplier;
}
}
///
/// 启动
///
///
private bool StartPowerStep(CellPowerSupplier cellPowerSupplier)
{
bool result = cellPowerSupplier.StartSetStepPeriodNoWaitEnd(_powerSupplierStepPeriodDatas);
if (!result)
{
cellPowerSupplier.DisableOperation("", null);
return false;
}
return true;
}
///
/// 更新HotPlating step数据
///
private void UpdateHotPlatingStepDatas()
{
ushort second = _powerSupplierStepPeriodDatas[0].Second;
ushort minute = _powerSupplierStepPeriodDatas[0].Minute;
ushort hour = _powerSupplierStepPeriodDatas[0].Hour;
if (second + _recipe.PlatingDelaySeconds >= 60)
{
if (minute + 1 < 60)
{
_powerSupplierStepPeriodDatas[0].Minute = (ushort)(minute + 1);
}
else
{
_powerSupplierStepPeriodDatas[0].Minute = 0;
_powerSupplierStepPeriodDatas[0].Hour = (ushort)(hour + 1);
}
_powerSupplierStepPeriodDatas[0].Second = (ushort)(second + _recipe.PlatingDelaySeconds - 60);
}
else
{
_powerSupplierStepPeriodDatas[0].Second = (ushort)(second + _recipe.PlatingDelaySeconds);
}
}
///
/// 更新Power step步骤
///
private void UpdatePowerStepDatas()
{
_powerSupplierStepPeriodDatas.Clear();
foreach (var item in _recipe.CurrentRampProfileSteps)
{
PowerSupplierStepPeriodData step = new PowerSupplierStepPeriodData();
step.Current = item.ForwardAmps;
step.Hour = (ushort)(item.CurrentRampDurartionSeconds / 3600);
step.Minute = (ushort)(item.CurrentRampDurartionSeconds / 60);
step.Second = (ushort)(item.CurrentRampDurartionSeconds % 60);
step.Microsecond = 0;
_powerSupplierStepPeriodDatas.Add(step);
}
}
///
/// 等待Plating Delay结束
///
///
private bool WaitPlatingDelay()
{
if (DateTime.Now.Subtract(_platingDelayTime).TotalSeconds >= _recipe.PlatingDelaySeconds)
{
return true;
}
return false;
}
///
/// 检验步骤是否完成
///
///
private bool CheckStepComplete()
{
if (_stepIndex >= _powerSupplierStepPeriodDatas.Count)
{
_stepWatch.Stop();
LOG.WriteLog(eEvent.INFO_METAL, Module, $"step {_stepIndex} is over step count {_powerSupplierStepPeriodDatas.Count}");
return true;
}
if (DateTime.Now.Subtract(_startStepTime).TotalMilliseconds >= 2000)
{
bool abnormal = CheckMetalDisable();
if (abnormal)
{
return false;
}
}
int length = _powerSupplierStepPeriodDatas[_stepIndex].Hour * 3600 + _powerSupplierStepPeriodDatas[_stepIndex].Minute * 60 +
_powerSupplierStepPeriodDatas[_stepIndex].Second;
if (DateTime.Now.Subtract(_startStepTime).TotalSeconds >= length)
{
_stepIndex++;
if (_stepIndex >= _powerSupplierStepPeriodDatas.Count)
{
_stepWatch.Stop();
LOG.WriteLog(eEvent.INFO_METAL, Module, $"step {_stepIndex} is over step count {_powerSupplierStepPeriodDatas.Count}");
return true;
}
bool result = _device.ChangeCurveSpeedMotion((int)_recipe.CurrentRampProfileSteps[_stepIndex].ShearPlateSpeed);
if (result)
{
LOG.WriteLog(eEvent.INFO_METAL, Module, $"step {_stepIndex} complete");
_startStepTime = DateTime.Now;
}
return result;
}
double second = (double)_stepWatch.ElapsedMilliseconds / 1000;
if (string.IsNullOrEmpty(_side))
{
_anodeAUsage += _device.SideAPowerSupplier.PowerSupplierData.Current * second / 3600;
_anodeBUsage += _device.SideBPowerSupplier.PowerSupplierData.Current * second / 3600;
}
else if(_side==SIDE_A)
{
_anodeAUsage += _device.SideAPowerSupplier.PowerSupplierData.Current * second / 3600;
}
else
{
_anodeBUsage += _device.SideBPowerSupplier.PowerSupplierData.Current * second / 3600;
}
_stepWatch.Restart();
return false;
}
///
/// 检验Power是否Disable
///
///
private bool CheckMetalDisable()
{
if (string.IsNullOrEmpty(_side))
{
if (!_device.SideAPowerSupplier.PowerSupplierData.Enabled)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerA disable");
Abort();
return true;
}
if (!_device.SideBPowerSupplier.PowerSupplierData.Enabled)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerB disable");
Abort();
return true;
}
}
else
{
if (_side == SIDE_A && !_device.SideAPowerSupplier.PowerSupplierData.Enabled)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerA disable");
Abort();
return true;
}
if (_side == SIDE_B && !_device.SideBPowerSupplier.PowerSupplierData.Enabled)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerB disable");
Abort();
return true;
}
}
if (!_device.IsLinmotMotorOn)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, "Linmot is not motor on");
Abort();
return true;
}
//CheckVotlageAndCurrent();
if (!CheckVoltageAndCurrentValid())
{
Abort();
return true;
}
return false;
}
///
/// 检验电压电流的合理性
///
///
private bool CheckVoltageAndCurrentValid()
{
double sideACurrent = _device.SideAPowerSupplier.PowerSupplierData.Current;
double sideAVoltage = _device.SideAPowerSupplier.PowerSupplierData.Voltage;
double sideBCurrent = _device.SideBPowerSupplier.PowerSupplierData.Current;
double sideBVoltage = _device.SideBPowerSupplier.PowerSupplierData.Voltage;
if (string.IsNullOrEmpty(_side))
{
bool sideAValid = CheckSidePowerInvalid(sideACurrent, sideAVoltage, SIDE_A);
if (sideAValid)
{
return false;
}
bool sideBValid = CheckSidePowerInvalid(sideBCurrent, sideBVoltage, SIDE_B);
if (sideBValid)
{
return false;
}
}
else
{
if (_side == SIDE_A)
{
bool sideAValid = CheckSidePowerInvalid(sideACurrent, sideAVoltage, SIDE_A);
if (sideAValid)
{
return false;
}
}
else
{
bool sideBValid = CheckSidePowerInvalid(sideBCurrent, sideBVoltage, SIDE_B);
if (sideBValid)
{
return false;
}
}
}
return true;
}
///
/// 监控电流和电压
///
private void CheckVotlageAndCurrent()
{
if (string.IsNullOrEmpty(_side))
{
//监控电压A面
MetalEntity metalEntity = Singleton.Instance.GetModule(Module);
if (_device.SideAPowerSupplier.PowerSupplierData.Voltage > _recipe.VoltageWarningLevel && _device.SideAPowerSupplier.PowerSupplierData.Voltage < _recipe.VolatageLimitMax && !_isVotlageWarningA)
{
_isVotlageWarningA = true;
LOG.WriteLog(eEvent.WARN_METAL, Module, $"Current SideA Votlage {_device.SideAPowerSupplier.PowerSupplierData.Voltage} is large than recipe VolatageWarningLevel {_recipe.VoltageWarningLevel}");
}
if (_device.SideAPowerSupplier.PowerSupplierData.Voltage < _recipe.VolatageLimitMin)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideA Votlage {_device.SideAPowerSupplier.PowerSupplierData.Voltage} is lower than recipe VolatageLimitMin {_recipe.VolatageLimitMin}");
}
if (_device.SideAPowerSupplier.PowerSupplierData.Voltage > _recipe.VolatageLimitMax)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideA Votlage {_device.SideAPowerSupplier.PowerSupplierData.Voltage} is large than recipe VolatageLimitMin {_recipe.VolatageLimitMax}");
}
//监控电流A面
double currentWarningFault = _powerSupplierStepPeriodDatas[_stepIndex].Current * _recipe.CurrentWarningLevel * 0.01;
double currentErrorFault = _powerSupplierStepPeriodDatas[_stepIndex].Current * _recipe.FaultPercent * 0.01;
if (_device.SideAPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault
|| _device.SideAPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideA Current {_device.SideAPowerSupplier.PowerSupplierData.Current} is not in " +
$"recipe Range {_powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault} ~ {_powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault}");
}
if (!_isCurrentWarningA && ((_device.SideAPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current + currentWarningFault && _device.SideAPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault)
|| (_device.SideAPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current - currentWarningFault && _device.SideAPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault)))
{
_isCurrentWarningA = true;
LOG.WriteLog(eEvent.WARN_METAL, Module, $"Current SideA Current {_device.SideAPowerSupplier.PowerSupplierData.Current} is not in " +
$"recipe Range {_powerSupplierStepPeriodDatas[_stepIndex].Current - currentWarningFault} ~ {_powerSupplierStepPeriodDatas[_stepIndex].Current + currentWarningFault}");
}
//监控电压B面
if (_device.SideBPowerSupplier.PowerSupplierData.Voltage > _recipe.VoltageWarningLevel && _device.SideBPowerSupplier.PowerSupplierData.Voltage < _recipe.VolatageLimitMax && !_isVotlageWarningB)
{
_isVotlageWarningB = true;
LOG.WriteLog(eEvent.WARN_METAL, Module, $"Current SideB Votlage {_device.SideBPowerSupplier.PowerSupplierData.Voltage} is large than recipe VolatageWarningLevel {_recipe.VoltageWarningLevel}");
}
if (_device.SideBPowerSupplier.PowerSupplierData.Voltage < _recipe.VolatageLimitMin)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideB Votlage {_device.SideBPowerSupplier.PowerSupplierData.Voltage} is lower than recipe VolatageLimitMin {_recipe.VolatageLimitMin}");
}
if (_device.SideBPowerSupplier.PowerSupplierData.Voltage > _recipe.VolatageLimitMax)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideB Votlage {_device.SideBPowerSupplier.PowerSupplierData.Voltage} is large than recipe VolatageLimitMin{_recipe.VolatageLimitMax}");
}
//监控电流B面
if (_device.SideBPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault
|| _device.SideBPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideB Current {_device.SideBPowerSupplier.PowerSupplierData.Current} is not in " +
$"recipe Range {_powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault} ~ {_powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault}");
}
if (!_isCurrentWarningB && ((_device.SideBPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current + currentWarningFault && _device.SideBPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault)
|| (_device.SideBPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current - currentWarningFault && _device.SideBPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault)))
{
_isCurrentWarningB = true;
LOG.WriteLog(eEvent.WARN_METAL, Module, $"Current SideB Current {_device.SideBPowerSupplier.PowerSupplierData.Current} is not in " +
$"recipe Range {_powerSupplierStepPeriodDatas[_stepIndex].Current - currentWarningFault} ~ {_powerSupplierStepPeriodDatas[_stepIndex].Current + currentWarningFault}");
}
}
else
{
if (_side == SIDE_A)
{
//监控电压A面
MetalEntity metalEntity = Singleton.Instance.GetModule(Module);
if (_device.SideAPowerSupplier.PowerSupplierData.Voltage > _recipe.VoltageWarningLevel && _device.SideAPowerSupplier.PowerSupplierData.Voltage < _recipe.VolatageLimitMax && !_isVotlageWarningA)
{
_isVotlageWarningA = true;
LOG.WriteLog(eEvent.WARN_METAL, Module, $"Current SideA Votlage {_device.SideAPowerSupplier.PowerSupplierData.Voltage} is large than recipe VolatageWarningLevel {_recipe.VoltageWarningLevel}");
}
if (_device.SideAPowerSupplier.PowerSupplierData.Voltage < _recipe.VolatageLimitMin)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideA Votlage {_device.SideAPowerSupplier.PowerSupplierData.Voltage} is lower than recipe VolatageLimitMin {_recipe.VolatageLimitMin}");
}
if (_device.SideAPowerSupplier.PowerSupplierData.Voltage > _recipe.VolatageLimitMax)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideA Votlage {_device.SideAPowerSupplier.PowerSupplierData.Voltage} is large than recipe VolatageLimitMin {_recipe.VolatageLimitMax}");
}
//监控电流A面
double currentWarningFault = _powerSupplierStepPeriodDatas[_stepIndex].Current * _recipe.CurrentWarningLevel * 0.01;
double currentErrorFault = _powerSupplierStepPeriodDatas[_stepIndex].Current * _recipe.FaultPercent * 0.01;
if (_device.SideAPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault
|| _device.SideAPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideA Current {_device.SideAPowerSupplier.PowerSupplierData.Current} is not in " +
$"recipe Range {_powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault} ~ {_powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault}");
}
if (!_isCurrentWarningA && ((_device.SideAPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current + currentWarningFault && _device.SideAPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault)
|| (_device.SideAPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current - currentWarningFault && _device.SideAPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault)))
{
_isCurrentWarningA = true;
LOG.WriteLog(eEvent.WARN_METAL, Module, $"Current SideA Current {_device.SideAPowerSupplier.PowerSupplierData.Current} is not in " +
$"recipe Range{_powerSupplierStepPeriodDatas[_stepIndex].Current - currentWarningFault} ~ {_powerSupplierStepPeriodDatas[_stepIndex].Current + currentWarningFault}");
}
}
else
{
//监控电压B面
MetalEntity metalEntity = Singleton.Instance.GetModule(Module);
if (!_isVotlageWarningB && _device.SideBPowerSupplier.PowerSupplierData.Voltage > _recipe.VoltageWarningLevel && _device.SideBPowerSupplier.PowerSupplierData.Voltage < _recipe.VolatageLimitMax)
{
_isVotlageWarningB = true;
LOG.WriteLog(eEvent.WARN_METAL, Module, $"Current SideB Votlage {_device.SideBPowerSupplier.PowerSupplierData.Voltage} is large than recipe VolatageWarningLevel {_recipe.VoltageWarningLevel}");
}
if (_device.SideBPowerSupplier.PowerSupplierData.Voltage < _recipe.VolatageLimitMin)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideB Votlage {_device.SideBPowerSupplier.PowerSupplierData.Voltage} is lower than recipe VolatageLimitMin {_recipe.VolatageLimitMin}");
}
if (_device.SideBPowerSupplier.PowerSupplierData.Voltage > _recipe.VolatageLimitMax)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideB Votlage {_device.SideBPowerSupplier.PowerSupplierData.Voltage} is large than recipe VolatageLimitMin {_recipe.VolatageLimitMax}");
}
//监控电流B面
double currentWarningFault = _powerSupplierStepPeriodDatas[_stepIndex].Current * _recipe.CurrentWarningLevel * 0.01;
double currentErrorFault = _powerSupplierStepPeriodDatas[_stepIndex].Current * _recipe.FaultPercent * 0.01;
if (_device.SideBPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault
|| _device.SideBPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault)
{
if (metalEntity != null)
{
metalEntity.PostMsg(MetalMsg.Error);
}
Abort();
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Current SideB Current {_device.SideBPowerSupplier.PowerSupplierData.Current} is not in " +
$"recipe Range{_powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault} ~ {_powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault}");
}
if (!_isCurrentWarningB && ((_device.SideBPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current + currentWarningFault && _device.SideBPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current + currentErrorFault)
|| (_device.SideBPowerSupplier.PowerSupplierData.Current < _powerSupplierStepPeriodDatas[_stepIndex].Current - currentWarningFault && _device.SideBPowerSupplier.PowerSupplierData.Current > _powerSupplierStepPeriodDatas[_stepIndex].Current - currentErrorFault)))
{
_isCurrentWarningB = true;
LOG.WriteLog(eEvent.WARN_METAL, Module, $"Current SideB Current {_device.SideBPowerSupplier.PowerSupplierData.Current} is not in " +
$"recipe Range {_powerSupplierStepPeriodDatas[_stepIndex].Current - currentWarningFault} ~ {_powerSupplierStepPeriodDatas[_stepIndex].Current + currentWarningFault}");
}
}
}
}
///
/// 检验电流和电压合理性
///
///
///
///
///
private bool CheckSidePowerInvalid(double current,double voltage,string side)
{
double maxVoltage = _recipe.VolatageLimitMax;
double warnVoltage = _recipe.VoltageWarningLevel;
double minVoltage=_recipe.VolatageLimitMin;
if (voltage > maxVoltage)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} voltage {voltage} is large than recipe max voltage {maxVoltage}");
return true;
}
if (voltage < minVoltage)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} voltage {voltage} is less than recipe min voltage {minVoltage}");
return true;
}
if (voltage > warnVoltage)
{
string str = $"{side} voltage is {voltage} in warning";
if (AlarmListManager.Instance.AddWarn(Module, $"{side} voltage", str))
{
LOG.WriteLog(eEvent.WARN_PREWET, Module, str);
}
}
double maxErrorCurrent = _powerSupplierStepPeriodDatas[_stepIndex].Current * (double)(1 + _recipe.FaultPercent * 0.01);
double minErrorCurrent = _powerSupplierStepPeriodDatas[_stepIndex].Current * (double)(1 - _recipe.FaultPercent * 0.01);
double maxWarnCurrent = _powerSupplierStepPeriodDatas[_stepIndex].Current * (double)(1 + _recipe.CurrentWarningLevel * 0.01);
double minWarnCurrent = _powerSupplierStepPeriodDatas[_stepIndex].Current * (double)(1 - _recipe.CurrentWarningLevel * 0.01);
if (current > maxErrorCurrent)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} current {current} is large than recipe max current {maxErrorCurrent}");
return true;
}
if (current < minErrorCurrent)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} current {current} is less than recipe min current {minErrorCurrent}");
return true;
}
if ((current <= maxErrorCurrent && current >= maxWarnCurrent) || (current >= minErrorCurrent && current <= minWarnCurrent))
{
string str = $"{side} current {current} is in warning";
if (AlarmListManager.Instance.AddWarn(Module, $"{side} current", str))
{
LOG.WriteLog(eEvent.WARN_PREWET, Module, str);
}
}
return false;
}
///
/// 停止Linmot
///
///
private bool StopLinmot()
{
return _device.StopLinmot();
}
///
/// 停止电源
///
///
private bool StopPowerSupplier()
{
if (string.IsNullOrEmpty(_side))
{
_device.SideAPowerSupplier.DisableOperation("", null);
_device.SideBPowerSupplier.DisableOperation("", null);
}
else
{
CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
cellPowerSupplier.DisableOperation("", null);
}
return true;
}
///
/// 切换成正常模式
///
///
private bool SwitchToNormal()
{
if (string.IsNullOrEmpty(_side))
{
_device.SideAPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
_device.SideBPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
}
else
{
CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
cellPowerSupplier.SwitchPowerRunModel((int)PowerRunModelEnum.Normal);
}
return true;
}
///
/// 启动
///
///
///
public RState Start(params object[] objs)
{
_isVotlageWarningA = false;
_isVotlageWarningB = false;
_isCurrentWarningA = false;
_isCurrentWarningB = false;
_recipe = objs[0] as DepRecipe;
if (_recipe == null)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, "recipe is null");
return RState.Failed;
}
if (objs.Length > 1)
{
_side = objs[1].ToString();
}
_startRecipeStep = false;
_anodeAUsage = 0;
_anodeBUsage = 0;
_device = DEVICE.GetDevice(Module);
_metalEntity = Singleton.Instance.GetModule(Module);
UpdatePowerStepDatas();
_stepIndex = 0;
_header.SoftWareVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
_header.Recipe = $"{_recipe.Ppid}.dep.rcp";
if(SC.ContainsItem("System.ToolID")) _header.ToolID = SC.GetStringValue("System.ToolID");
//lotTract记录SequenceRecipe
MetalEntity metalEntity = Singleton.Instance.GetModule(Module);
if (metalEntity.WaferHolderInfo != null && metalEntity.WaferHolderInfo.SequenceRecipe != null && !String.IsNullOrEmpty(metalEntity.WaferHolderInfo.SequenceRecipe.Ppid.ToString()))
{
_header.SequenceRecipe = metalEntity.WaferHolderInfo.SequenceRecipe.Ppid.ToString();
_header.ProcessTransferList = new List();
_header.ProcessTransferList.AddRange(metalEntity.WaferHolderInfo.SchedulerModules);
metalEntity.WaferHolderInfo.SchedulerModules.Clear();
}
_facilities = DEVICE.GetDevice("System.Facilities");
if (_facilities == null)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, "Facility is null");
return RState.Failed;
}
string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module);
MetalItem metalItem = MetalItemManager.Instance.GetMetalItem(Module);
_metalType = metalItem.SubType;
if (_metalType == STRATUS)
{
_standardHotReservoirDevice = DEVICE.GetDevice(reservoirName);
_standardHotMetalDevice = DEVICE.GetDevice(Module);
if (_standardHotReservoirDevice == null || _standardHotMetalDevice == null)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, $"metal or reservoir device is null");
return RState.Failed;
}
}
else
{
_compactMembranReservoirDevice = DEVICE.GetDevice(reservoirName);
_compactMembranMetalDevice = DEVICE.GetDevice(Module);
if(_compactMembranMetalDevice == null || _compactMembranReservoirDevice == null)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, $"metal or reservoir device is null");
return RState.Failed;
}
}
ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(reservoirName);
_temperatureController = DEVICE.GetDevice(reservoirItem.TCID);
if (_temperatureController == null)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, $"Temperature controller is null");
return RState.Failed;
}
_persistentValue = MetalPersistentManager.Instance.GetMetalPersistentValue(Module);
if (_persistentValue == null)
{
LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} Persistent Value Object is not exist");
return RState.Failed;
}
_datas.Clear();
_lotTackTime = DateTime.Now;
return Runner.Start(Module, "Metal run recipe");
}
}
}