using Aitex.Core.RT.Device;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.RecipeCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.Common.RecipeCenter;
using MECF.Framework.Common.Routine;
using MECF.Framework.Common.Utilities;
using CyberX8_Core;
using CyberX8_RT.Devices.Resistivity;
using CyberX8_RT.Devices.Rinse;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CyberX8_RT.Modules.Rinse
{
public class RinseThirdStepRoutine:RoutineBase,IRoutine
{
private enum RinseThirdStep
{
Recipe_StartThirdRinseCycle,
Recipe_ThirdRinseStartFilling,
Recipe_ThirdRinseRecordStartWaterLevel,
Recipe_ThirdRinseStartFillingWait,
Recipe_ThirdRinseWaitFillingDetected,
Recipe_ThirdRinseWaitFull,
Recipe_ThirdRinseWaitEndFillTime,
Recipe_ThirdRinseWaitResistivityStart,
Recipe_ThirdRinseResistivityAveraging,
Recipe_ThirdRinseCheckResistivity,
Recipe_StartThirdRinseClampCycle,
Recipe_ThirdRinseWaitClampTime,
Recipe_ThirdRinseCycleClampOff,
Recipe_ThirdRinseCycleClampOn,
Recipe_ThirdRinseCycleWaitSlowDrainTime,
Recipe_ThirdRinseCycleEnd,
Recipe_ThirdRinseWaitDrain,
Recipe_ThirdRinseCheckDrain,
Recipe_ThirdRinseWaitDrainExtraTime,
Recipe_ThirdRinseComplete,
Recipe_Complete,
}
#region 内部变量
///
/// 设备对象
///
private RinseDevice _device;
///
/// Recipe
///
private QdrRecipe _recipe;
///
/// Fill打开注水记录Water Level
///
private double _fillingDetectStartWaterLevel;
///
/// Concurrent Fill Time Seconds
///
private int _concurrentFillTimeSeconds;
///
/// 开始注水的偏差
///
private double _fillingStartedDelta;
///
/// 注满数值
///
private int _sensorReadingFull;
///
/// 液位为空数值
///
private int _sensorReadingEmpty;
///
/// 开始流水时间
///
private DateTime _startFillTime;
///
/// Clamp开关等待时间
///
private double _clampCycleTimeSeconds;
///
/// 从开始排水到检测是否排空的间隔时间
///
private int _normalDrainTimeSeconds;
///
/// Clamp Cycle开关次数
///
private int _numberClampCyclesToComplete;
///
/// Resistivity取值样本列表
///
private List _resistivitySample = new List();
///
/// 开始注水后检测是否正常注水间隔
///
private int _checkIsFillingTimeSeconds;
///
/// 开始注水后检测是否注满间隔
///
private int _checkIsFullTimeSeconds;
/// 采样水阻值次数
///
private int _readResistivityCount = 0;
///
/// 当前执行到哪一步的显示
///
private string _currentStateMachine;
///
/// 开始采样时间
///
private DateTime _startSampleTime = DateTime.Now;
///
/// 采样时间
///
private DateTime _sampeIntervalTime = DateTime.Now;
///
/// 启动采样
///
private bool _startSample = false;
#endregion
///
/// 构造函数
///
///
public RinseThirdStepRoutine(string module) : base(module)
{
}
///
/// 启动
///
///
///
public RState Start(params object[] objects)
{
_startSample = false;
_resistivitySample.Clear();
_device = DEVICE.GetDevice(Module);
_recipe = objects[0] as QdrRecipe;
_concurrentFillTimeSeconds = SC.GetValue("QDR.ConcurrentFillTimeSeconds");
_fillingStartedDelta = SC.GetValue("QDR.FillingStartedDelta");
_sensorReadingFull = SC.GetValue("QDR.SensorReadingFull");
_sensorReadingEmpty = SC.GetValue("QDR.SensorReadingEmpty");
_clampCycleTimeSeconds = SC.GetValue("QDR.ClampCycleTimeSeconds");
_numberClampCyclesToComplete = SC.GetValue("QDR.NumberClampCyclesToComplete");
_normalDrainTimeSeconds = SC.GetValue("QDR.NominalDrainTimeSeconds");
_checkIsFillingTimeSeconds = SC.GetValue("QDR.NominalCheckFillWaterTimeSeconds");
_checkIsFullTimeSeconds = SC.GetValue("QDR.NominalCheckFillFullTimeSeconds");
//配置项规范性验证
if (_checkIsFillingTimeSeconds + _checkIsFullTimeSeconds > _concurrentFillTimeSeconds)
{
NotifyError(eEvent.ERR_RINSE, $"configuration item 'QDR.NominalCheckFillWaterTimeSeconds' plus 'QDR.NominalCheckFillFullTimeSeconds' is large than QDR.ConcurrentFillTimeSeconds", 0);
return RState.Failed;
}
if (_normalDrainTimeSeconds > _recipe.DumpTimeSeconds)
{
NotifyError(eEvent.ERR_RINSE, $"configuration item 'QDR.NominalDrainTimeSeconds' is large than 'recipe.DumpTimeSeconds",0);
return RState.Failed;
}
return Runner.Start(Module, "Start Rinse Third Step");
}
///
/// 监控
///
///
public RState Monitor()
{
_currentStateMachine = Runner.CurrentStep.ToString();
_device.UpdateStateMachine(_currentStateMachine);
//3.6-StartThirdRinseCycle
Runner.Run(RinseThirdStep.Recipe_StartThirdRinseCycle, OpenN2ValveAndCloseDumpValve, _delay_1ms)
//3.7-ThirdRinseStartFilling
.Run(RinseThirdStep.Recipe_ThirdRinseStartFilling, () => _device.FillValveOn(), _delay_1ms)
.Run(RinseThirdStep.Recipe_ThirdRinseRecordStartWaterLevel, CheckFillValveOn, _delay_1ms)
.RunDelay(RinseThirdStep.Recipe_ThirdRinseStartFillingWait, CheckFillNormalStatus, _checkIsFillingTimeSeconds *1000)
//3.8-ThirdRinseWaitFillingDetected and 3.9-ThirdRinseWaitFull
.RunDelay(RinseThirdStep.Recipe_ThirdRinseWaitFillingDetected, CheckFillFullStatus, _checkIsFullTimeSeconds *1000)
//.Run(RinseThirdStep.Recipe_ThirdRinseWaitFull, CheckFillFullStatus, _delay_1s)
//4.0-ThirdRinseWaitEndFillTime
.Delay(RinseThirdStep.Recipe_ThirdRinseWaitEndFillTime, (_concurrentFillTimeSeconds - _checkIsFillingTimeSeconds - _checkIsFullTimeSeconds) * 1000)
//4.1-ThirdRinseWaitResistivityStart
.Run(RinseThirdStep.Recipe_ThirdRinseWaitResistivityStart, ResistivityStart, _recipe.ResistivityStartTimeSeconds*1000)
//4.2-ThirdRinseResistivityAveraging
.Run(RinseThirdStep.Recipe_ThirdRinseResistivityAveraging, ResistivityAveraging,_delay_1ms)
//4.3-ThirdRinseCheckResistivity
.Wait(RinseThirdStep.Recipe_ThirdRinseCheckResistivity, ResitivitySampleResitivity, _recipe.ResistivityDurationSeconds * 1000)
//4.4-ThirdRinseWaitClampTime
.Delay(RinseThirdStep.Recipe_ThirdRinseWaitClampTime, (_recipe.FinalRinsePulseClampTime - _recipe.ResistivityStartTimeSeconds - _recipe.ResistivityDurationSeconds) * 1000)
.LoopStart(RinseThirdStep.Recipe_StartThirdRinseClampCycle, "Clamp On/Off Cycle", _numberClampCyclesToComplete, NullFun, _delay_1ms)
//4.5-ThirdRinseCycleClampOff
.LoopRun(RinseThirdStep.Recipe_ThirdRinseCycleClampOff, () => _device.WaferHolderClampValveOff(), (int)_clampCycleTimeSeconds*1000)
//4.6-ThirdRinseCycleClampOn
.LoopRun(RinseThirdStep.Recipe_ThirdRinseCycleClampOn, () => _device.WaferHolderClampValveOn(), (int)_clampCycleTimeSeconds * 1000)
.LoopEnd(RinseThirdStep.Recipe_ThirdRinseCycleEnd, NullFun, _delay_1ms)
//4.8-ThirdRinseCycleWaitSlowDrainTime
.Delay(RinseThirdStep.Recipe_ThirdRinseCycleWaitSlowDrainTime,(_recipe.FinalRinseSlowDrainTime - (int)_clampCycleTimeSeconds * 2 * _numberClampCyclesToComplete) * 1000)
//4.9-ThirdRinseWaitDrain
.Run(RinseThirdStep.Recipe_ThirdRinseWaitDrain, StartOpenDumpValve, _delay_1ms)
.RunDelay(RinseThirdStep.Recipe_ThirdRinseCheckDrain, CheckWaterLevelEmpty, _normalDrainTimeSeconds * 1000)
//5.0-ThirdRinseWaitDrainExtraTime
.RunIf(RinseThirdStep.Recipe_ThirdRinseWaitDrainExtraTime, _recipe.DumpTimeSeconds - _normalDrainTimeSeconds > 0, NullFun, (_recipe.DumpTimeSeconds - _normalDrainTimeSeconds) * 1000)
//5.1-Recipe_Complete
.Run(RinseThirdStep.Recipe_ThirdRinseComplete, () => _device.WasteValveOff(), _delay_1ms)
.End(RinseThirdStep.Recipe_Complete, NullFun, _delay_1ms);
return Runner.Status;
}
///
/// 启动N2和关闭Dump Valve
///
///
private bool OpenN2ValveAndCloseDumpValve()
{
bool result = true;
if (_recipe.Step2N2BubbleOn)
{
result = _device.N2ValveOn();
if (!result)
{
NotifyError(eEvent.ERR_RINSE, "Open N2 Valve error", 0);
return false;
}
}
result = _device.DrainValveOff();
if (!result)
{
NotifyError(eEvent.ERR_RINSE, "Close Dump Valve error",0);
}
return result;
}
///
/// 检验Fill Valve打开状态
///
///
private bool CheckFillValveOn()
{
_startFillTime = DateTime.Now;
_fillingDetectStartWaterLevel = _device.RinseData.WaterLevel;
return true;
}
///
/// 检验是否正常注水
///
///
private bool CheckFillNormalStatus()
{
double currentWaterLevel = _device.RinseData.WaterLevel;
return (currentWaterLevel - _fillingDetectStartWaterLevel) > _fillingStartedDelta;
}
///
/// 检验是否注满
///
///
private bool CheckFillFullStatus()
{
double currentWaterLevel = _device.RinseData.WaterLevel;
bool result = currentWaterLevel > _sensorReadingFull;
return result;
}
///
/// 打开Dump Valve
///
///
private bool StartOpenDumpValve()
{
CheckNeedCloseMetalDrain();
bool result = _device.DrainValveOn();
if (!result)
{
NotifyError(eEvent.ERR_RINSE, "Open Dump valve error", 0);
return false;
}
return result;
}
///
/// 检验快排是否排空
///
///
private bool CheckWaterLevelEmpty()
{
double currentWaterLevel = _device.RinseData.WaterLevel;
bool reseult = currentWaterLevel < _sensorReadingEmpty;
if (!reseult)
{
NotifyError(eEvent.ERR_RINSE, $"current water level: {currentWaterLevel} is large than sensorReadingEmpty: {_sensorReadingEmpty}", 0);
}
return reseult;
}
///
/// 检验是否需要关闭Metal Valve
///
///
private void CheckNeedCloseMetalDrain()
{
//此时已经冲洗的次数包括第一步加第二步加第三步的一次
if (_recipe.Step1NumberOfRinse + _recipe.Step2NumberOfRinse + 1 > _recipe.Step1NumberOfDumpToMetalDrain)
{
bool result = _device.WasteValveOn();
if (!result)
{
NotifyError(eEvent.ERR_RINSE, "Close Metal Drain Valve error", 0);
}
}
}
///
/// ResistivityStart
///
///
private bool ResistivityStart()
{
bool result = true;
result = _device.FillValveOff();
if (!result)
{
NotifyError(eEvent.ERR_RINSE, "Fill Valve Off error",0);
return false;
}
if (_recipe.Step2N2BubbleOn)
{
result = _device.N2ValveOff();
if (!result)
{
NotifyError(eEvent.ERR_RINSE, "N2 Valve Off error", 0);
return false;
}
}
return result;
}
///
/// ResistivityAveraging
///
///
private bool ResistivityAveraging()
{
if (_recipe.ResistivityDurationSeconds == 0)
{
_resistivitySample.Add(GetResitivity());
}
else
{
_startSampleTime = DateTime.Now;
_sampeIntervalTime = DateTime.Now;
_startSample = true;
}
return true;
}
///
/// 采样Resitivity
///
///
private bool ResitivitySampleResitivity()
{
if (!_startSample)
{
return true;
}
int sampleTotalCount = (int)Math.Ceiling(_recipe.ResistivityDurationSeconds / 0.1);
//每隔100毫秒采样
if (DateTime.Now.Subtract(_sampeIntervalTime).TotalMilliseconds >= 100)
{
_sampeIntervalTime = DateTime.Now;
_readResistivityCount++;
_resistivitySample.Add(GetResitivity());
}
//ResistivityDurationSeconds时长减去0.1s,避免超时
if (DateTime.Now.Subtract(_startSampleTime).TotalMilliseconds >= _recipe.ResistivityDurationSeconds * 1000 - 100)
{
bool result = CheckResistivity();
if (!result)
{
Runner.Stop("Sample Resitiviy abormal", true);
}
return result;
}
return false;
}
//读取Resitivity的值
private double GetResitivity()
{
double resistivity = 0;
ResistivityController resistivityController = DEVICE.GetDevice(_device.RinseItem.ResistivityID);
if (resistivityController != null)
{
try
{
resistivity = double.Parse(resistivityController.ResisitivityValue.Trim());
}
catch
{
resistivity = 0;
}
}
return resistivity;
}
///
/// CheckResistivity
///
///
private bool CheckResistivity()
{
if (_recipe.ResistivityMegaOhms == 0)
{
_resistivitySample.Clear();
return true;
}
double resistivityAverageValue = _resistivitySample.Average();
if ((_resistivitySample.Count == 1 && _resistivitySample[0] < _recipe.ResistivityMegaOhms) || resistivityAverageValue < _recipe.ResistivityMegaOhms)
{
NotifyError(eEvent.ERR_RINSE, $"The detected resistivity value is abnormal,: {resistivityAverageValue}",0);
}
else
{
LOG.WriteLog(eEvent.INFO_RINSE, Module, $"The detected resistivity value is : {resistivityAverageValue}");
}
_resistivitySample.Clear();
return true;
}
///
/// Abort
///
public void Abort()
{
Runner.Stop("Manual abort");
}
}
}