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 内部变量
        /// 
        /// recipe
        /// 
        private DepRecipe _recipe;
        /// 
        /// Plate Delay时间
        /// 
        private DateTime _platingDelayTime = DateTime.Now;
        /// 
        /// 启动步骤时间
        /// 
        private DateTime _startStepTime = DateTime.Now;
        /// 
        /// 电量步骤计数
        /// 
        private Stopwatch _stepWatch = new Stopwatch();
        /// 
        /// Power 集合
        /// 
        List _powerSupplierStepPeriodDatas = new List();
        /// 
        /// 单面
        /// 
        private string _side;
        /// 
        /// 步骤索引
        /// 
        private int _stepIndex = 0;
        /// 
        /// 设备
        /// 
        private MetalCellDevice _device;
        /// 
        /// 设备Entity
        /// 
        private MetalEntity _metalEntity;
        /// 
        /// A面电量
        /// 
        private double _anodeAUsage;
        /// 
        /// B面电量
        /// 
        private double _anodeBUsage;
        /// 
        /// 是否启动recipe步骤
        /// 
        private bool _startRecipeStep = false;
        /// 
        /// lock track time
        /// 
        private DateTime _lotTackTime = DateTime.Now;
        /// 
        /// LotTrack数据
        /// 
        private List _datas = new List();
        /// 
        /// LotTrack文件头数据
        /// 
        private LotTrackFileHeaderCommonData _header = new LotTrackFileHeaderCommonData();
        /// 
        /// Facilities
        /// 
        private SystemFacilities _facilities;
        /// 
        /// StandardHot Reservoir Device
        /// 
        private StandardHotReservoirDevice _standardHotReservoirDevice;
        /// 
        /// StandardHot Metal Device
        /// 
        private StandardHotMetalDevice _standardHotMetalDevice;
        /// 
        /// CompactMembran Reservoir Device
        /// 
        private CompactMembranReservoirDevice _compactMembranReservoirDevice;
        /// 
        /// CompactMembran Reservoir Metal
        /// 
        private CompactMembranMetalDevice _compactMembranMetalDevice;
        /// 
        /// MetalType
        /// 
        private string _metalType;
        /// 
        /// TC device
        /// 
        private TemperatureController _temperatureController;
        /// 
        /// Persistent value
        /// 
        private MetalPersistentValue _persistentValue;
        /// 
        /// PlatingDelay计时
        /// 
        private DateTime _hotPlatingRunTime;
        /// 
        /// 是否处于warning状态
        /// 
        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 属性
        /// 
        /// A面电量
        /// 
        public double AnodeAUsage { get { return _anodeAUsage; } }
        /// 
        /// B面电量
        /// 
        public double AnodeBUsage { get { return _anodeBUsage; } }
        /// 
        /// LotTrack数据
        /// 
        public List MetalLotTrackDatas { get { return _datas; } }
        /// 
        /// LotTrack文件头数据
        /// 
        public LotTrackFileHeaderCommonData MetalLotTrackHeaderDatas { get { return _header; } }
        #endregion
        /// 
        /// 构造函数
        /// 
        public ReservoirRunRecipeRoutine(string moduleName) : base(moduleName)
        {
        }
        /// 
        /// 中止
        /// 
        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");
        }
        /// 
        /// 监控
        /// 
        /// 
        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;
        }
        /// 
        /// 记录Lottrack
        /// 
        private void LottrackRecord()
        {
            //记录Lottrack
            if (DateTime.Now.Subtract(_lotTackTime).TotalMilliseconds >= LOTTRACK_TIME)
            {
                AddLotTrackData();
                _lotTackTime = DateTime.Now;
            }
        }
        /// 
        /// 获取Lot Track数据
        /// 
        /// 
        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);
        }
        /// 
        /// Plate Delay
        /// 
        /// 
        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;
        }
        /// 
        /// Hot Plating
        /// 
        /// 
        private bool HotPlating()
        {
            UpdateHotPlatingStepDatas();
            return StartPowerStep();
        }
        /// 
        /// 启动PowerSupplier
        /// 
        /// 
        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;
            }
        }
        /// 
        /// 检验Powerstep是否启动完成
        /// 
        /// 
        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;
        }
        /// 
        /// 检验Powerstep是否启动完成
        /// 
        /// 
        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;
        }
        /// 
        /// 获取单面PowerSupplier
        /// 
        /// 
        private CellPowerSupplier GetSidePowerSupplier()
        {
            if (_side == SIDE_A)
            {
                return _device.SideAPowerSupplier;
            }
            else
            {
                return _device.SideBPowerSupplier;
            }
        }
        /// 
        /// 启动
        /// 
        /// 
        private bool StartPowerStep(CellPowerSupplier cellPowerSupplier)
        {
            bool result = cellPowerSupplier.StartSetStepPeriodNoWaitEnd(_powerSupplierStepPeriodDatas);
            if (!result)
            {
                cellPowerSupplier.DisableOperation("", null);
                return false;
            }
            return true;
        }
        /// 
        /// 更新HotPlating step数据
        /// 
        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);
            }
        }
        /// 
        /// 更新Power step步骤
        /// 
        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;
            }
        }
        /// 
        /// 等待Plating Delay结束
        /// 
        /// 
        private bool WaitPlatingDelay()
        {
            if (DateTime.Now.Subtract(_platingDelayTime).TotalSeconds >= _recipe.PlatingDelaySeconds)
            {
                return true;
            }
            return false;
        }
        /// 
        /// 检验步骤是否完成
        /// 
        /// 
        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("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;
        }
        /// 
        /// 检验Power是否Disable
        /// 
        /// 
        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;
        }
        /// 
        /// 检验电压电流的合理性
        /// 
        /// 
        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;
        }
        /// 
        /// 检验电流和电压合理性
        /// 
        /// 
        /// 
        /// 
        /// 
        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;
        }
        /// 
        /// 停止Linmot
        /// 
        /// 
        private bool StopLinmot()
        {
            return _device.StopLinmot();
        }
        /// 
        /// 停止电源
        /// 
        /// 
        private bool StopPowerSupplier()
        {
            if (string.IsNullOrEmpty(_side))
            {
                _device.SideAPowerSupplier.DisableOperation("", null);
                _device.SideBPowerSupplier.DisableOperation("", null);
            }
            else
            {
                CellPowerSupplier cellPowerSupplier = GetSidePowerSupplier();
                cellPowerSupplier.DisableOperation("", null);
            }
            return true;
        }
        /// 
        /// 切换成正常模式
        /// 
        /// 
        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;
        }
        /// 
        /// 启动
        /// 
        /// 
        /// 
        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(Module);
            _metalEntity = Singleton.Instance.GetModule(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.Instance.GetModule(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();
                _header.ProcessTransferList.AddRange(metalEntity.WaferHolderInfo.SchedulerModules);
                metalEntity.WaferHolderInfo.SchedulerModules.Clear();
            }
            _facilities = DEVICE.GetDevice("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(reservoirName);
                _standardHotMetalDevice = DEVICE.GetDevice(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(reservoirName);
                _compactMembranMetalDevice = DEVICE.GetDevice(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(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;
        }
    }
}