| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949 | 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;        #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)        {        }        /// <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;            }            return false;        }        /// <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;            }            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;        }        /// <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;        }    }}
 |