using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.ParameterCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using FurnaceRT.Devices; using FurnaceRT.Equipments.Systems; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.Event; using MECF.Framework.Common.OperationCenter; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Xml; namespace FurnaceRT.Equipments.PMs { public partial class PMModule { private string _currentLeakCheckFileName = ""; private Dictionary _leakCheckDic; private int _currentRetryCount = 0; private int _currentLeakCheckIndex = -1; private double _basePressure = -1; private double _leakCheckDelayStartPressure = 0; private double _leakCheckDelayMonitorPressure = 0; private double _leakCheckStartPressure = 0; private double _leakCheckMonitorPressure = 0; private double _leakCheckActualLeak = 0; private bool _isLeakCheckFinished = false; private Stopwatch _leakCheckDelayTimer = new Stopwatch(); private Stopwatch _leakCheckTimer = new Stopwatch(); private string _leakCheckStatus = "None"; private LeakCheckTableParameter _leakCheckTableParameter = null; private void InitLeakCheckData() { DATA.Subscribe($"{Module}.LeakCheckPressureSensorName", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.PressureSensorName : ""); DATA.Subscribe($"{Module}.LeakCheckTable", () => _leakCheckTableParameter != null ? $"{_leakCheckTableParameter.No}:{_leakCheckTableParameter.Name}" : "0:Not Select"); DATA.Subscribe($"{Module}.LeakCheckHightLimitCommand", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.HightLimitCommand : "None"); DATA.Subscribe($"{Module}.LeakCheckLowLimitCommand", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.LowLimitCommand : "None"); DATA.Subscribe($"{Module}.LeakCheckBasePressureLimitCommand", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.BasePressureLimitCommand : "None"); DATA.Subscribe($"{Module}.LeakCheckErrorCommand", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.ErrorCommand : "None"); DATA.Subscribe($"{Module}.LeakCheckRetryOverCommand", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.RetryOverCommand : "None"); DATA.Subscribe($"{Module}.LeakCheckHighLimit", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.HighLimit : 0.0f); DATA.Subscribe($"{Module}.LeakCheckLowLimit", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.LowLimit : 0.0f); DATA.Subscribe($"{Module}.LeakCheckBasePressureLimit", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.BasePressureLimit : 0.0f); DATA.Subscribe($"{Module}.LeakCheckDelayTime", () => _leakCheckTableParameter != null? _leakCheckTableParameter.DelayTime : 0.0f); DATA.Subscribe($"{Module}.LeakCheckDelayElapseTime", () => (_leakCheckTableParameter != null && !_leakCheckStatus.Equals("None") && _leakCheckDelayTimer.IsRunning) || _leakCheckTimer.IsRunning ? _leakCheckDelayTimer.ElapsedMilliseconds / 1000 : 0.0f); DATA.Subscribe($"{Module}.LeakCheckCheckTime", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.CheckTime : 0.0f); DATA.Subscribe($"{Module}.LeakCheckElapseTime", () => _leakCheckTableParameter != null && !_leakCheckStatus.Equals("None") && _leakCheckTimer.IsRunning ? _leakCheckTimer.ElapsedMilliseconds / 1000 : 0.0f); DATA.Subscribe($"{Module}.LeakCheckBasePressure", () => _leakCheckTableParameter != null ? _basePressure : 0.0f); DATA.Subscribe($"{Module}.LeakCheckLeakLimit", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.LeakLimit : 0.0f); DATA.Subscribe($"{Module}.LeakCheckDelayMonitorPressure", () => _leakCheckTableParameter != null && _leakCheckDelayTimer.IsRunning && !_leakCheckTimer.IsRunning ? (float)_leakCheckDelayMonitorPressure : 0.0f); DATA.Subscribe($"{Module}.LeakCheckDelayStartPressure", () => _leakCheckTableParameter != null && _leakCheckDelayTimer.IsRunning ? (float)_leakCheckDelayStartPressure : 0.0f); DATA.Subscribe($"{Module}.LeakCheckMonitorPressure", () => _leakCheckTableParameter != null && _leakCheckDelayTimer.IsRunning && _isLeakCheckFinished ? (float)_leakCheckMonitorPressure : 0.0f); DATA.Subscribe($"{Module}.LeakCheckStartPressure", () => _leakCheckTableParameter != null && _leakCheckDelayTimer.IsRunning && _leakCheckTimer.IsRunning ? (float)_leakCheckStartPressure : 0.0f); DATA.Subscribe($"{Module}.LeakCheckActualLeak", () => (float)_leakCheckActualLeak); DATA.Subscribe($"{Module}.LeakCheckRetryCurrentCount", () => _currentRetryCount); DATA.Subscribe($"{Module}.LeakCheckRetryLimit", () => _leakCheckTableParameter != null ? _leakCheckTableParameter.RetryLimit : 0); DATA.Subscribe($"{Module}.LeakCheckStatus", () => _leakCheckStatus); } public void SetLeakCheckTableIndex(int index) { _leakCheckDelayStartPressure = 0; _currentLeakCheckIndex = -1; _basePressure = -1; _isLeakCheckFinished = false; _leakCheckActualLeak = 0; _leakCheckDelayStartPressure = 0; _leakCheckDelayMonitorPressure = 0; _leakCheckStartPressure = 0; _leakCheckMonitorPressure = 0; if (_leakCheckDic == null) return; var ret = _leakCheckDic.TryGetValue(index, out _leakCheckTableParameter); if (!ret) return; _leakCheckStatus = "BasePressureCheck"; _currentLeakCheckIndex = index; _basePressure = _leakCheckTableParameter.PressureSensor.Value; if (_basePressure > _leakCheckTableParameter.HighLimit && _leakCheckTableParameter.HighLimit > 0) { LeakCheckAlarm.Set($"Leak check alarm: PH={_leakCheckTableParameter.HighLimit} < BP={_basePressure}"); ProcessLeakCheckErrorCommand(_leakCheckTableParameter.HightLimitCommand); return; } if (_basePressure > _leakCheckTableParameter.LowLimit && _leakCheckTableParameter.LowLimit > 0 && _basePressure <= _leakCheckTableParameter.HighLimit) { LeakCheckAlarm.Set($"Leak check alarm: PL={_leakCheckTableParameter.LowLimit} < BP={_basePressure} <= PH={_leakCheckTableParameter.HighLimit}"); ProcessLeakCheckErrorCommand(_leakCheckTableParameter.LowLimitCommand); return; } if (_basePressure < _leakCheckTableParameter.BasePressureLimit && _leakCheckTableParameter.BasePressureLimit > 0) { LeakCheckAlarm.Set($"Leak check alarm: BP={_basePressure} < BPLIMIT={_leakCheckTableParameter.HighLimit}"); ProcessLeakCheckErrorCommand(_leakCheckTableParameter.BasePressureLimitCommand); return; } _leakCheckDelayStartPressure = _leakCheckTableParameter.PressureSensor.Value; _leakCheckDelayTimer.Restart(); _leakCheckDelayStartPressure = _leakCheckTableParameter.PressureSensor.Value; _leakCheckTimer.Stop(); } public void InitLeakCheck(string fileName) { _leakCheckStatus = "None"; _currentRetryCount = 0; if (string.IsNullOrEmpty(fileName)) { return; } _currentLeakCheckFileName = fileName; var content = ParameterFileManager.Instance.LoadParameter("Parameter\\LeakCheckCondition", fileName, false); if (string.IsNullOrEmpty(content)) { return; } var doc = new XmlDocument(); doc.LoadXml(content); XmlNodeList nodeSteps = doc.SelectNodes($"Aitex/TableParameterData/Module[@Name='']/Step"); if (nodeSteps == null) nodeSteps = doc.SelectNodes($"Aitex/TableParameterData/Step"); if (nodeSteps == null) { EV.PostWarningLog(ModuleName.PM1.ToString(), $"Invalid leak check file {fileName}"); return; } _leakCheckDic = new Dictionary(); for (int i = 0; i < nodeSteps.Count; i++) { var step = nodeSteps[i]; XmlElement stepNode = step as XmlElement; int tableIndex = i + 1; LeakCheckTableParameter table = new LeakCheckTableParameter(); foreach (XmlAttribute att in stepNode.Attributes) { switch (att.Name) { case "StepNo": int.TryParse(att.Value, out int no); table.No = no; break; case "Name": table.Name = att.Value; break; case "PressSensor": table.PressureSensor = DEVICE.GetDevice($"{Module}.VG13");//给一个默认值,防止LeakCheck没有选择导致报错 if (!string.IsNullOrEmpty(att.Value)) { var paras = att.Value.Split(':'); if(paras.Length > 1) { table.PressureSensor = DEVICE.GetDevice($"{Module}.{paras[1]}"); } } table.PressureSensorName = att.Value; break; case "PHHighLimit": if (!string.IsNullOrEmpty(att.Value)) { float.TryParse(att.Value, out float value); table.HighLimit = value; } break; case "PLLowLimit": if (!string.IsNullOrEmpty(att.Value)) { float.TryParse(att.Value, out float value); table.LowLimit = value; } break; case "BPLimit": if (!string.IsNullOrEmpty(att.Value)) { float.TryParse(att.Value, out float value); table.BasePressureLimit = value; } break; case "DelayTime": if (!string.IsNullOrEmpty(att.Value)) { float.TryParse(att.Value, out float value); table.DelayTime = value; } break; case "CheckTime": if (!string.IsNullOrEmpty(att.Value)) { float.TryParse(att.Value, out float value); table.CheckTime = value; } break; case "LeakLimit": if (!string.IsNullOrEmpty(att.Value)) { float.TryParse(att.Value, out float value); table.LeakLimit = value; } break; case "RetryLimit": if (!string.IsNullOrEmpty(att.Value)) { int.TryParse(att.Value, out int value); table.RetryLimit = value; } break; case "HightLimitCommand": table.HightLimitCommand = att.Value; break; case "LowLimitCommand": table.LowLimitCommand = att.Value; break; case "BasePressureLimitCommand": table.BasePressureLimitCommand = att.Value; break; case "ErrorCommand": table.ErrorCommand = att.Value; break; case "RetryOverCommand": table.RetryOverCommand = att.Value; break; } } _leakCheckDic.Add(tableIndex, table); } } public bool CheckLeakCheckFinish() { if (_leakCheckStatus == "None")//没在leakCheck状态 { _currentRetryCount = 0; return true; } if (_leakCheckDic == null || _currentLeakCheckIndex < 0) return true; var ret = _leakCheckDic.TryGetValue(_currentLeakCheckIndex, out var leakCheckParameter); if (!ret) return true; if (_isLeakCheckFinished) { if (_leakCheckDelayTimer.IsRunning) _leakCheckDelayTimer.Stop(); if (_leakCheckTimer.IsRunning) _leakCheckTimer.Stop(); } if (!_leakCheckDelayTimer.IsRunning && !_leakCheckTimer.IsRunning) { _leakCheckDelayStartPressure = leakCheckParameter.PressureSensor.Value; _leakCheckDelayTimer.Restart(); } if (_leakCheckDelayTimer.IsRunning && _leakCheckDelayTimer.ElapsedMilliseconds >= leakCheckParameter.DelayTime* 1000) { _leakCheckStatus = "LeakCheck"; if (!_leakCheckTimer.IsRunning) { _leakCheckDelayMonitorPressure = leakCheckParameter.PressureSensor.Value; _leakCheckStartPressure = leakCheckParameter.PressureSensor.Value; _leakCheckTimer.Restart(); } _leakCheckDelayTimer.Stop(); } else { if(!_leakCheckTimer.IsRunning) _leakCheckStatus = "LeakCheckDelay"; } if (_leakCheckTimer.IsRunning && _leakCheckTimer.ElapsedMilliseconds >= leakCheckParameter.CheckTime * 1000) { _leakCheckMonitorPressure = leakCheckParameter.PressureSensor.Value; _leakCheckActualLeak = leakCheckParameter.PressureSensor.Value - _leakCheckStartPressure; if (_leakCheckActualLeak > leakCheckParameter.LeakLimit) { if (leakCheckParameter.RetryLimit > 0) { if (_currentRetryCount < leakCheckParameter.RetryLimit) { _currentRetryCount++; _processRoutine.LeakCheckRetry(); LOG.Write($"Leak check retry {_currentRetryCount}/{leakCheckParameter.RetryLimit}"); } else { LeakCheckAlarm.Set($"Leak check alarm: already retry count={_currentRetryCount} >= retry limit={leakCheckParameter.RetryLimit}"); ProcessLeakCheckErrorCommand(leakCheckParameter.RetryOverCommand); } } else { LeakCheckAlarm.Set($"Leak check alarm: actual leak={_leakCheckActualLeak} > leak limit={leakCheckParameter.LeakLimit}"); ProcessLeakCheckErrorCommand(leakCheckParameter.ErrorCommand); } return false; } else { _isLeakCheckFinished = true; _leakCheckStatus = "None"; _leakCheckTimer.Stop(); _leakCheckDelayTimer.Stop(); LOG.Write($"Leak check completed, leak rate={_leakCheckActualLeak}, delay time={leakCheckParameter.DelayTime}, check time={leakCheckParameter.CheckTime}, leak limit={leakCheckParameter.LeakLimit}, retry info={_currentRetryCount}/{leakCheckParameter.RetryLimit}"); } } return _isLeakCheckFinished; } public void AbortLeakCheck() { _leakCheckStatus = "None"; _currentRetryCount = 0; if (_leakCheckDelayTimer.IsRunning) _leakCheckDelayTimer.Stop(); if (_leakCheckTimer.IsRunning) _leakCheckTimer.Stop(); } private void ProcessLeakCheckErrorCommand(string command) { _isLeakCheckFinished = true; _leakCheckStatus = "None"; var recipe = ""; var recipeType = ""; var recipeTable = ""; switch (command) { case "Reset": recipe = SC.GetStringValue("System.Recipe.Reset Recipe"); recipeType = "Reset"; CheckToPostMessage((int)MSG.RunOtherRecipe, recipe, recipeType); LOG.Write($"Leak check: command={command} recipe={recipe}"); break; case "End": //因为要跳到执行最后一步,所以stepNumber需要减一 _processRoutine.JumpCurrentRecipeStep(RecipeRunningInfo.RecipeStepList.Count - 1, RecipeRunningInfo.RecipeStepList[RecipeRunningInfo.RecipeStepList.Count - 1].StepName); LOG.Write($"Leak check: command={command} step name={RecipeRunningInfo.RecipeStepList[RecipeRunningInfo.RecipeStepList.Count - 1].StepName}"); break; case "Hold": _processRoutine.PauseRecipe(); LOG.Write($"Leak check: command={command}"); break; case "Monitor": LOG.Write($"Leak check: command={command}"); break; case "Buzzer": Singleton.Instance.IsAlarmConditionBuzzerOn = true; LOG.Write($"Leak check: command={command}"); break; default: if (command.StartsWith("JUMP")) { //Jump step //Jump 1: var stepName = command.Replace("JUMP ", ""); var jumpStepNumber = RecipeRunningInfo.RecipeStepList.FindIndex(x => x.StepName == stepName); if (jumpStepNumber > 0) _processRoutine.JumpCurrentRecipeStep(jumpStepNumber, stepName); LOG.Write($"Leak check: command={command} step name={stepName}"); } else if (command.StartsWith("CALL")) { //call Alarm recipe //Call 1: var paras = command.Split(':'); if (paras.Length > 0) { recipe = RecipeRunningInfo.Head.AlarmRecipe; recipeType = "Alarm"; recipeTable = paras[0].Replace("CALL", "").Replace(" ", "").Replace(":", "").Replace(":", ""); CheckToPostMessage((int)MSG.RunOtherRecipe, recipe, recipeType, recipeTable); LOG.Write($"Leak check: command={command} recipe={recipe}"); } } else if (command.StartsWith("ABORT")) { //call Abort recipe //Abort 1: var paras = command.Split(':'); if (paras.Length > 0) { recipe = RecipeRunningInfo.Head.AbortRecipe; recipeType = "Abort"; recipeTable = paras[0].Replace("ABORT", "").Replace(" ", "").Replace(":", "").Replace(":", ""); CheckToPostMessage((int)MSG.RunOtherRecipe, recipe, recipeType, recipeTable); LOG.Write($"Leak check: command={command} recipe={recipe}"); } } break; } } class LeakCheckTableParameter { public int No { get; set; } public string Name { get; set; } public string PressureSensorName { get; set; } public IoPressureMeter PressureSensor { get; set; } public float HighLimit { get; set; } = 0; public float LowLimit { get; set; } = 0; public float BasePressureLimit { get; set; } = 0; public float DelayTime { get; set; } = 0; public float CheckTime { get; set; } = 0; public float LeakLimit { get; set; } = 0; public int RetryLimit { get; set; } public string HightLimitCommand { get; set; } public string LowLimitCommand { get; set; } public string BasePressureLimitCommand { get; set; } public string ErrorCommand { get; set; } public string RetryOverCommand { get; set; } } } }