| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 | using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Text;using System.Threading.Tasks;using Aitex.Core.Common;using Aitex.Core.RT.DataCenter;using Aitex.Core.RT.Device;using Aitex.Core.RT.Event;using Aitex.Core.RT.Fsm;using Aitex.Core.RT.Log;using Aitex.Core.RT.SCCore;using Aitex.Core.Util;using Aitex.Sorter.Common;using Venus_RT.Modules;using Venus_RT.Modules.PMs;using MECF.Framework.Common.Equipment;using MECF.Framework.Common.Schedulers;using MECF.Framework.Common.SubstrateTrackings;using Venus_RT.Devices;namespace Venus_RT.Scheduler{    public class SchedulerPM : SchedulerModule    {        public override bool IsAvailable        {            get { return _entity.IsIdle /*&& _entity.IsOnline*/ && CheckTaskDone() && !_waitCompletejobClean; } // 测试TMCycle, 暂时注释掉 _entity.IsOnline        }        public override bool IsOnline        {            get { return _entity != null && _entity.IsOnline; }        }        public override bool IsError        {            get { return _entity.IsError; }        }        public bool IsIdle        {            get { return _entity.IsIdle && _entity.IsOnline && CheckTaskDone() ; }        }        public TaskType Task => _task;        private PMEntity _entity = null;        private ModuleName _taskRobot;        private EnumTransferType _taskTransferType;        private Hand _taskBlade;        private int _taskSlot;        private int _entityTaskToken = (int)FSM_MSG.NONE;        private DeviceTimer _timerProcess = new DeviceTimer();        private JetPMBase _pm;        private float _paramTemp;        public float Temperature        {            get            {                //if (SC.GetValue<bool>($"{Module}.Chiller.EnableChiller"))                //{                //    return _pm.CoolantOutletTempFB;                //}                //return _pm.SubstrateTempFB;                return _pm.CoolantOutletTempFB;            }        }        public RD_TRIG IdlePurgeTrig { get; set; }        public Stopwatch IdlePurgeTimer { get; set; }        public int IdlePurgeTime { get; set; }        public int IdlePurgeNextRunTime { get; set; }        public RD_TRIG IdleCleanTrig { get; set; }        public Stopwatch IdleCleanTimer { get; set; }        public int IdleCleanTime { get; set; }        public int IdleCleanNextRunTime { get; set; }        private bool _waitPreJobClean;        private bool _waitCompletejobClean;        private R_TRIG _trigIdleCleanFailed = new R_TRIG();        private R_TRIG _trigIdlePurgeFailed = new R_TRIG();        public RD_TRIG PreJobCleanTrig { get; set; }        public Stopwatch PreJobCleanTimer { get; set; }        public int PreJobCleanTime { get; set; }        public SchedulerPM(ModuleName chamber) : base(chamber.ToString())        {            _entity = Singleton<RouteManager>.Instance.GetPM(chamber);            _pm = DEVICE.GetDevice<JetPMBase>(Module.ToString());            IdlePurgeTrig = new RD_TRIG();            IdlePurgeTimer = new Stopwatch();            IdleCleanTrig = new RD_TRIG();            IdleCleanTimer = new Stopwatch();            PreJobCleanTrig = new RD_TRIG();            PreJobCleanTimer = new Stopwatch();            EventWaferArrived += WaferArrived;        }        public void InitClean()        {            DATA.Subscribe($"{Module}.IdlePurgeNextRunTime", () => IdlePurgeNextRunTime);            DATA.Subscribe($"{Module}.IdleCleanNextRunTime", () => IdleCleanNextRunTime);        }        public override bool IsReadyForPick(ModuleName robot, int slot, Hand blade)        {            return _entity.IsPrepareTransferReady(robot, EnumTransferType.Pick, slot, blade)                   && WaferManager.Instance.CheckHasWafer(ModuleHelper.Converter(_module), slot);        }        public override bool IsReadyForPlace(ModuleName robot, int slot, Hand blade)        {            return _entity.IsPrepareTransferReady(robot, EnumTransferType.Place, slot, blade)                   && WaferManager.Instance.CheckNoWafer(ModuleHelper.Converter(_module), slot);        }        public bool IsTemperatureReady(float temp)        {            return Math.Abs(Temperature - temp) < SC.GetValue<double>("System.MaxTemperatureToleranceTransferWafer");        }        public bool IsPrepareTransfer(ModuleName robot, EnumTransferType type, int slot)        {            return _task == TaskType.PrepareTransfer && _taskRobot == robot && _taskSlot == slot &&                   _taskTransferType == type;        }        public override bool PrepareTransfer(ModuleName robot, EnumTransferType type, int slot)        {            _task = TaskType.PrepareTransfer;            _taskRobot = robot;            _taskSlot = slot;            _taskTransferType = type;            _entityTaskToken = _entity.InvokePrepareTransfer(robot, type, slot);            LogTaskStart(_task, $"{robot} {type} slot {slot + 1}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public bool PrepareTransfer(ModuleName robot, EnumTransferType type, int slot, float temp, Hand blade)        {            _task = TaskType.PrepareTransfer;            _taskRobot = robot;            _taskSlot = slot;            _taskBlade = blade;            _taskTransferType = type;            _entityTaskToken = _entity.InvokePrepareTransfer(robot, type, slot, temp);            LogTaskStart(_task, $"{robot} {type} slot {slot + 1}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public bool PrepareTransfer(ModuleName robot, EnumTransferType type, int slot, float temp, Hand blade, WaferSize size)        {            _task = TaskType.PrepareTransfer;            _taskRobot = robot;            _taskSlot = slot;            _taskBlade = blade;            _taskTransferType = type;            _entityTaskToken = _entity.InvokePrepareTransfer(robot, type, slot, temp, size);            LogTaskStart(_task, $"{robot} {type} slot {slot + 1}, {size}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public override bool PostTransfer(ModuleName robot, EnumTransferType type, int slot)        {            StopWaitTransfer(robot);            _task = TaskType.PostTransfer;            _taskRobot = robot;            _taskSlot = slot;            _taskTransferType = type;            _entityTaskToken = _entity.InvokePostTransfer(robot, type, slot);            LogTaskStart(_task, $"{robot} {type} slot {slot + 1}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public override bool PostTransfer(ModuleName robot)        {            StopWaitTransfer(robot);            _task = TaskType.PostTransfer;            _taskRobot = robot;            _taskSlot = _inTransferSlot;            _taskTransferType = _inTransferType;            _entityTaskToken = _entity.InvokePostTransfer(robot, _inTransferType, _inTransferSlot);            LogTaskStart(_task, $"{robot} {_inTransferType} slot {_inTransferSlot + 1}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public override bool Process(string recipeName, bool isCleanRecipe, bool withWafer, WaferInfo wafer)        {            _task = TaskType.Process;            LogTaskStart(_task, $"recipe: {recipeName}, clean: {isCleanRecipe}, with wafer: {withWafer}");            if (SC.GetValue<bool>("System.IsATMMode"))            {                int time = SC.GetValue<int>("System.ATMCyclePMDelayTime");                _timerProcess.Start(time * 1000);                EV.PostInfoLog("Scheduler", $"System run in ATM mode, process skipped, delay {time} seconds");                WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.InProcess);                return true;            }            else            {                _entityTaskToken = _entity.InvokeProcess(recipeName, wafer.WaferOrigin, withWafer);                return _entityTaskToken != (int)FSM_MSG.NONE;            }        }        public override bool Preheating(float temperature)        {            _task = TaskType.Heating;            _paramTemp = temperature;            _entityTaskToken = _entity.InvokePreHeat(temperature);            LogTaskStart(_task, $"preheat to {temperature}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public bool CheckTaskDone()        {            bool ret = false;            switch (_task)            {                case TaskType.None:                    ret = true;                    break;                case TaskType.PrepareTransfer:                    ret = _entity.CheckAcked(_entityTaskToken) && _entity.IsPrepareTransferReady(_taskRobot, _taskTransferType == EnumTransferType.Swap ? EnumTransferType.Pick : _taskTransferType, _taskSlot, _taskBlade);                    break;                case TaskType.PostTransfer:                    ret = _entity.CheckAcked(_entityTaskToken);                    break;                case TaskType.Heating:                    ret = _entity.CheckAcked(_entityTaskToken) && IsTemperatureReady(_paramTemp);                    break;                case TaskType.Process:                case TaskType.IdlePurgeProcess:                case TaskType.IdleCleanProcess:                case TaskType.PreJobProcess:                case TaskType.CompleteJobProcess:                    if (SC.GetValue<bool>("System.IsATMMode"))                    {                        ret = _timerProcess.IsTimeout() && _entity.IsIdle;                        if (ret)                            WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Completed);                    }                    else                    {                        ret = _entity.CheckAcked(_entityTaskToken) && _entity.IsIdle;                    }                    break;            }            if (ret && _task != TaskType.None)            {                LogTaskDone(_task, "");                _task = TaskType.None;            }            return ret;        }        public bool Monitor()        {            return true;        }        public void SetPMAuto()        {            _entity.SetAuto();        }        public bool IdlePurgeProcess(string recipeName)        {            _task = TaskType.IdlePurgeProcess;            _entityTaskToken = _entity.InvokeClean(recipeName, "", false);            LogTaskStart(_task, $"recipe: {recipeName}, clean: {false}, with wafer: {false}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public bool IdleCleanProcess(string recipeName)        {            _task = TaskType.IdleCleanProcess;            _entityTaskToken = _entity.InvokeClean(recipeName, "", false);            LogTaskStart(_task, $"recipe: {recipeName}, clean: {true}, with wafer: {false}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public void PreJobClean()        {            var enableJobClean = SC.GetValue<bool>($"{Module}.JobClean.IsEnabled");            var enablePreJobClean = SC.GetValue<bool>($"{Module}.JobClean.EnablePreJobClean");            _waitPreJobClean = enableJobClean && enablePreJobClean;        }        public bool PreJobProcess(string recipeName)        {            _task = TaskType.PreJobProcess;            _entityTaskToken = _entity.InvokeClean(recipeName, "", false);            LogTaskStart(_task, $"recipe: {recipeName}, clean: {true}, with wafer: {false}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public void CompleteJobClean()        {            var enableJobClean = SC.GetValue<bool>($"{Module}.JobClean.IsEnabled");            var enableCompleteJobClean = SC.GetValue<bool>($"{Module}.JobClean.EnableCompleteJobClean");            _waitCompletejobClean = enableJobClean && enableCompleteJobClean;        }        public bool CompleteJobProcess(string recipeName)        {            _task = TaskType.CompleteJobProcess;            _entityTaskToken = _entity.InvokeClean(recipeName, "", false);            LogTaskStart(_task, $"recipe: {recipeName}, clean: {true}, with wafer: {false}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        private void WaferArrived(object sender, EventArgs e)        {            WaferInfo wafer = WaferManager.Instance.GetWafer(Module, 0);            var recipeName = Module == ModuleName.PMA                ? wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["PMARecipe"]                : wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["PMBRecipe"];            Process((string)recipeName, false, true, wafer);        }        #region clean task        internal void ResetIdlePurgeTime()        {            IdlePurgeTimer.Restart();        }        internal void ResetIdleCleanTime()        {            IdleCleanTimer.Restart();        }        public bool ResetClean(bool resetPurge, bool resetClean, bool jobClean)        {            if (resetPurge)            {                IdlePurgeTrig.RST = true;                IdlePurgeTimer.Stop();                IdlePurgeTime = 0;            }            if (resetClean)            {                IdleCleanTrig.RST = true;                IdleCleanTimer.Stop();                IdleCleanTime = 0;            }            if (jobClean)            {                _waitPreJobClean = false;                _waitCompletejobClean = false;                PreJobCleanTrig.RST = true;                PreJobCleanTimer.Stop();            }            return true;        }        public void MonitorCleanTasks()        {            var hasWafer = WaferManager.Instance.CheckHasWafer(Module, 0);            var enablePurge = false;//SC.GetValue<bool>($"{Module}.IdlePurge.IsEnabled");            var enableClean = SC.GetValue<bool>($"{Module}.IdleClean.IsEnabled");            #region Idle Purge            IdlePurgeTrig.CLK = (IsIdle || _task != TaskType.IdlePurgeProcess) && enablePurge && !hasWafer;            if (IdlePurgeTrig.R)            {                LOG.Write( eEvent.INFO_PM, Module, $"{Module} idle purge start calc elapse time");                IdlePurgeTimer.Restart();            }            if (IdlePurgeTrig.T)            {                LOG.Write(eEvent.INFO_PM, Module, $"{Module} idle purge stopped calc elapse time");                ResetClean(true, false, false);            }            if (IdlePurgeTimer.IsRunning)            {                IdlePurgeTime = (int)IdlePurgeTimer.ElapsedMilliseconds / 1000;                int idlePurgeTimeSetPoint = SC.GetValue<int>($"{Module}.IdlePurge.IdlePurgeTime");                var nextRunTime = idlePurgeTimeSetPoint - IdlePurgeTime;                if (nextRunTime < 0)                    nextRunTime = 0;                if (enablePurge)                {                    if (nextRunTime <= 0 && IsAvailable)                    {                        var recipe = SC.GetStringValue($"{Module}.IdlePurge.IdlePurgeRecipe");                        if (string.IsNullOrEmpty(recipe))                        {                            _trigIdlePurgeFailed.CLK = true;                            LOG.Write(eEvent.INFO_PM, Module, $"{Module} Idle purge can not run, recipe is empty");                            ResetClean(true, false, false);                        }                        else if (hasWafer)                        {                            _trigIdlePurgeFailed.CLK = true;                            LOG.Write(eEvent.INFO_PM, Module, $"{Module} Idle purge can not run, has wafer");                            ResetClean(true, false, false);                        }                        else                        {                            _trigIdlePurgeFailed.CLK = false;                            LOG.Write(eEvent.INFO_PM, Module, $"{Module} Start run idle purge recipe {recipe}");                            IdlePurgeProcess("ALD\\Process\\" + recipe);                        }                        if (_trigIdlePurgeFailed.Q)                        {                            LOG.Write(eEvent.WARN_PM, Module, "Can not run idle purge recipe");                        }                    }                }                else                {                    nextRunTime = 0;                }                IdlePurgeNextRunTime = nextRunTime;            }            else            {                IdlePurgeNextRunTime = 0;            }            #endregion            #region Idle Clean            IdleCleanTrig.CLK = (IsIdle || _task != TaskType.IdleCleanProcess) && enableClean && !hasWafer;            if (IdleCleanTrig.R)            {                LOG.Write(eEvent.INFO_PM, Module, $"{Module} idle clean start calc elapse time");                IdleCleanTimer.Restart();            }            if (IdleCleanTrig.T)            {                LOG.Write(eEvent.INFO_PM, Module, $"{Module} idle clean stopped calc elapse time");                ResetClean(false, true, false);            }            if (IdleCleanTimer.IsRunning)            {                IdleCleanTime = (int)IdleCleanTimer.ElapsedMilliseconds / 1000;                int idleCleanTimeSetPoint = SC.GetValue<int>($"{Module}.IdleClean.IdleCleanTime");                var nextRunTime = idleCleanTimeSetPoint - IdleCleanTime;                if (nextRunTime < 0)                    nextRunTime = 0;                if (enableClean)                {                    if (nextRunTime <= 0 && IsAvailable)                    {                        var recipe = SC.GetStringValue($"{Module}.IdleClean.IdleCleanRecipe");                        if (string.IsNullOrEmpty(recipe))                        {                            _trigIdleCleanFailed.CLK = true;                            LOG.Write(eEvent.INFO_PM, Module, $"{Module} Idle clean can not run, recipe is empty");                            ResetClean(false, true, false);                        }                        else if (hasWafer)                        {                            _trigIdleCleanFailed.CLK = true;                            LOG.Write(eEvent.INFO_PM, Module, $"{Module} Idle clean can not run, has wafer");                            ResetClean(false, true, false);                        }                        else                        {                            _trigIdleCleanFailed.CLK = false;                            LOG.Write(eEvent.INFO_PM, Module, $"{Module} Start run idle Clean recipe {recipe}");                            IdleCleanProcess($"{Module}\\" + recipe);                        }                        if (_trigIdleCleanFailed.Q)                        {                            EV.PostWarningLog(Module.ToString(), "Can not run idle clean recipe");                        }                    }                }                else                {                    nextRunTime = 0;                }                IdleCleanNextRunTime = nextRunTime;            }            else            {                IdleCleanNextRunTime = 0;            }            #endregion            #region PreJob Clean            var enableJobClean = SC.GetValue<bool>($"{Module}.JobClean.IsEnabled");            var enablePreJobClean = SC.GetValue<bool>($"{Module}.JobClean.EnablePreJobClean");            var enableCompleteJobClean = SC.GetValue<bool>($"{Module}.JobClean.EnableCompleteJobClean");            if (enableJobClean && enableCompleteJobClean && _waitCompletejobClean && IsIdle)            {                var recipe = SC.GetStringValue($"{Module}.JobClean.CompleteJobCleanRecipe");                if (string.IsNullOrEmpty(recipe))                {                    EV.PostWarningLog(Module.ToString(), "complete job clean can not run, recipe is empty");                }                else if (hasWafer)                {                    EV.PostWarningLog(Module.ToString(), "complete job clean can not run, has wafer");                }                else                {                    EV.PostInfoLog(Module.ToString(), $"Start run complete job clean recipe {recipe}");                    CompleteJobProcess($"{Module}\\" + recipe);                }                _waitCompletejobClean = false;            }            PreJobCleanTrig.CLK = enableJobClean && enablePreJobClean && IsIdle;            if (PreJobCleanTrig.R)            {                PreJobCleanTimer.Restart();            }            if(PreJobCleanTrig.T)            {                ResetClean(false, false, true);            }            if (PreJobCleanTimer.IsRunning && _waitPreJobClean)            {                PreJobCleanTime = (int)PreJobCleanTimer.ElapsedMilliseconds / 1000;                int PreJobCleanIdleTimeSP = SC.GetValue<int>($"{Module}.JobClean.IdleCleanTime");                if(PreJobCleanTime >= PreJobCleanIdleTimeSP)                {                    var recipe = SC.GetStringValue($"{Module}.JobClean.PreJobCleanRecipe");                    if (string.IsNullOrEmpty(recipe))                    {                        EV.PostWarningLog(Module.ToString(), "pre job clean can not run, recipe is empty");                    }                    else if (hasWafer)                    {                        EV.PostWarningLog(Module.ToString(), "pre job clean can not run, has wafer");                    }                    else                    {                        EV.PostInfoLog(Module.ToString(), $"Start run pre job clean recipe {recipe}");                        PreJobProcess($"{Module}\\" + recipe);                    }                }            }            #endregion        }        #endregion    }}
 |