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.ToolLayout;
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;
using System.Windows.Documents;
namespace CyberX8_RT.Modules.Rinse
{
public class RinseSecondStepRoutine:RoutineBase,IRoutine
{
private enum RinseSecondStep
{
PrepareStart,
Recipe_StartSecondRinseCycle,
Recipe_PerformSecondRinseCycle,
Recipe_SecondRinseCycleStartFilling,
Recipe_SecondRinseCycleRecordStartWaterLevel,
Recipe_SecondRinseCycleStartFillingWait,
Recipe_SecondRinseCycleWaitFillingDetected,
Recipe_SecondRinseCycleWaitFull,
Recipe_SecondRinseCycleWaitEndFillTime,
Recipe_SecondRinseCycleWaitDwell,
Recipe_SecondRinseCycleWaitDrain,
Recipe_SecondRinseCycleCheckDrain,
Recipe_SecondRinseCycleWaitDrainExtraTime,
Recipe_SecondRinseCycleWaitResistivityStart,
Recipe_SecondRinseCycleResistivityAveraging,
Recipe_SecondRinseCycleCheckResistivity,
Recipe_SecondRinseCycleWaitDrain2,
Recipe_SecondRinseCycleCheckDrain2,
Recipe_SecondRinseCycleWaitDrain2ExtraTime,
Recipe_SecondRinseCycleEnd,
Recipe_SecondRinseCycleComplete
}
#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;
///
/// 从开始排水到检测是否排空的间隔时间
///
private int _normalDrainTimeSeconds;
///
/// 表示当前正在执行第几次rinse
///
private int _rinseCycleTwo_RinsesCompleted = 0;
///
/// 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 RinseSecondStepRoutine(string module) : base(module)
{
}
///
/// 启动
///
///
///
public RState Start(params object[] objects)
{
_startSample = false;
_device = DEVICE.GetDevice(Module);
_resistivitySample.Clear();
_readResistivityCount = 0;
_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");
_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 Second Step");
}
///
/// 监控
///
///
public RState Monitor()
{
_currentStateMachine = Runner.CurrentStep.ToString();
_device.UpdateStateMachine(_currentStateMachine);
Runner.RunIf(RinseSecondStep.PrepareStart, _recipe.Step2N2BubbleOn, N2ValveOff, _delay_1ms)
//2.6-StartSecondRinseCycle
.LoopStart(RinseSecondStep.Recipe_StartSecondRinseCycle, "Rinse Second step", _recipe.Step2NumberOfRinse, NullFun, _delay_1ms)
//2.7-PerformSecondRinseCycle
.LoopRun(RinseSecondStep.Recipe_PerformSecondRinseCycle, OpenN2ValveAndCloseDumpValve, _delay_1ms)
//2.8-SecondRinseCycleStartFilling
.LoopRun(RinseSecondStep.Recipe_SecondRinseCycleStartFilling, () => _device.FillValveOn(), _delay_1ms)
.LoopRun(RinseSecondStep.Recipe_SecondRinseCycleRecordStartWaterLevel, CheckFillValveOn, _delay_1ms)
.LoopRunOnlyTimeOutFault(RinseSecondStep.Recipe_SecondRinseCycleStartFillingWait, CheckFillNormalStatus, _checkIsFillingTimeSeconds * 1000)
//2.9-SecondRinseCycleWaitFillingDetected //3.0-SecondRinseCycleWaitFull
.LoopRunOnlyTimeOutFault(RinseSecondStep.Recipe_SecondRinseCycleWaitFillingDetected, CheckFillFullStatus, _checkIsFullTimeSeconds * 1000)
//.LoopRun(RinseSecondStep.Recipe_SecondRinseCycleWaitFull, CheckFillFullStatus, _delay_1s)
//3.1-SecondRinseCycleWaitEndFillTime
.LoopDelay(RinseSecondStep.Recipe_SecondRinseCycleWaitEndFillTime, (_concurrentFillTimeSeconds - _checkIsFillingTimeSeconds - _checkIsFullTimeSeconds) * 1000)
//3.2-SecondRinseCycleWaitDwell
.LoopRunIf(RinseSecondStep.Recipe_SecondRinseCycleWaitDwell, ((_rinseCycleTwo_RinsesCompleted < _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry)
|| ((_rinseCycleTwo_RinsesCompleted < _recipe.Step2NumberOfRinse) && _recipe.FinalRinseDry),
StartDwell, _recipe.Step2DwellTimeSeconds * 1000)
//3.3-SecondRinseCycleWaitDrain
.LoopRunIf(RinseSecondStep.Recipe_SecondRinseCycleWaitDrain, ((_rinseCycleTwo_RinsesCompleted < _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry)
|| ((_rinseCycleTwo_RinsesCompleted < _recipe.Step2NumberOfRinse) && _recipe.FinalRinseDry),
StartOpenDumpValve, _delay_1ms)
.LoopRunIfOnlyTimeOutFault(RinseSecondStep.Recipe_SecondRinseCycleCheckDrain, ((_rinseCycleTwo_RinsesCompleted < _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry)
|| ((_rinseCycleTwo_RinsesCompleted < _recipe.Step2NumberOfRinse) && _recipe.FinalRinseDry),
CheckWaterLevelEmpty, _normalDrainTimeSeconds * 1000)
//3.4-SecondRinseCycleWaitDrainExtraTime
.LoopRunIf(RinseSecondStep.Recipe_SecondRinseCycleWaitDrainExtraTime, ((_rinseCycleTwo_RinsesCompleted < _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry && _recipe.DumpTimeSeconds - _normalDrainTimeSeconds > 0)
|| ((_rinseCycleTwo_RinsesCompleted < _recipe.Step2NumberOfRinse) && _recipe.FinalRinseDry && _recipe.DumpTimeSeconds - _normalDrainTimeSeconds > 0),
NullFun, (_recipe.DumpTimeSeconds - _normalDrainTimeSeconds) * 1000)
//3.7-SecondRinseCycleWaitResistivityStart 条件:(Final Rinse == false && RinseComplete == _recipe.Step2NumberOfRinse - 1)
.LoopRunIf(RinseSecondStep.Recipe_SecondRinseCycleWaitResistivityStart, (_rinseCycleTwo_RinsesCompleted == _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry,
ResistivityStart, _recipe.ResistivityStartTimeSeconds*1000)
//3.8-SecondRinseCycleResistivityAveraging 条件:(Final Rinse == false && RinseComplete == _recipe.Step2NumberOfRinse - 1)
.LoopRunIf(RinseSecondStep.Recipe_SecondRinseCycleResistivityAveraging, (_rinseCycleTwo_RinsesCompleted == _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry,
ResistivityAveraging, _delay_1ms)
//3.9-SecondRinseCycleCheckResistivity 条件:(Final Rinse == false && RinseComplete == _recipe.Step2NumberOfRinse - 1)
.LoopWaitIf(RinseSecondStep.Recipe_SecondRinseCycleCheckResistivity, (_rinseCycleTwo_RinsesCompleted == _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry,
ResitivitySampleResitivity,_recipe.ResistivityDurationSeconds*1000)
//4.0-SecondRinseCycleWaitDrain 条件:(Final Rinse == false && RinseComplete == _recipe.Step2NumberOfRinse - 1)
.LoopRunIf(RinseSecondStep.Recipe_SecondRinseCycleWaitDrain2, (_rinseCycleTwo_RinsesCompleted == _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry,
StartOpenDumpValve, _delay_1ms)
.LoopRunIfOnlyTimeOutFault(RinseSecondStep.Recipe_SecondRinseCycleCheckDrain2, (_rinseCycleTwo_RinsesCompleted == _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry,
CheckWaterLevelEmpty, _normalDrainTimeSeconds * 1000)
//4.1-Recipe_SecondRinseCycleWaitDrain2ExtraTime 条件:(Final Rinse == false && RinseComplete == _recipe.Step2NumberOfRinse - 1)
.LoopRunIf(RinseSecondStep.Recipe_SecondRinseCycleWaitDrain2ExtraTime, (_rinseCycleTwo_RinsesCompleted == _recipe.Step2NumberOfRinse - 1) && !_recipe.FinalRinseDry && _recipe.DumpTimeSeconds - _normalDrainTimeSeconds > 0,
NullFun, (_recipe.DumpTimeSeconds - _normalDrainTimeSeconds) * 1000)
.LoopEnd(RinseSecondStep.Recipe_SecondRinseCycleEnd, CountNumberofRinsesComplete, _delay_1ms)
.End(RinseSecondStep.Recipe_SecondRinseCycleComplete, ResetRinseComplete, _delay_1ms);
return Runner.Status;
}
///
/// N2 Valve Off
///
///
private bool N2ValveOff()
{
if (_recipe.Step1N2BubbleOn)
{
return _device.N2ValveOff();
}
else
{
return true;
}
}
///
/// 检验N2Valve off
///
///
private bool CheckN2ValveOff()
{
if (_recipe.Step1N2BubbleOn)
{
return !_device.RinseData.N2Valve;
}
else
{
return true;
}
}
///
/// 启动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;
}
///
/// 增加已完成Rinses的次数
///
///
private bool CountNumberofRinsesComplete()
{
_rinseCycleTwo_RinsesCompleted++;
return true;
}
///
/// 开始Dwell
///
///
private bool StartDwell()
{
bool 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 true;
}
///
/// 打开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 加上第一步的number of rinse
///
///
private void CheckNeedCloseMetalDrain()
{
if (_recipe.Step1NumberOfRinse + _rinseCycleTwo_RinsesCompleted + 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;
//LOG.WriteLog(eEvent.ERR_RINSE, Module, "Resitivity value abnormal");
}
}
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);
}
_resistivitySample.Clear();
return true;
}
private bool ResetRinseComplete()
{
_rinseCycleTwo_RinsesCompleted = 0;
return true;
}
///
/// Abort
///
public void Abort()
{
Runner.Stop("Manual abort");
}
}
}