| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021 | 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 CyberX8_RT.Modules.Metal;using CyberX8_RT.Modules;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 内部变量        /// <summary>        /// recipe        /// </summary>        private DepRecipe _recipe;        /// <summary>        /// Plate Delay时间        /// </summary>        private DateTime _platingDelayTime = DateTime.Now;        /// <summary>        /// 启动步骤时间        /// </summary>        private DateTime _startStepTime = DateTime.Now;        /// <summary>        /// 电量步骤计数        /// </summary>        private Stopwatch _stepWatch = new Stopwatch();        /// <summary>        /// Power 集合        /// </summary>        List<PowerSupplierStepPeriodData> _powerSupplierStepPeriodDatas = new List<PowerSupplierStepPeriodData>();        /// <summary>        /// 单面        /// </summary>        private string _side;        /// <summary>        /// 步骤索引        /// </summary>        private int _stepIndex = 0;        /// <summary>        /// 设备        /// </summary>        private MetalCellDevice _device;        /// <summary>        /// 设备Entity        /// </summary>        private MetalEntity _metalEntity;        /// <summary>        /// A面电量        /// </summary>        private double _anodeAUsage;        /// <summary>        /// B面电量        /// </summary>        private double _anodeBUsage;        /// <summary>        /// 是否启动recipe步骤        /// </summary>        private bool _startRecipeStep = false;        /// <summary>        /// lock track time        /// </summary>        private DateTime _lotTackTime = DateTime.Now;        /// <summary>        /// LotTrack数据        /// </summary>        private List<MetalLotTrackData> _datas = new List<MetalLotTrackData>();        /// <summary>        /// LotTrack文件头数据        /// </summary>        private LotTrackFileHeaderCommonData _header = new LotTrackFileHeaderCommonData();        /// <summary>        /// Facilities        /// </summary>        private SystemFacilities _facilities;        /// <summary>        /// StandardHot Reservoir Device        /// </summary>        private StandardHotReservoirDevice _standardHotReservoirDevice;        /// <summary>        /// StandardHot Metal Device        /// </summary>        private StandardHotMetalDevice _standardHotMetalDevice;        /// <summary>        /// CompactMembran Reservoir Device        /// </summary>        private CompactMembranReservoirDevice _compactMembranReservoirDevice;        /// <summary>        /// CompactMembran Reservoir Metal        /// </summary>        private CompactMembranMetalDevice _compactMembranMetalDevice;        /// <summary>        /// MetalType        /// </summary>        private string _metalType;        /// <summary>        /// TC device        /// </summary>        private TemperatureController _temperatureController;        /// <summary>        /// Persistent value        /// </summary>        private MetalPersistentValue _persistentValue;        /// <summary>        /// PlatingDelay计时        /// </summary>        private DateTime _hotPlatingRunTime;        /// <summary>        /// 是否处于warning状态        /// </summary>        private bool _isVotlageWarningA = false;        private bool _isVotlageWarningB = false;        private bool _isCurrentWarningA = false;        private bool _isCurrentWarningB = false;        private bool _isZeroCurrent = false;        private int _totalMicrosecond = 0;        private double _currentHoldoffTime;        private double _voltageHoldoffTime;        private double _cellFlowHoldoffTime;        private HoldoffTimeSignalMonitor _currentHoldoffTimeSignalMonitor;        private HoldoffTimeSignalMonitor _voltageHoldoffTimeSignalMonitor;        private HoldoffTimeSignalMonitor _cellFlowHoldoffTimeSignalMonitor;        #endregion        #region 属性        /// <summary>        /// A面电量        /// </summary>        public double AnodeAUsage { get { return _anodeAUsage; } }        /// <summary>        /// B面电量        /// </summary>        public double AnodeBUsage { get { return _anodeBUsage; } }        /// <summary>        /// LotTrack数据        /// </summary>        public List<MetalLotTrackData> MetalLotTrackDatas { get { return _datas; } }        /// <summary>        /// LotTrack文件头数据        /// </summary>        public LotTrackFileHeaderCommonData MetalLotTrackHeaderDatas { get { return _header; } }        #endregion        /// <summary>        /// 构造函数        /// </summary>        public ReservoirRunRecipeRoutine(string moduleName) : base(moduleName)        {            _currentHoldoffTime = SC.GetValue<double>($"Metal.CurrentAlarmHoldoffTime");            _voltageHoldoffTime = SC.GetValue<double>($"Metal.VoltageAlarmHoldoffTime");            _cellFlowHoldoffTime = SC.GetValue<double>($"Metal.CellFlowAlarmHoldoffTime");            _currentHoldoffTimeSignalMonitor = new HoldoffTimeSignalMonitor(Module, "Current");            _voltageHoldoffTimeSignalMonitor = new HoldoffTimeSignalMonitor(Module, "Voltage");            _cellFlowHoldoffTimeSignalMonitor = new HoldoffTimeSignalMonitor(Module, "CellFlow");        }        /// <summary>        /// 中止        /// </summary>        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");        }        /// <summary>        /// 监控        /// </summary>        /// <returns></returns>        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; }, 24 * 60 * 60 * 1000)                .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;        }        /// <summary>        /// 记录Lottrack        /// </summary>        private void LottrackRecord()        {            //记录Lottrack            if (DateTime.Now.Subtract(_lotTackTime).TotalMilliseconds >= LOTTRACK_TIME)            {                AddLotTrackData();                _lotTackTime = DateTime.Now;            }        }        /// <summary>        /// 获取Lot Track数据        /// </summary>        /// <returns></returns>        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);        }        /// <summary>        /// Plate Delay        /// </summary>        /// <returns></returns>        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;        }        /// <summary>        /// Hot Plating        /// </summary>        /// <returns></returns>        private bool HotPlating()        {            UpdateHotPlatingStepDatas();            return StartPowerStep();        }        /// <summary>        /// 启动PowerSupplier        /// </summary>        /// <returns></returns>        private bool StartPowerStep()        {            if (_isZeroCurrent)            {                _startStepTime = DateTime.Now;                return true;            }            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;            }        }        /// <summary>        /// 检验Powerstep是否启动完成        /// </summary>        /// <returns></returns>        private bool CheckRecipeStepEndStatus()        {            if (_isZeroCurrent)            {                return true;            }            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;        }        /// <summary>        /// 检验Powerstep是否启动完成        /// </summary>        /// <returns></returns>        private bool CheckRecipeStepStopStatus()        {            if (_isZeroCurrent)            {                return false;            }            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;        }        /// <summary>        /// 获取单面PowerSupplier        /// </summary>        /// <returns></returns>        private CellPowerSupplier GetSidePowerSupplier()        {            if (_side == SIDE_A)            {                return _device.SideAPowerSupplier;            }            else            {                return _device.SideBPowerSupplier;            }        }        /// <summary>        /// 启动        /// </summary>        /// <returns></returns>        private bool StartPowerStep(CellPowerSupplier cellPowerSupplier)        {            bool result = cellPowerSupplier.StartSetStepPeriodNoWaitEnd(_powerSupplierStepPeriodDatas);            if (!result)            {                cellPowerSupplier.DisableOperation("", null);                return false;            }            return true;        }        /// <summary>        /// 更新HotPlating step数据        /// </summary>        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);            }        }        /// <summary>        /// 更新Power step步骤        /// </summary>        private void UpdatePowerStepDatas()        {            _isZeroCurrent = false;            double current = 0;            _totalMicrosecond = 0;            _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 - step.Hour * 3600) / 60);                step.Second = (ushort)(item.CurrentRampDurartionSeconds % 60);                step.Microsecond = 0;                step.Voltage = _recipe.VoltageWarningLevel;                _powerSupplierStepPeriodDatas.Add(step);                current += step.Current;                _totalMicrosecond += item.CurrentRampDurartionSeconds * 1000;            }            if (current == 0)            {                _isZeroCurrent = true;            }        }        /// <summary>        /// 等待Plating Delay结束        /// </summary>        /// <returns></returns>        private bool WaitPlatingDelay()        {            if (DateTime.Now.Subtract(_platingDelayTime).TotalSeconds >= _recipe.PlatingDelaySeconds)            {                return true;            }            return false;        }        /// <summary>        /// 检验步骤是否完成        /// </summary>        /// <returns></returns>        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;            }            int firstDelay = 2000;            if (_stepIndex == 0)            {                firstDelay = SC.GetValue<int>("Metal.CurrentCheckDelay") * 1000;            }            if (DateTime.Now.Subtract(_startStepTime).TotalMilliseconds >= firstDelay)            {                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;        }        /// <summary>        /// 检验Power是否Disable        /// </summary>        /// <returns></returns>        private bool CheckMetalDisable()        {            if (!_device.IsLinmotMotorOn)            {                LOG.WriteLog(eEvent.ERR_METAL, Module, "Linmot is not motor on");                Abort();                return true;            }            //CheckVotlageAndCurrent();            if (!CheckVoltageAndCurrentValid())            {                Abort();                return true;            }            if (!CheckMetalCellFlow()) //校验Manual 状态下run recipe的 cell flow和hold flow            {                Abort();                return true;            }            return false;        }        /// <summary>        /// 监控流量        /// </summary>        /// <returns></returns>        private bool CheckMetalCellFlow()        {            MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(Module);            if (metalEntity != null && metalEntity.IsManual)            {                MetalItem metalItem = MetalItemManager.Instance.GetMetalItem(Module);                _metalType = metalItem.SubType;                if (_metalType == STRATUS)                {                    StandardHotMetalDevice _standardHotMetalDevice = DEVICE.GetDevice<StandardHotMetalDevice>(Module.ToString());                    //if (_standardHotMetalDevice.MetalDeviceData.CellFlow <= 0)                    //{                    //    LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module} metal cell flow is 0");                    //    return false;                    //}                    bool cellFlowSignalresulte = _cellFlowHoldoffTimeSignalMonitor.IsSignalAbnormal(_cellFlowHoldoffTime, _standardHotMetalDevice.MetalDeviceData.CellFlow, null, 0);                    if (cellFlowSignalresulte)                    {                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module} metal cell flow is 0");                        return false;                    }                }            }            return true;        }        /// <summary>        /// 检验电压电流的合理性        /// </summary>        /// <returns></returns>        private bool CheckVoltageAndCurrentValid()        {            //零电流不检验            if (_isZeroCurrent)            {                return true;            }            if (string.IsNullOrEmpty(_side))            {                if (!_device.SideAPowerSupplier.PowerSupplierData.Enabled)                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerA disable");                    return false;                }                if (!_device.SideBPowerSupplier.PowerSupplierData.Enabled)                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerB disable");                    return false;                }            }            else            {                if (_side == SIDE_A && !_device.SideAPowerSupplier.PowerSupplierData.Enabled)                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerA disable");                    return false;                }                if (_side == SIDE_B && !_device.SideBPowerSupplier.PowerSupplierData.Enabled)                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, "PowerB disable");                    return false;                }            }            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;        }        /// <summary>        /// 检验电流和电压合理性        /// </summary>        /// <param name="current"></param>        /// <param name="voltage"></param>        /// <param name="side"></param>        /// <returns></returns>        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;            //}            bool voltageSignalresulte = _voltageHoldoffTimeSignalMonitor.IsSignalAbnormal(_voltageHoldoffTime, voltage, maxVoltage, minVoltage);            if (voltageSignalresulte)            {                if (voltage > maxVoltage)                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} voltage {voltage} is large than recipe max voltage {maxVoltage}");                }                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;            //}            bool currentSignalresulte = _currentHoldoffTimeSignalMonitor.IsSignalAbnormal(_currentHoldoffTime, current, maxErrorCurrent, minErrorCurrent);            if (currentSignalresulte)            {                if (current > maxErrorCurrent)                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"{side} current {current} is large than recipe max current {maxErrorCurrent}");                }                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;        }        /// <summary>        /// 停止Linmot        /// </summary>        /// <returns></returns>        private bool StopLinmot()        {            return _device.StopLinmot();        }        /// <summary>        /// 停止电源        /// </summary>        /// <returns></returns>        private bool StopPowerSupplier()        {            if (string.IsNullOrEmpty(_side))            {                _device.SideAPowerSupplier.DisableOperation("", null);                _device.SideBPowerSupplier.DisableOperation("", null);            }            else            {                CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();                cellPowerSupplier.DisableOperation("", null);            }            return true;        }        /// <summary>        /// 切换成正常模式        /// </summary>        /// <returns></returns>        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;        }        /// <summary>        /// 启动        /// </summary>        /// <param name="objs"></param>        /// <returns></returns>        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<MetalCellDevice>(Module);            _metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(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<RouteManager>.Instance.GetModule<MetalEntity>(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<string>();                _header.ProcessTransferList.AddRange(metalEntity.WaferHolderInfo.SchedulerModules);                metalEntity.WaferHolderInfo.SchedulerModules.Clear();            }            _facilities = DEVICE.GetDevice<SystemFacilities>("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<StandardHotReservoirDevice>(reservoirName);                _standardHotMetalDevice = DEVICE.GetDevice<StandardHotMetalDevice>(Module);                if (_standardHotReservoirDevice == null || _standardHotMetalDevice == null)                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"metal or reservoir device is null");                    return RState.Failed;                }                if (_standardHotMetalDevice.MetalDeviceData.CellFlow <= 0) //检查cell flow                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"reservoir metal cell flow is 0");                    return RState.Failed;                }            }            else            {                _compactMembranReservoirDevice = DEVICE.GetDevice<CompactMembranReservoirDevice>(reservoirName);                _compactMembranMetalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(Module);                if (_compactMembranMetalDevice == null || _compactMembranReservoirDevice == null)                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"metal or reservoir device is null");                    return RState.Failed;                }                if (_compactMembranMetalDevice.MetalDeviceData.CellFlow <= 0) //检查cell flow                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"reservoir metal cell flow is 0");                    return RState.Failed;                }                if (_compactMembranMetalDevice.ANACellFlow.CounterValue <= 0) //检查hold flow                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"reservoir metal AnodeA flow is 0");                    return RState.Failed;                }                if (_compactMembranMetalDevice.ANBCellFlow.CounterValue <= 0)                {                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"reservoir metal AnodeB flow is 0");                    return RState.Failed;                }            }            ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(reservoirName);            _temperatureController = DEVICE.GetDevice<TemperatureController>(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;            }            _lotTackTime = DateTime.Now;            return Runner.Start(Module, "Metal run recipe");        }        public void clearLotTrack()        {            _datas.Clear();        }        public void resetMetalUsage()        {            _anodeAUsage = 0;            _anodeBUsage = 0;        }    }}
 |