| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892 | using System;using System.Collections.Generic;using System.Xml;using Aitex.Core.Equipment.SusceptorDefine;using Aitex.Core.RT.Device;using Aitex.Core.RT.Event;using Aitex.Core.RT.Log;using Aitex.Core.RT.OperationCenter;using Aitex.Core.RT.RecipeCenter;using Aitex.Core.RT.Routine;using Aitex.Core.RT.SCCore;using Aitex.Core.Util;using MECF.Framework.Common.DBCore;using MECF.Framework.Common.Equipment;using VirgoRT.Devices;using VirgoRT.Module;namespace VirgoRT.Modules.PMs{    class ProcessRoutine : PMRoutineBase    {        private enum RecipeEngineState        {            Error,            RecipeCompleted,            ExecStep,            TimeWait,            EndPointWait,            StepCompleted,            Paused,        }        private object _lockerTotalCycle = new object();        private Dictionary<string, int> _recipeTotalCycle = new Dictionary<string, int>();        private DeviceTimer _beginPauseTimer = new DeviceTimer();        private object _recipeLocker = new object();        private RecipeEngineState _state = RecipeEngineState.ExecStep;        private RecipeEngineState _pausedState = RecipeEngineState.ExecStep;        private DeviceTimer _estimatedTimeCalcTimer = new DeviceTimer();//用于定时计算工艺程序估计的结束时间        public DateTime RecipeStartTime { get; private set; }        public int RecipeChangeNo { get; private set; }        public string CurrentRecipeBaseName { get; private set; }        public string CurrentRecipeRunningName { get; private set; }        public string CurrentRecipeContent { get; private set; }        public string CurrentLotName { get; set; }        public string CurrentRecipeGuid { get; set; }        private List<RecipeStep> _recipeStepList = new List<RecipeStep>();        public List<RecipeStep> CurrentRecipeStepList        {            get            {                return _recipeStepList;            }            set            {                _recipeStepList = value;            }        }        public RecipeHead CurrentRecipeHead { get; set; }        public int CurStepNum { get; private set; }        public int CurStepTotalLoopCount { get; private set; }        public double CurStepTotalTime        {            get            {                if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)                    return 0;                return _recipeStepList[CurStepNum].StepTime * 1000;            }        }        public int CurrentLoopCount        {            get;            private set;        }        private DeviceTimer StepTimer = new DeviceTimer();        public bool IsPaused        {            private set;            get;        }        public string CurStepComment        {            get            {                if (_recipeStepList == null || _recipeStepList.Count == 0)                    return string.Empty;                return _recipeStepList[CurStepNum].StepName;            }        }        public double CurStepLeftTime        {            get            {                if (IsPaused)                    return StepTimer.GetTotalTime() - StepTimer.GetElapseTime() + _beginPauseTimer.GetElapseTime();                //return Math.Max(0,StepTimer.GetTotalTime() - StepTimer.GetElapseTime());                return StepTimer.GetTotalTime() - StepTimer.GetElapseTime();            }        }        public double CurStepElpasedTime        {            get            {                if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)                    return 0;                return StepTimer.GetElapseTime();            }        }        public double CurStepTotalRfTime        {            get            {                if (_recipeStepList == null || _recipeStepList.Count == 0 || _state == RecipeEngineState.RecipeCompleted || _state == RecipeEngineState.Error)                    return 0;                if (_recipeStepList[CurStepNum].RecipeCommands.ContainsKey("Rf.SetPower") &&                    !string.IsNullOrEmpty(_recipeStepList[CurStepNum].RecipeCommands["Rf.SetPower"]) &&                    Convert.ToDouble(_recipeStepList[CurStepNum].RecipeCommands["Rf.SetPower"]) > 0.1)                    return CurStepTotalTime;                return 0;            }        }        public int TotalCycle        {            get            {                if (string.IsNullOrEmpty(DateTimeRecipeBaseName))                    return 0;                lock (_lockerTotalCycle)                {                    if (_recipeTotalCycle.ContainsKey(DateTimeRecipeBaseName))                        return _recipeTotalCycle[DateTimeRecipeBaseName];                }                return 0;            }        }        public string DateTimeRecipeBaseName        {            get            {                if (string.IsNullOrEmpty(CurrentRecipeBaseName))                    return "";                return DateTime.Now.ToString("yyyyMMdd") + CurrentRecipeBaseName;            }        }        public double PausedTime        {            get            {                return IsPaused ? _beginPauseTimer.GetElapseTime() : 0;            }        }        public double EstimatedTotalLeftTime        {            get;            private set;        }        public int RecipeTotalStepNum        {            get            {                return _recipeStepList.Count;            }        }        protected PMEntity _chamberEntity;        private RecipeFACallback _faCallback;        private RecipeDBCallback _dbCallback;        private Fdc _fdc;        public ProcessRoutine(JetPM chamber, PMEntity entity) : base(chamber)        {            Name = "ProcessRoutine";            RecipeStartTime = new DateTime(0);            EstimatedTotalLeftTime = 0;            CalcEstimatedRecipeEndTime();            _chamberEntity = entity;            _faCallback = new RecipeFACallback();            _dbCallback = new RecipeDBCallback();            _fdc = new Fdc(Module);        }        public Result Start(params object[] param)        {            RecipeStartTime = DateTime.Now;            CurrentRecipeBaseName = (string)param[0];            CurrentRecipeRunningName = (string)param[1];            RecipeChangeNo = (int)param[2];            CurrentLotName = (string)param[3];            CurrentRecipeContent = (string)param[4];            CurrentRecipeHead = (RecipeHead)param[5];            CurrentRecipeStepList = (List<RecipeStep>)param[6];            if (!_chamber.IsRFGInterlockOn)            {                EV.PostAlarmLog(Module, "RF Interlock sensor error");                return Result.VERIFYFAIL;            }            lock (_lockerTotalCycle)            {                if (_recipeTotalCycle.ContainsKey(DateTimeRecipeBaseName))                    _recipeTotalCycle[DateTimeRecipeBaseName] += 1;                else                {                    _recipeTotalCycle[DateTimeRecipeBaseName] = 1;                }                List<string> keys = new List<string>();                foreach (KeyValuePair<string, int> item in _recipeTotalCycle)                {                    if (!item.Key.StartsWith(DateTime.Now.ToString("yyyyMMdd")))                        keys.Add(item.Key);                }                foreach (string key in keys)                {                    _recipeTotalCycle.Remove(key);                }            }            _chamber.SetValveOnOff(ValveType.PROCESS, true);            CurStepNum = CurStepTotalLoopCount = 0;            _estimatedTimeCalcTimer.Start(1000);            EV.PostInfoLog(Module, $"Recipe {CurrentRecipeRunningName} Start running");            _chamberEntity.RecipeRunningInfo.InnerId = Guid.NewGuid();            _chamberEntity.RecipeRunningInfo.BeginTime = DateTime.Now;            _chamberEntity.RecipeRunningInfo.RecipeName = CurrentRecipeBaseName;            _chamberEntity.RecipeRunningInfo.RecipeStepList = CurrentRecipeStepList;            //ProcessDataRecorder.UpdateStatus(RecipeRunGuid.ToString(), SusceptorStatus.InProcessing.ToString(), Module);            _state = RecipeEngineState.ExecStep;            double totalTime = 0;            foreach (var step in CurrentRecipeStepList)            {                totalTime += step.StepTime;            }            _dbCallback.RecipeStart(_chamber.Module.ToString(), 0, _chamberEntity.RecipeRunningInfo.InnerId.ToString(), _chamberEntity.RecipeRunningInfo.RecipeName);            _dbCallback.RecipeUpdateStatus(_chamberEntity.RecipeRunningInfo.InnerId.ToString(), "InProcess", (float)totalTime);            _faCallback.RecipeStart(_chamber.Module.ToString(), CurrentRecipeBaseName);            _fdc.Reset();            _chamberEntity.EndPointRecipeStart(CurrentRecipeBaseName);            return Result.RUN;        }        /// <summary>        /// quiting current state        /// </summary>        /// <param name="nextState"></param>        public void Exit()        {            _chamber.IsPressureToleranceEnabled = false;            var ts = DateTime.Now - RecipeStartTime;            var totalTime = $"{Convert.ToInt32(ts.TotalHours)}:{ts.Minutes}:{ts.Seconds}";            bool isProcessCompleted = _state == RecipeEngineState.RecipeCompleted;            if (isProcessCompleted)            {                EV.PostInfoLog(Module, $"Recipe {CurrentRecipeRunningName} Completed");                _faCallback.RecipeComplete(_chamber.Module.ToString(), CurrentRecipeBaseName);                _dbCallback.RecipeComplete(_chamberEntity.RecipeRunningInfo.InnerId.ToString());                _fdc.Stop();            }            else            {                _faCallback.RecipeFailed(_chamber.Module.ToString(), CurrentRecipeBaseName);                _dbCallback.RecipeFailed(_chamberEntity.RecipeRunningInfo.InnerId.ToString());                _chamberEntity.StopEndPoint();                string info = string.Format("Recipe:{0}\r\nStart time:{1:yyyy/MM/dd HH:mm:ss}\r\nEnd time:{2:yyyy/MM/dd HH:mm:ss}\r\nTotal time:{3}",                    CurrentRecipeRunningName, RecipeStartTime, DateTime.Now, totalTime);                EV.PostWarningLog(Module, info);                EV.PostPopDialogMessage(EventLevel.Warning, $"{Module} recipe was aborted", info);            }            _chamberEntity.EndPointRecipeStop();            //重置工艺程序名            CurrentRecipeRunningName = string.Empty;            CurrentLotName = string.Empty;        }        public Result Monitor()        {            string reason = string.Empty;            CalcEstimatedRecipeEndTime();            //工艺程序运行监控,自动打开阀门如果对应的MFC设定设置大于0            _chamber.Monitor();            if (_chamber.IsError)                return Result.FAIL;            //工艺程序运行引擎            lock (_recipeLocker)            {                try                {                    switch (_state)                    {                        case RecipeEngineState.ExecStep:                            {                                //工艺程序循环设置                                if (_recipeStepList[CurStepNum].IsLoopStartStep)                                {                                    CurStepTotalLoopCount = _recipeStepList[CurStepNum].LoopCount;                                    if (CurStepTotalLoopCount == 0)                                    {                                        CurrentLoopCount = 0;                                    }                                    else                                    {                                        CurrentLoopCount++;                                    }                                }                                //当前工艺程序步的定时器设定                                StepTimer.Start(_recipeStepList[CurStepNum].StepTime * 1000);                                //发送信息到用户界面                                EV.PostInfoLog(Module, $"Recipe {CurrentRecipeRunningName} No {CurStepNum + 1} step start:{_recipeStepList[CurStepNum].StepName}");                                //执行工艺程序命令                                foreach (var cmdkey in _recipeStepList[CurStepNum].RecipeCommands.Keys)                                {                                    string recipeCmd = cmdkey;                                    string param = _recipeStepList[CurStepNum].RecipeCommands[recipeCmd];                                    if (string.IsNullOrWhiteSpace(param)) continue;                                    if (recipeCmd == "EPD.SetConfig" && !SC.GetValue<bool>($"{Module}.EPD.IsEnabled"))                                        continue;                                                                            if (!OP.CanDoOperation($"{Module}." + recipeCmd, out reason, param))                                    {                                        EV.PostAlarmLog(Module, $"Can not do {recipeCmd}, {reason}");                                        return Result.FAIL;                                    }                                    else                                    {                                        var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);                                        if (_recipeStepList[CurStepNum].IsJumpStep)                                            rampTime_ms = 0;                                        if (recipeCmd == "EPD.SetConfig")                                        {                                            if(SC.GetValue<bool>($"{Module}.EPD.IsEnabled"))                                                OP.DoOperation($"{Module}." + recipeCmd, out string reason1, rampTime_ms, CurStepNum, _recipeStepList[CurStepNum].RecipeCommands[recipeCmd]);                                        }                                        else                                        {                                            OP.DoOperation($"{Module}." + recipeCmd, out string reason1, rampTime_ms, param);                                        }                                    }                                }                                string endby = _recipeStepList[CurStepNum].EndBy;                                if (!string.IsNullOrEmpty(endby) && endby == "EndByEndPoint")                                {                                    _state = RecipeEngineState.EndPointWait;                                }                                else                                {                                    _state = RecipeEngineState.TimeWait;                                }                                _faCallback.RecipeStepStart(_chamber.Module.ToString(), CurrentRecipeBaseName, CurStepNum);                                _dbCallback.RecipeStepStart(_chamberEntity.RecipeRunningInfo.InnerId.ToString(), CurStepNum, _chamberEntity.RecipeRunningInfo.RecipeStepList[CurStepNum].StepName, (float)_chamberEntity.RecipeRunningInfo.RecipeStepList[CurStepNum].StepTime);                                _fdc.Start(_chamberEntity.RecipeRunningInfo.RecipeStepList[CurStepNum].RecipeCommands);                            }                            break;                        case RecipeEngineState.TimeWait:                            _chamber.CheckPressureStability();                            if (StepTimer.IsTimeout())                            {                                _state = RecipeEngineState.StepCompleted;                            }                            break;                        case RecipeEngineState.EndPointWait:                            {                                if (_chamberEntity.CheckEndPoint())                                {                                    _state = RecipeEngineState.StepCompleted;                                }                                if (StepTimer.IsTimeout())                                {                                    if (_recipeStepList[CurStepNum].FaultIfNoEPDTrigger)                                    {                                        EV.PostAlarmLog(Module, $"{_chamberEntity.Module} EPD step not triggered, timeout");                                        return Result.FAIL;                                    }                                    else                                    {                                        EV.PostWarningLog(Module, $"{_chamberEntity.Module} EPD step not triggered, skipped");                                    }                                    _state = RecipeEngineState.StepCompleted;                                }                            }                            break;                        case RecipeEngineState.Paused:                            break;                        case RecipeEngineState.StepCompleted:                            {                                EV.PostInfoLog(Module, $"Recipe {CurrentRecipeRunningName} No {CurStepNum + 1} step completed");                                _chamberEntity.StopEndPoint();                                _faCallback.RecipeStepEnd(_chamber.Module.ToString(), CurrentRecipeBaseName, CurStepNum, _fdc.DataList);                                _dbCallback.RecipeStepEnd(_chamberEntity.RecipeRunningInfo.InnerId.ToString(), CurStepNum, _fdc.DataList);                                _fdc.Stop();                                //判断是否当前步循环终止                                if (_recipeStepList[CurStepNum].IsLoopEndStep)                                {                                    //重新读取循环的设定次数                                    for (int nn = CurStepNum; nn >= 0; nn--)                                    {                                        if (_recipeStepList[nn].IsLoopStartStep)                                        {                                            CurStepTotalLoopCount = _recipeStepList[nn].LoopCount;                                            break;                                        }                                    }                                    if (CurrentLoopCount >= CurStepTotalLoopCount)                                    {                                        CurrentLoopCount = CurStepTotalLoopCount = 0;                                        CurStepNum++;                                    }                                    else                                    {                                        int n = CurStepNum - 1;                                        int next = -1;                                        while (n >= 0)                                        {                                            if (_recipeStepList[n].IsLoopStartStep)                                            {                                                next = n;                                                break;                                            }                                            n--;                                        }                                        if (next == -1)                                            throw new Exception("Loop End control error");                                        CurStepNum = next;                                    }                                }                                else                                {                                    if (CurStepNum < _recipeStepList.Count - 1)                                    {                                        CurStepNum++;                                        _state = RecipeEngineState.ExecStep;                                    }                                    else                                    {                                        EV.PostInfoLog(Module, $"Recipe {CurrentRecipeRunningName} finish");                                        CurStepNum = _recipeStepList.Count - 1;                                        _state = RecipeEngineState.RecipeCompleted;                                        return Result.DONE;                                    }                                }                            }                            break;                        case RecipeEngineState.RecipeCompleted:                            return Result.DONE;                        case RecipeEngineState.Error:                            return Result.FAIL;                        default:                            break;                    }                }                catch (Exception ex)                {                    EV.PostAlarmLog(Module, $"{CurStepNum + 1}, grammar error, {ex.Message}");                    return Result.FAIL;                }            }            return Result.RUN;        }        /// <summary>        /// 暂停工艺程序运行        /// </summary>        public void PauseRecipe()        {            if (_state != RecipeEngineState.TimeWait && _state != RecipeEngineState.EndPointWait)                return;            if (!IsPaused)            {                string reason = string.Empty;                IsPaused = true;                _pausedState = _state;                _state = RecipeEngineState.Paused;                _beginPauseTimer.Start(0);                EV.PostInfoLog(Module, $"Recipe'{CurrentRecipeRunningName}' No {CurStepNum + 1} step pause");            }        }        /// <summary>        /// 恢复工艺程序运行        /// </summary>        public void ResumeRecipe()        {            if (IsPaused)            {                //update current recipe step time                string recipeXml = CurrentRecipeContent;                int currentStepNo = CurStepNum;                XmlDocument xmlDoc = new XmlDocument();                xmlDoc.LoadXml(recipeXml);                var stepNodes = xmlDoc.SelectNodes("/TableRecipeData/Step");                if (currentStepNo >= 0 && currentStepNo < stepNodes.Count)                {                    var curStepNode = stepNodes[currentStepNo] as XmlElement;                    var curStepNewTime = CurStepTotalTime + PausedTime;                    if (curStepNewTime < 0)                        curStepNewTime = 0;                    TimeSpan tspan = new TimeSpan(0, 0, 0, 0, (int)curStepNewTime);                    var timeString =                        $"{((int)tspan.TotalHours).ToString("00")}:{tspan.Minutes.ToString("00")}:{tspan.Seconds.ToString("00")}";                    curStepNode.SetAttribute("Time", timeString);                    LOG.Write($"执行Resume命令,将当前第{currentStepNo}步时间修改为{timeString}");                    UpdateRecipe(xmlDoc.OuterXml);                }                //Resume recipe                IsPaused = false;                _state = _pausedState;                EV.PostInfoLog(Module, $"Recipe'{CurrentRecipeRunningName}' No {CurStepNum + 1} step continue");                //resume recipe                double stepElapsedTime = StepTimer.GetElapseTime() - _beginPauseTimer.GetElapseTime();                double stepLeftTime = StepTimer.GetTotalTime() - stepElapsedTime;                if (stepLeftTime < 0)                    stepLeftTime = 0;                //更新当前步的定时器时间                StepTimer.Restart(StepTimer.GetTotalTime() + _beginPauseTimer.GetElapseTime());                //重新执行当前工艺程序步                foreach (var recipeCmd in _recipeStepList[CurStepNum].RecipeCommands.Keys)                {                    if (!DEVICE.CanDo(recipeCmd))                    {                        EV.PostInfoLog(Module, $"Unknown recipe command {recipeCmd}");                    }                    else                    {                        var rampTime_ms = (int)(_recipeStepList[CurStepNum].StepTime * 1000);                        if (_recipeStepList[CurStepNum].IsJumpStep)                            rampTime_ms = 0;                        DEVICE.Do(recipeCmd, rampTime_ms, false, _recipeStepList[CurStepNum].RecipeCommands[recipeCmd]);                    }                }            }        }        /// <summary>        /// 终止工艺程序运行        /// </summary>        public void AbortRecipe()        {            ResumeRecipe();            _chamberEntity.StopEndPoint();            _state = RecipeEngineState.Error;            CalcEstimatedRecipeEndTime();            _faCallback.RecipeFailed(_chamber.Module.ToString(), CurrentRecipeBaseName);            _dbCallback.RecipeFailed(_chamberEntity.RecipeRunningInfo.InnerId.ToString());            _fdc.Stop();            EV.PostInfoLog(Module, "Receipe abort");        }        /// <summary>        /// 跳至工艺程序下一步        /// </summary>        public void SkipCurrentRecipeStep()        {            if (_state == RecipeEngineState.Paused)            {                EV.PostInfoLog(Module, "Can not do Skip to next step command at the recipe Pause status");                return;            }            try            {                //update current recipe step time                string recipeXml = CurrentRecipeContent;                int currentStepNo = CurStepNum;                XmlDocument xmlDoc = new XmlDocument();                xmlDoc.LoadXml(recipeXml);                var stepNodes = xmlDoc.SelectNodes("/TableRecipeData/Step");                if (currentStepNo >= 0 && currentStepNo < stepNodes.Count)                {                    var curStepNode = stepNodes[currentStepNo] as XmlElement;                    var curStepElapsedTime = CurStepTotalTime - CurStepLeftTime;//ms                    if (curStepElapsedTime < 0)                        curStepElapsedTime = 0;                    //TimeSpan tspan = new TimeSpan(0, 0, 0, 0, (int)curStepElapsedTime);                    //var timeString =                    //    $"{((int)tspan.TotalHours).ToString("00")}:{tspan.Minutes.ToString("00")}:{tspan.Seconds.ToString("00")}";                    string timeString = ((int)(curStepElapsedTime / 1000)).ToString();                    curStepNode.SetAttribute("Time", timeString);                    LOG.Write($"step skipped,step {currentStepNo} time changed to {timeString}");                    //recipe update command                    UpdateRecipe(xmlDoc.OuterXml);                }            }            catch (Exception ex)            {                LOG.Write(ex);            }            if (_state == RecipeEngineState.EndPointWait || _state == RecipeEngineState.TimeWait)            {                _state = RecipeEngineState.StepCompleted;                //send informational event                EV.PostMessage(Module, EventEnum.GeneralInfo, Module, CurrentRecipeRunningName, CurStepNum + 1);            }        }        public bool UpdateRecipe(string newRecipeContent)        {            lock (_recipeLocker)            {                RecipeHead head = null;                List<RecipeStep> newRecipeData = null;                if (!Recipe.Parse(Module, newRecipeContent, out head, out newRecipeData))                {                    EV.PostMessage(Module, EventEnum.DefaultAlarm, Module, CurrentRecipeRunningName);                    return false;                }                else                {                    string oldRecipeName = CurrentRecipeRunningName;                    CurrentRecipeRunningName =                        $"{DateTime.Now:yyyyMMddHHmmss}-{CurrentRecipeBaseName}-({RecipeChangeNo++})";                    //update local recipe data                    _recipeStepList = newRecipeData;                    CurrentRecipeContent = newRecipeContent;                    //send informational event                    EV.PostInfoLog(Module, $"Recipe'{oldRecipeName}' No {CurStepNum + 1} step,update recipe content '{CurrentRecipeRunningName}");                    RecipeFileManager.Instance.SaveRecipeHistory(ModuleName.System.ToString(), CurrentRecipeRunningName, CurrentRecipeContent);                }            }            return true;        }        public override void Abort()        {            _dbCallback.RecipeFailed(_chamberEntity.RecipeRunningInfo.InnerId.ToString() );            base.Abort();        }        public override string ToString()        {            return "recipe running";        }        /// <summary>        /// 工艺程序估计结束时间计算        /// </summary>        protected void CalcEstimatedRecipeEndTime()        {            try            {                //(*计算当前工艺程序预计所需的总时间,从当前步开始计算剩余步的估算时间+已经既成事实的时间 => 总的估计时间,采用该种方式进行总工艺时间理论上最为精确*)                if (!_estimatedTimeCalcTimer.IsTimeout())                    return;                _estimatedTimeCalcTimer.Start(1000);                EstimatedTotalLeftTime = 0;                if (_state == RecipeEngineState.RecipeCompleted)                    return;                if (!(CurStepNum >= 0 && CurStepNum <= _recipeStepList.Count - 1))                    return;                if (CurStepLeftTime > 0)                {                    EstimatedTotalLeftTime = CurStepLeftTime;                }                int nextBegin = CurStepNum;                //(*判断当前是否处于循环之中*)                bool IsInLoop = false;                int iNum1 = 0;                int iNum2 = 0;                //int j=i;                for (int j = CurStepNum; j < _recipeStepList.Count; j++)                {                    if (_recipeStepList[j].IsLoopEndStep)                    {                        iNum2 = j;                        IsInLoop = true;                        break;                    }                    else if (j > CurStepNum && _recipeStepList[j].IsLoopStartStep)                    {                        IsInLoop = false;                        break;                    }                }                if (IsInLoop)                {                    //(*当前步处于循环中*)                    iNum1 = CurStepNum;                    for (int j = CurStepNum; j >= 0; j--)                    {                        if (_recipeStepList[j].IsLoopStartStep)                        {                            iNum1 = j;                            break;                        }                    }                    for (int j = CurStepNum + 1; j <= iNum2; j++)                    {                        EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000 * (_recipeStepList[iNum1].LoopCount - CurrentLoopCount + 1);                    }                    for (int j = iNum1; j <= CurStepNum; j++)                    {                        EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000 * (_recipeStepList[iNum1].LoopCount - CurrentLoopCount);                    }                    nextBegin = iNum2 + 1;                }                else                {                    nextBegin++;                }                //(*当前步处于循环外*)                for (int j = nextBegin; j < _recipeStepList.Count; j++)                {                    if (_recipeStepList[j].IsLoopStartStep)                    {                        //j=i;                        iNum1 = j;                        iNum2 = j + 1;                        double lr1 = 0;                        for (int m = j; m < _recipeStepList.Count; m++)                        {                            lr1 += _recipeStepList[m].StepTime * 1000;                            if (_recipeStepList[m].IsLoopEndStep)                            {                                iNum2 = m;                                break;                            }                        }                        EstimatedTotalLeftTime = EstimatedTotalLeftTime + lr1 * _recipeStepList[iNum1].LoopCount;                        j = iNum2;                    }                    else                    {                        EstimatedTotalLeftTime += _recipeStepList[j].StepTime * 1000;                    }                    //END_WHILE                }            }            catch (Exception ex)            {                LOG.Write(ex);            }        }        public class RecipeRunningInfo        {            public Guid InnerId { get; set; }            public RecipeHead Head { get; set; }            public List<RecipeStep> RecipeStepList { get; set; }            public string RecipeName { get; set; }            public DateTime BeginTime { get; set; }            public DateTime EndTime { get; set; }            public int StepNumber { get; set; }            public string StepName { get; set; }            public double StepTime { get; set; }            public double StepElapseTime { get; set; }            public double TotalTime { get; set; }            public double TotalElapseTime { get; set; }        }    }}
 |