| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 | 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 Aitex.Core.RT.RecipeCenter;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;using Venus_Core;using MECF.Framework.Common.DataCenter;using System.IO;namespace Venus_RT.Scheduler{    public class SchedulerPM : SchedulerModule    {        public override bool IsAvailable        {            get { return _entity.IsIdle && _entity.IsInclude && (_entity.IsOnline || !Singleton<RouteManager>.Instance.IsAutoMode) && CheckTaskDone(); }        }        public override bool IsOnline        {            get { return _entity != null && _entity.IsOnline; }        }        public override bool IsError        {            get { return _entity.IsError; }        }        public override bool IsIdle        {            get { return _entity.IsIdle; }        }        public override bool IsVac        {            get { return _entity.IsVac; }        }        public override bool IsAtm        {            get { return _entity.IsAtm; }        }        public override int TimeToReady        {            get { return _entity.TimeToReady; }        }                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 int _idleCleanOpt = 0;        private int _idleCleanHourSetPoint;        private int _idleCleanWaferSetPoint;        private int _idleCleanWaferCount;        private string _idleCleanRecipe;        private DateTime _lastRunTime = new DateTime();        private float _paramTemp;        public float Temperature        {            get            {                return _entity.ChamberTemperature;            }        }        public JetChamber ChamberType        {            get            {                return _entity.ChamberType;            }        }        public SchedulerPM(ModuleName chamber) : base(chamber.ToString())        {            _entity = Singleton<RouteManager>.Instance.GetPM(chamber);            _pm = DEVICE.GetDevice<JetPMBase>(Module.ToString());            EventWaferArrived += WaferArrived;            LoadIdleCleanOpt();        }        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, RecipeType recipeType, WaferInfo wafer)        {            bool withWafer;            if (recipeType == RecipeType.Clean)            {                withWafer = false;            }            else            {                withWafer = true;            }            _task = TaskType.Process;            LogTaskStart(_task, $"recipe: {recipeName}, clean: {isCleanRecipe}, with wafer: {withWafer}");            if (RouteManager.IsATMMode)            {                int time = SC.GetValue<int>("System.ATMCyclePMDelayTime");                _timerProcess.Start(time * 1000);                LOG.Write(eEvent.EV_SCHEDULER, Module, $"System run in ATM mode, process skipped, delay {time} seconds");                WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.InProcess);                return true;            }            else            {                if(isCleanRecipe)                {                    _entityTaskToken = _entity.InvokeClean(recipeName, "", RecipeType.Clean);                }                else                {                    _entityTaskToken = _entity.InvokeProcess(recipeName,  wafer.WaferOrigin, RecipeType.Process);                }                                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 (RouteManager.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, "", RecipeType.Clean);            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, "", RecipeType.Clean);            LogTaskStart(_task, $"recipe: {recipeName}, clean: {true}, with wafer: {false}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public void PreJobClean()        {        }        public bool PreJobProcess(string recipeName)        {            _task = TaskType.PreJobProcess;            _entityTaskToken = _entity.InvokeClean(recipeName, "", RecipeType.Clean);            LogTaskStart(_task, $"recipe: {recipeName}, clean: {true}, with wafer: {false}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        public bool CompleteJobProcess(string recipeName)        {            _task = TaskType.CompleteJobProcess;            _entityTaskToken = _entity.InvokeClean(recipeName, "", RecipeType.Clean);            LogTaskStart(_task, $"recipe: {recipeName}, clean: {true}, with wafer: {false}");            return _entityTaskToken != (int)FSM_MSG.NONE;        }        private void WaferArrived(object sender, EventArgs e)        {            if(WaferManager.Instance.CheckHasWafer(Module, 0))            {                WaferInfo wafer = WaferManager.Instance.GetWafer(Module, 0);                string recipeName = wafer.ProcessJob.Sequence.GetRecipe(Module);                if (recipeName.Length > 0)                {                    Process(recipeName, false, RecipeType.Process, wafer);                }                else                {                    LOG.Write(eEvent.WARN_SCHEDULER, Module, "Cannot run process as get recipe failed.");                }            }            else            {                LOG.Write(eEvent.WARN_SCHEDULER, Module, "Cannot run process as PM is empty");            }        }        public override void ResetTask()        {            _entity.ResetRecipeTime();            base.ResetTask();        }        #region clean task        private void LoadIdleCleanOpt()        {            // Load Idle Clean Config            _idleCleanOpt = SC.GetValue<int>($"{Module}.IdleClean.Option");            _idleCleanHourSetPoint = SC.GetValue<int>($"{Module}.IdleClean.IdleCleanTime");            _idleCleanWaferSetPoint = SC.GetValue<int>($"{Module}.IdleClean.IdleCleanWaferCount");            _idleCleanWaferCount = SC.GetValue<int>($"{Module}.IdleClean.WaferCountSinceLastClean");            _idleCleanRecipe = SC.GetStringValue($"{Module}.IdleClean.IdleCleanRecipe");            string lastRun = SC.GetStringValue($"{Module}.IdleClean.LastRunTime");            if (lastRun.Length > 10)            {                try                {                    _lastRunTime = DateTime.Parse(lastRun);                }                catch                {                    lastRun = string.Empty;                }            }            if (lastRun.Length <= 10)            {                _lastRunTime = DateTime.Now;                SC.SetItemValueFromString($"{Module}.IdleClean.LastRunTime", _lastRunTime.ToString());            }            // validate the idle clean recipe name            string path = Path.Combine("Recipes", Module.ToString(), "Clean", $"{_idleCleanRecipe}.rcp");            if (File.Exists(path))            {                string recipeContent = RecipeFileManager.Instance.LoadRecipeByPath(path);                Recipe recipe = Recipe.Load(recipeContent);                if (recipe == null)                {                    _idleCleanRecipe = string.Empty;                }            }        }        public void WaferProcessDone()        {            _lastRunTime = DateTime.Now;            SC.SetItemValueFromString($"{Module}.IdleClean.LastRunTime", _lastRunTime.ToString());            _idleCleanWaferCount++;            SC.SetItemValue($"{Module}.IdleClean.IdleCleanWaferCount", _idleCleanWaferCount);        }                private void ResetIdleCleanCounter()        {            _lastRunTime = DateTime.Now;            SC.SetItemValueFromString($"{Module}.IdleClean.LastRunTime", _lastRunTime.ToString());            _idleCleanWaferCount = 0;            SC.SetItemValue($"{Module}.IdleClean.IdleCleanWaferCount", _idleCleanWaferCount);        }        public bool RunIdleCleanTask()        {            if(_idleCleanOpt == 1)            {                TimeSpan span = DateTime.Now - _lastRunTime;                if(span.TotalHours >= _idleCleanHourSetPoint)                {                    Process(_idleCleanRecipe, true, RecipeType.Clean, null);                    ResetIdleCleanCounter();                    return true;                }            }            else if(_idleCleanOpt == 2)            {                if(_idleCleanWaferCount >= _idleCleanWaferSetPoint)                {                    Process(_idleCleanRecipe, true, RecipeType.Clean, null);                    ResetIdleCleanCounter();                    return true;                }            }            return false;        }        public bool RunJobCleanTask(string jobCleanRecipe)        {            // validate the job clean recipe name            //string recipeContent = RecipeFileManager.Instance.LoadRecipe(Module.ToString(), jobCleanRecipe, false);            string path = Path.Combine( "Recipes", Module.ToString(),"Clean" , $"{jobCleanRecipe}.rcp");            string recipeContent = RecipeFileManager.Instance.LoadRecipeByPath(path);            if (recipeContent.Length == 0)            {                return false;            }            Recipe recipe = Recipe.Load(recipeContent);            if (recipe == null)            {                LOG.Write(eEvent.WARN_ROUTER, Module, $"Loading clean recipe: {path} failed");                return false;            }            return Process(jobCleanRecipe, true, RecipeType.Clean, null);        }        #endregion    }}
 |