Browse Source

开发 AutoCycle 模块, 进行中

sangwq 1 year ago
parent
commit
d900c241bd

+ 28 - 2
Venus/Framework/Common/CommonData/MoveItem.cs

@@ -10,14 +10,19 @@ using MECF.Framework.Common.Equipment;
 
 namespace MECF.Framework.Common.Schedulers
 {
+    public enum EnumMoveType
+    {
+        Place,
+        Pick,
+        Move,
+    }
+
     [DataContract]
     [Serializable]
     //helper class
     public class MoveItem :  IDeviceData
     {
 
-    
-
         [DataMember]
         public ModuleName SourceModule { get; set; }
         [DataMember]
@@ -29,6 +34,27 @@ namespace MECF.Framework.Common.Schedulers
         [DataMember]
         public Hand RobotHand { get; set; }
 
+        public ModuleName Module
+        {
+            get
+            {
+                return ModuleHelper.IsTMRobot(SourceModule) || ModuleHelper.IsEFEMRobot(SourceModule) ? DestinationModule : SourceModule;
+            }
+        }
+
+        public EnumMoveType TransferType
+        {
+            get
+            {
+                if (ModuleHelper.IsTMRobot(SourceModule) || ModuleHelper.IsEFEMRobot(SourceModule))
+                    return EnumMoveType.Place;
+                else if (ModuleHelper.IsTMRobot(DestinationModule) || ModuleHelper.IsEFEMRobot(DestinationModule))
+                    return EnumMoveType.Pick;
+                else
+                    return EnumMoveType.Move;
+            }
+        }
+
 
 
         public MoveItem(ModuleName sourceModule, int sourceSlot, ModuleName destinationModule, int destinationSlot, Hand robotHand)

+ 646 - 23
Venus/Venus_RT/Modules/AutoCycle.cs

@@ -1,20 +1,25 @@
-using Aitex.Core.RT.Routine;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Aitex.Core.RT.Routine;
 using Aitex.Core.RT.SCCore;
 using Aitex.Sorter.Common;
-using Venus_RT.Devices;
+using Aitex.Core.RT.Log;
+using Aitex.Core.Util;
+using Aitex.Core.RT.DataCenter;
+using Aitex.Core.RT.Fsm;
+
+using MECF.Framework.Common.Jobs;
 using MECF.Framework.Common.Routine;
 using MECF.Framework.Common.Equipment;
 using MECF.Framework.Common.SubstrateTrackings;
+using MECF.Framework.Common.Schedulers;
+
 using Venus_Core;
-using Aitex.Core.RT.Log;
-using Aitex.Core.Util;
-using System.Collections.Generic;
-using System.Linq;
+
 using Venus_RT.Modules.Schedulers;
 using Venus_RT.Scheduler;
-using System;
-using MECF.Framework.Common.Schedulers;
-using Aitex.Core.RT.Fsm;
 
 namespace Venus_RT.Modules
 {
@@ -25,18 +30,30 @@ namespace Venus_RT.Modules
         Low,
         Stop,
     }
+
+    enum MovingStatus
+    {
+        Staying,
+        Waiting,
+        Moving,
+    }
     class ModuleFlag
     {
-        public ModulePriority priority;
+        public ModulePriority Priority { get; set; }
+        public MovingStatus MovingStatus { get; set; }
 
         public ModuleFlag(ModulePriority _priority)
         {
-            priority = _priority;
+            Priority = _priority;
+            MovingStatus = MovingStatus.Staying;
         }
     }
 
     class AutoCycle : IRoutine
     {
+        private List<ControlJobInfo> _lstControlJobs = new List<ControlJobInfo>();
+        private List<ProcessJobInfo> _lstProcessJobs = new List<ProcessJobInfo>();
+
         private RState _cycleState = RState.Init;
 
         Dictionary<ModuleName, SchedulerModule> _atmSchedulers  = new Dictionary<ModuleName, SchedulerModule>();
@@ -45,13 +62,51 @@ namespace Venus_RT.Modules
         Dictionary<ModuleName, SchedulerModule> _vacSchedulers  = new Dictionary<ModuleName, SchedulerModule>();
         Dictionary<ModuleName, ModuleFlag> _vacModules          = new Dictionary<ModuleName, ModuleFlag>();
 
+
+        SchedulerTMRobot _tmRobot = new SchedulerTMRobot();
+        SchedulerEfemRobot _efemRobot = new SchedulerEfemRobot();
+
+        List<SlotItem>  _vacReadyOutSlots   = new List<SlotItem>();
+        List<SlotItem>  _vacReadyInSlots    = new List<SlotItem>();
+        List<SlotItem>  _atmReadyOutSlots   = new List<SlotItem>();
+        List<SlotItem>  _atmReadyInSlots    = new List<SlotItem>();
+
+        List<int> _LLAInSlot = new List<int> { 0, 1, 2, 3 };
+        List<int> _LLAOutSlot = new List<int> { 0, 1, 2, 3 };
+        List<int> _LLBInSlot = new List<int> { 0, 1, 2, 3 };
+        List<int> _LLBOutSlot = new List<int> { 0, 1, 2, 3 };
+
+        List<MoveItem> _movingItems = new List<MoveItem>();
+        List<MoveItem> _efemMovingItems = new List<MoveItem>();
+
+        Dictionary<SlotItem, Guid> _vacWaferTargets = new Dictionary<SlotItem, Guid>();
+        Dictionary<SlotItem, Guid> _atmWaferTargets = new Dictionary<SlotItem, Guid>();
+
+        private bool _isCycleMode;
+        private int _cycleSetPoint = 0;
+        private int _cycledCount = 0;
+        private int _cycledWafer = 0;
+
+        #region public interface
         public AutoCycle() 
         {
             InitModules();
+
+            DATA.Subscribe("Scheduler.CycledCount", () => _cycledCount);
+            DATA.Subscribe("Scheduler.CycledWafer", () => _cycledWafer);
+            DATA.Subscribe("Scheduler.CycleSetPoint", () => _cycleSetPoint);
+
+
+            DATA.Subscribe("Scheduler.PjIdList", () => Array.ConvertAll(_lstProcessJobs.ToArray(), x => x.InnerId.ToString()).ToList());
         }
 
         public RState Start(params object[] objs)
         {
+            _isCycleMode = SC.GetValue<bool>("System.IsCycleMode");
+            _cycleSetPoint = _isCycleMode ? SC.GetValue<int>("System.CycleCount") : 0;
+            _cycledWafer = 0;
+            _cycledCount = 0;
+
             return RState.Running;
         }
 
@@ -68,6 +123,36 @@ namespace Venus_RT.Modules
         {
         }
 
+        public bool CheckAllJobDone()
+        {
+            foreach (var cj in _lstControlJobs)
+            {
+                if (cj.State == EnumControlJobState.Executing || cj.State == EnumControlJobState.Paused)
+                    return false;
+            }
+
+            return true;
+        }
+
+        public bool CheckJobJustDone(out string sJobName)
+        {
+            foreach (var cj in _lstControlJobs)
+            {
+                if (cj.State == EnumControlJobState.Completed && !cj.BeenPosted)
+                {
+                    //LP;WaferSize;Lot;Number;Start;End;
+                    sJobName = $"{cj.Module};{cj.JobWaferSize};{cj.LotName};{cj.LotWafers.Count};{cj.StartTime:T};{cj.EndTime:T}";
+                    cj.BeenPosted = true;
+                    return true;
+                }
+            }
+
+            sJobName = "NULL";
+            return false;
+        }
+
+        #endregion
+
         private void InitModules()
         {
             foreach(var module in new ModuleName[]{ ModuleName.LP1, ModuleName.LP2, ModuleName.LP3, 
@@ -118,23 +203,271 @@ namespace Venus_RT.Modules
 
         private void epilogue()
         {
+            foreach(var mod in _vacSchedulers)
+            {
+                if(mod.Value.IsAvailable)
+                {
+                    var tars = _vacWaferTargets.Where(item => item.Key.Module == mod.Key).ToArray();
+                    foreach(var tar in tars)
+                    {
+                        var wafer = WaferManager.Instance.GetWafer(tar.Key.Module, tar.Key.Slot);
+                        if (wafer.IsEmpty)
+                            continue;
+
+                        if(wafer.InnerId == tar.Value)
+                        {
+                            // wafer arrive
+                            _vacWaferTargets.Remove(tar.Key);
+                            wafer.NextSequenceStep++;
+                        }
+                    }
+                }
+            }
+
+            foreach(var mod in _atmSchedulers)
+            {
+                if (mod.Value.IsAvailable)
+                {
+                    var tars = _atmWaferTargets.Where(item => item.Key.Module == mod.Key).ToArray();
+                    foreach (var tar in tars)
+                    {
+                        var wafer = WaferManager.Instance.GetWafer(tar.Key.Module, tar.Key.Slot);
+                        if (wafer.IsEmpty)
+                            continue;
+
+                        if (wafer.InnerId == tar.Value)
+                        {
+                            // wafer arrive
+                            _atmWaferTargets.Remove(tar.Key);
+
+                            if (!ModuleHelper.IsLoadPort(tar.Key.Module))
+                                wafer.NextSequenceStep++;
+                        }
+                    }
+                }
+            }
         }
 
         private void driveVacSystem()
         {
             PumpingTMRobotTask();
             ProcessTMRobotTask();
+            RuningTMRobotTask();
         }
 
         #region Vacuum System
         private void PumpingTMRobotTask()
         {
+            foreach(var mod in _vacSchedulers)
+            {
+                if (mod.Value.IsAvailable && _vacModules[mod.Key].MovingStatus == MovingStatus.Staying)
+                {
+
+                    if(ModuleHelper.IsLoadLock(mod.Key))
+                    {
+                        var inSlots = mod.Key == ModuleName.LLA ? _LLAInSlot : _LLBInSlot;
+                        foreach(var slot in inSlots)
+                        {
+                            if(WaferManager.Instance.CheckHasWafer(mod.Key, slot) && IsVacWaferReadyOut(mod.Key, slot))
+                            {
+                                _vacReadyOutSlots.Add(new SlotItem(mod.Key, slot));
+                                _vacModules[mod.Key].MovingStatus = MovingStatus.Waiting;
+                            }
+                        }
+
+                        var outSlots = mod.Key == ModuleName.LLA ? _LLAOutSlot : _LLBOutSlot;
+                        foreach(var slot in outSlots)
+                        {
+                            if(WaferManager.Instance.CheckNoWafer(mod.Key, slot))
+                            {
+                                _vacReadyInSlots.Add(new SlotItem(mod.Key, slot));
+                                _vacModules[mod.Key].MovingStatus = MovingStatus.Waiting;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if(WaferManager.Instance.CheckHasWafer(mod.Key, 0) && IsVacWaferReadyOut(mod.Key, 0))  // processed?
+                        {
+                            _vacReadyOutSlots.Add(new SlotItem(mod.Key, 0));
+                            _vacModules[mod.Key].MovingStatus = MovingStatus.Waiting;
+                        }
+                        else
+                        {
+                            _vacReadyInSlots.Add(new SlotItem(mod.Key, 0));
+                            _vacModules[mod.Key].MovingStatus = MovingStatus.Waiting;
+                        }
+                    }
+                }
+            }
+        }
+
+        bool SearchWaferDestination(SlotItem outSlot, out SlotItem destSlot)
+        {
+            destSlot = new SlotItem(ModuleName.System, -1);
+            var wafer = WaferManager.Instance.GetWafer(outSlot.Module, outSlot.Slot);
+            foreach (var next_module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
+            {
+                var validSlots = GetModuleValidSlots(next_module);
+                foreach (var nSlot in validSlots)
+                {
+                    if (_movingItems.Exists(mItem => mItem.DestinationModule == next_module && mItem.DestinationSlot == nSlot))
+                        continue;
+
+                    var ready_in = _vacReadyInSlots.Find(item => item.Module == next_module && item.Slot == nSlot);
+                    if (ready_in != null)
+                    {
+                        destSlot.Module = ready_in.Module;
+                        destSlot.Slot = nSlot;
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        List<int> GetModuleValidSlots(ModuleName mod)
+        {
+            var validSlot = new List<int>();
+            if(ModuleHelper.IsLoadLock(mod))
+            {
+                var inSlots = mod == ModuleName.LLA ? _LLAInSlot : _LLBInSlot;
+                foreach (var slot in inSlots)
+                {
+                    if (WaferManager.Instance.CheckNoWafer(mod, slot) && !_movingItems.Exists(item => item.DestinationModule == mod && item.DestinationSlot == slot))
+                        validSlot.Add(slot);
+
+                    if (WaferManager.Instance.CheckHasWafer(mod, slot) && _movingItems.Exists(item => item.SourceModule == mod && item.SourceSlot == slot))
+                        validSlot.Add(slot);
+                }
+            }
+            else if(ModuleHelper.IsPm(mod))
+            {
+                if (WaferManager.Instance.CheckNoWafer(mod, 0) && !_movingItems.Exists(item => item.DestinationModule == mod))
+                    validSlot.Add(0);
+
+                if (WaferManager.Instance.CheckHasWafer(mod, 0) && _movingItems.Exists(item => item.SourceModule == mod))
+                    validSlot.Add(0);
+            }
             
+
+            return validSlot.Distinct().ToList();
+        }
+
+        List<MoveItem> SearchWaitInSlots(ModuleName inModule)
+        {
+            List<MoveItem> inSlots = new List<MoveItem>();
+            var validSlots = GetModuleValidSlots(inModule);
+            foreach(var slot in _vacReadyOutSlots)
+            {
+                if (slot.Module == inModule)
+                    continue;
+
+                var wafer = WaferManager.Instance.GetWafer(slot.Module, slot.Slot);
+                foreach (var next_module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
+                {
+                    if(next_module == inModule && validSlots.Count > 0)
+                    {
+                        inSlots.Add(new MoveItem(slot.Module, slot.Slot, inModule, validSlots.First(), Hand.None) );
+                        validSlots.RemoveAt(0);
+                    }
+                }
+
+            }
+
+            return inSlots;
         }
 
         private void ProcessTMRobotTask()
         {
+            if(_tmRobot.IsAvailable)
+            {
+                if(WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 0) || WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, 1))
+                {
+                    return;
+                }
+
+                foreach(var slot in _vacReadyOutSlots)
+                {
+                    if(ModuleHelper.IsLoadLock(slot.Module))
+                    {
+                        if(SearchWaferDestination(slot, out SlotItem destSlot))
+                        {
+                            _movingItems.Add(new MoveItem(slot.Module, slot.Slot, destSlot.Module, destSlot.Slot, Hand.None));
+
+                            // check whether match double pick pattern
+                            var out_slot_2 = _vacReadyOutSlots.Find(item => item.Module == slot.Module && item.Slot != slot.Slot);
+                            if (out_slot_2 != null)
+                            {
+                                if(SearchWaferDestination(out_slot_2, out SlotItem destSlot_2))
+                                {
+                                    _movingItems.Add(new MoveItem(out_slot_2.Module, out_slot_2.Slot, destSlot_2.Module, destSlot_2.Slot, Hand.None));
+                                }
+                            }
+
+                            // check whether match swap pattern
+                            var in_slots = SearchWaitInSlots(slot.Module);
+                            foreach(var in_slot in in_slots)
+                            {
+                                _movingItems.Add(in_slot);
+                            }
+
+                            return;
+                        }
+                    }
+                    else // PM
+                    {
+                        if(SearchWaferDestination(slot, out SlotItem destSlot))
+                        {
+                            _movingItems.Add(new MoveItem(slot.Module, slot.Slot, destSlot.Module, destSlot.Slot, Hand.None));
+
+                            // check whether match swap pattern
+                            var in_slots = SearchWaitInSlots(slot.Module);
+                            if(in_slots.Count >= 1)
+                            {
+                                _movingItems.Add(in_slots.First());
+                            }
+                            else
+                            {
+                                // check whether match double move pattern
+                                var same_dest = SearchWaitInSlots(destSlot.Module);
+                                foreach (var item in same_dest)
+                                {
+                                    _movingItems.Add(item);
+                                }
+                            }
+
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+
+        private void RuningTMRobotTask()
+        {
+            if(_tmRobot.IsAvailable)
+            {
+                if(_tmRobot.PostMoveItems(_movingItems.ToArray()))
+                {
+                    
+                    foreach(var item in _movingItems)
+                    {
+                        var wafer = WaferManager.Instance.GetWafer(item.SourceModule, item.SourceSlot);
+                        if (wafer.IsEmpty)
+                        {
+                            // post alarm
+                            LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Cannot run TM moving task as Get {item.SourceModule}{item.SourceModule} Wafer Info failed");
+                            return;
+                        }
 
+                        var slot = new SlotItem(item.DestinationModule, item.DestinationSlot);
+                        _vacWaferTargets[slot] = wafer.InnerId;
+                    }
+                    _movingItems.Clear();
+                }
+            }
         }
 
         private Hand GetTMRobotFreeHand()
@@ -151,37 +484,327 @@ namespace Venus_RT.Modules
                 return Hand.Blade1;
         }
 
+        private bool IsVacWaferReadyOut(ModuleName mod, int slot)
+        {
+            var wafer = WaferManager.Instance.GetWafer(mod, slot);
+
+            if (wafer.IsEmpty)
+                return false;
+
+            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
+                return false;
+
+            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
+            {
+                // should not go here
+                LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Wafer:{wafer.WaferOrigin} NextSequenceStep {wafer.NextSequenceStep} exceeds {wafer.ProcessJob.Sequence.Name} max steps number");
+                return false;
+            }
+
+            if (wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(mod))
+                return false;
+
+            foreach(var module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
+            {
+                if (ModuleHelper.IsLoadLock(module) || ModuleHelper.IsPm(module))
+                    return true;
+            }
+
+            return false;
+        }
+
         #endregion Vacuum System
 
         #region Atm System
         private void driveAtmSystem()
         {
             PumpingEFEMRobotTask();
-            ProcessEFEMRobotTask();
+            RuningEFEMRobotTask();
         }
 
         private void PumpingEFEMRobotTask()
         {
+            if (!_efemRobot.IsAvailable)
+                return;
+
+            foreach(var scheduler in _atmSchedulers)
+            {
+                if (!scheduler.Value.IsAvailable)
+                    continue;
 
+                if(ModuleHelper.IsLoadLock(scheduler.Key))
+                {
+                    if (ProcessLLEFEMRobotTask(scheduler.Key))
+                        return;
+                }
+                else if(ModuleHelper.IsLoadPort(scheduler.Key))
+                {
+                    if (ProcessLPEFEMRobotTask(scheduler.Key))
+                        return;
+                }
+                else if(ModuleHelper.IsAligner(scheduler.Key))
+                {
+                    if (ProcessAlignerEFEMRobotTask(scheduler.Key))
+                        return;
+                }
+                else if(ModuleHelper.IsCooling(scheduler.Key))
+                {
+                    if (ProcessCoolingEFEMRobotTask(scheduler.Key))
+                        return;
+                }
+                else
+                {
+                    // should not go here
+                    LOG.Write(eEvent.ERR_ROUTER, $"Wrong Module: {scheduler.Key} in ATM System");
+                }
+            }
         }
 
-        private void ProcessEFEMRobotTask()
+        List<int> GetEfemRobotWaferReadyInHands(ModuleName mod)
         {
+            var slots = new List<int>();
+            for(int i = 0; i < 2; i++)
+            {
+                var wafer = WaferManager.Instance.GetWafer(ModuleName.EfemRobot, i);
+                if (wafer.IsEmpty)
+                    continue;
 
+                if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
+                    continue;
+
+                if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
+                {
+                    // should not go here
+                    LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Wafer:{wafer.WaferOrigin} NextSequenceStep {wafer.NextSequenceStep} exceeds {wafer.ProcessJob.Sequence.Name} max steps number");
+                    continue;
+                }
+
+                if (wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(mod))
+                {
+                    slots.Add(i);
+                }
+            }
+
+            return slots;
         }
 
-        private Hand GetEFEMRobotFreeHand()
+        bool IsAtmWaferReadyOut(ModuleName mod, int slot)
         {
-            var blade1HasWafer = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 0);
-            var blade2HasWafer = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, 1);
-            if (blade1HasWafer && blade2HasWafer)
-                return Hand.None;
-            else if (!blade1HasWafer && !blade2HasWafer)
-                return Hand.Both;
-            else if (blade1HasWafer)
-                return Hand.Blade2;
+            var wafer = WaferManager.Instance.GetWafer(mod, slot);
+
+            if (wafer.IsEmpty)
+                return false;
+
+            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
+                return false;
+
+            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
+            {
+                // should not go here
+                LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Wafer:{wafer.WaferOrigin} NextSequenceStep {wafer.NextSequenceStep} exceeds {wafer.ProcessJob.Sequence.Name} max steps number");
+                return false;
+            }
+
+            if (wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(mod))
+                return false;
+
+            if(ModuleHelper.IsLoadLock(mod))
+            {
+                foreach (var module in wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules)
+                {
+                    if (ModuleHelper.IsPm(module))
+                        return false;
+                }
+            }
+
+            return true;
+        }
+        private bool ProcessLLEFEMRobotTask(ModuleName ll)
+        {
+            var robotSlots = GetEfemRobotWaferReadyInHands(ll);
+            var inSlots = ll == ModuleName.LLA ? _LLAInSlot : _LLBInSlot;
+            foreach(var slot in inSlots)
+            {
+                if(robotSlots.Count >= 1)
+                {
+                    if(WaferManager.Instance.CheckNoWafer(ll, slot))
+                    {
+                        _efemMovingItems.Add(new MoveItem(ModuleName.EfemRobot, robotSlots.First(), ll, slot, (Hand)robotSlots.First()));
+                        robotSlots.RemoveAt(0);
+                    }
+                }
+            }
+
+            var outSlots = ll == ModuleName.LLA ? _LLAOutSlot : _LLBOutSlot;
+
+            foreach(var slot in outSlots)
+            {
+                if(IsAtmWaferReadyOut(ll, slot))
+                {
+                    var robotHand = GetEFEMRobotFreeHand();
+                    if(robotHand !=  Hand.None)
+                    {
+                        _efemMovingItems.Add(new MoveItem(ll, slot, ModuleName.EfemRobot, (int)robotHand, robotHand));
+                    }
+                }
+            }
+
+            return _efemMovingItems.Count > 0;
+        }
+
+        private bool ProcessLPEFEMRobotTask(ModuleName lp)
+        {
+            // check return
+            for(int i = 0; i < 2; i++)
+            {
+                if(WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, i))
+                {
+                    var returnWafer = WaferManager.Instance.GetWafer(ModuleName.EfemRobot, i);
+                    if (returnWafer.IsEmpty)
+                        continue;
+
+                    if (returnWafer.ProcessJob == null || returnWafer.ProcessJob.Sequence == null)
+                        continue;
+
+                    if (returnWafer.NextSequenceStep >= returnWafer.ProcessJob.Sequence.Steps.Count && lp == (ModuleName)returnWafer.OriginStation)  // need return
+                    {
+                        _efemMovingItems.Add(new MoveItem(ModuleName.EfemRobot, i, lp, returnWafer.OriginSlot, (Hand)i));
+                    }
+                }
+            }
+
+            if (_efemMovingItems.Count > 0)
+                return true;
+
+            var outSlots = GetNextWaferInJobQueue(lp);
+            foreach(var slot in outSlots)
+            {
+                var hand = GetEFEMRobotFreeHand();
+                if(hand != Hand.None)
+                {
+                    _efemMovingItems.Add(new MoveItem(lp, slot, ModuleName.EfemRobot, (int)hand, hand));
+                }
+            }
+
+            return _efemMovingItems.Count > 0;
+        }
+
+        private List<int> GetNextWaferInJobQueue(ModuleName lp)
+        {
+            var inSlots = new List<int>();
+
+            return inSlots;
+
+
+            //if (GetSystemInnerWaferCount() >= SystemInternalWaferCount || GetBufferWaferCount() > _maxBufferWaferCount)
+            //    return new SlotItem(ModuleName.System, -1);
+
+            //foreach (var cj in _lstControlJobs)
+            //{
+            //    if (lpModule != ModuleName.System && (cj.Module != lpModule.ToString()))
+            //        continue;
+
+            //    if (cj.State == EnumControlJobState.Executing)
+            //    {
+            //        foreach (var pj in _lstProcessJobs)
+            //        {
+            //            if (pj.ControlJobName == cj.Name && pj.State == EnumProcessJobState.Processing)
+            //            {
+            //                foreach (var pjSlotWafer in pj.SlotWafers)
+            //                {
+            //                    if (CheckWaferNeedProcessAndPMAvailable(pjSlotWafer.Item1, pjSlotWafer.Item2))
+            //                    {
+            //                        return new SlotItem(pjSlotWafer.Item1, pjSlotWafer.Item2);
+            //                    }
+
+            //                }
+            //            }
+            //        }
+            //    }
+            //}
+
+            //return new SlotItem(ModuleName.System, -1);
+        }
+
+        private bool ProcessAlignerEFEMRobotTask(ModuleName aligner)
+        {
+            if(WaferManager.Instance.CheckHasWafer(aligner, 0) && IsAtmWaferReadyOut(aligner, 0))
+            {
+                var hand = GetEFEMRobotFreeHand();
+                if(hand != Hand.None)
+                {
+                    _efemMovingItems.Add(new MoveItem(aligner, 0, ModuleName.EfemRobot, (int)hand, hand));
+                }
+            }
             else
-                return Hand.Blade1;
+            {
+                var robotSlots = GetEfemRobotWaferReadyInHands(aligner);
+                if(robotSlots.Count > 0)
+                {
+                    _efemMovingItems.Add(new MoveItem(aligner, 0, ModuleName.EfemRobot, robotSlots.First(), (Hand)robotSlots.First()));
+                }
+            }
+
+            return _efemMovingItems.Count > 0;
+        }
+
+        private bool ProcessCoolingEFEMRobotTask(ModuleName cooling)
+        {
+            if (WaferManager.Instance.CheckHasWafer(cooling, 0) && IsAtmWaferReadyOut(cooling, 0))
+            {
+                var hand = GetEFEMRobotFreeHand();
+                if (hand != Hand.None)
+                {
+                    _efemMovingItems.Add(new MoveItem(cooling, 0, ModuleName.EfemRobot, (int)hand, hand));
+                }
+            }
+            else
+            {
+                var robotSlots = GetEfemRobotWaferReadyInHands(cooling);
+                if (robotSlots.Count > 0)
+                {
+                    _efemMovingItems.Add(new MoveItem(cooling, 0, ModuleName.EfemRobot, robotSlots.First(), (Hand)robotSlots.First()));
+                }
+            }
+
+            return _efemMovingItems.Count > 0;
+        }
+
+        private void RuningEFEMRobotTask()
+        {
+            if (_efemRobot.IsAvailable)
+            {
+                if (_efemRobot.PostMoveItems(_efemMovingItems.ToArray()))
+                {
+
+                    foreach (var item in _efemMovingItems)
+                    {
+                        var wafer = WaferManager.Instance.GetWafer(item.SourceModule, item.SourceSlot);
+                        if (wafer.IsEmpty)
+                        {
+                            // post alarm
+                            LOG.Write(eEvent.ERR_ROUTER, ModuleName.System, $"Cannot run EFEM moving task as Get {item.SourceModule}{item.SourceModule} Wafer Info failed");
+                            return;
+                        }
+
+                        var slot = new SlotItem(item.DestinationModule, item.DestinationSlot);
+                        _atmWaferTargets[slot] = wafer.InnerId;
+                    }
+                    _efemMovingItems.Clear();
+                }
+            }
+        }
+
+        private Hand GetEFEMRobotFreeHand()
+        {
+            for(int i = 0; i < 2; i++)
+            {
+                if ((WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, i) && !_efemMovingItems.Exists(item => item.DestinationModule == ModuleName.EfemRobot && item.DestinationSlot == i)) ||
+                (WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, i) && _efemMovingItems.Exists(item => item.SourceModule == ModuleName.EfemRobot && item.SourceSlot == i)))
+                return (Hand)i;
+            }
+
+            return Hand.None;
         }
 
         #endregion Atm System

+ 84 - 79
Venus/Venus_RT/Modules/Schedulers/SchedulerEfemRobot.cs

@@ -7,17 +7,29 @@ using Aitex.Core.RT.Fsm;
 using Aitex.Core.RT.Log;
 using Aitex.Core.Util;
 using Aitex.Sorter.Common;
-using Venus_RT.Modules;
+using MECF.Framework.Common.Schedulers;
 using MECF.Framework.Common.Equipment;
 using MECF.Framework.Common.SubstrateTrackings;
+using Venus_RT.Modules;
+using Venus_Core;
 
 namespace Venus_RT.Scheduler
 {
+    class SchedulerItem
+    {
+        public EfemEntity.MSG MoveType { get; set; }
+        public ModuleName target { get; set; }
+
+        public Queue<MoveItem> moveList { get; set; }
+
+        public RState Status { get; set; }
+
+    }
     public class SchedulerEfemRobot : SchedulerModule
     {
         public override bool IsAvailable
         {
-            get { return _entity.IsIdle && /*_entity.IsOnline && */CheckTaskDone(); }
+            get { return _entity.IsIdle && /*_entity.IsOnline && */CheckTaskDone() && RunSchedulers(); }
         }
         public override bool IsOnline
         {
@@ -31,14 +43,10 @@ namespace Venus_RT.Scheduler
         }
         private EfemEntity _entity = null;
 
-        private Hand _hand;
 
+        private SchedulerItem _currentScheduler = null;
         private int _entityTaskToken = (int)FSM_MSG.NONE;
 
-        private Hand _taskSwapPickHand;
-        private Hand _taskSwapPlaceHand;
-        private int _taskSwapPickSlot;
-        private int _taskSwapPlaceSlot;
 
         public ModuleName PreviousTarget { get; set; }
 
@@ -48,56 +56,8 @@ namespace Venus_RT.Scheduler
             PreviousTarget = ModuleName.System;
         }
 
-        public bool IsReadyForPick(Hand blade)
-        {
-            return WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, (int)blade);
-        }
-
-        public bool IsReadyForPlace(Hand blade)
-        {
-            return WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, (int)blade);
-        }
-
-        public bool Pick(ModuleName source, int slot, Hand hand)
-        {
-            _task = TaskType.Pick;
-            _hand = hand;
-            _entityTaskToken = _entity.InvokePick(source, slot, hand, WaferManager.Instance.GetWafer(source, slot).Size);
-            PreviousTarget = source;
-
-            LogTaskStart(_task, $"{source}.{slot + 1}=>{Module}.{hand}");
-            return true;
-        }
-
-        public bool Place(ModuleName destination, int slot, Hand hand)
-        {
-            _task = TaskType.Place;
-            _hand = hand;
-            _entityTaskToken = _entity.InvokePlace(destination, slot, hand, 
-                WaferManager.Instance.GetWafer(ModuleName.EfemRobot, hand==Hand.Blade1 ? 0:1).Size);
-            PreviousTarget = destination;
-            LogTaskStart(_task, $"{Module}.{hand}=>{destination}.{slot + 1}");
-            return true;
-        }
-
-        public bool PickAndPlace(ModuleName target, int pickSlot, int placeSlot, Hand pickHand, Hand placeHand)
-        {
-            PreviousTarget = target;
-            _task = TaskType.PickAndPlace;
-            _taskSwapPickHand = pickHand;
-            _taskSwapPlaceHand = placeHand;
-            _taskSwapPickSlot = pickSlot;
-            _taskSwapPlaceSlot = placeSlot;
-
-            _entityTaskToken = _entity.InvokePickAndPlace(target, pickHand, pickSlot, placeHand, placeSlot,  WaferManager.Instance.GetWafer(target, pickSlot).Size);
-
-            LogTaskStart(_task, $" {target}.{pickSlot + 1}=>{Module}.{pickHand} && {Module}.{placeHand}=>{target}.{placeSlot + 1}");
-            return true;
-        }
-
         public bool Goto(ModuleName target, int slot )
         {
-            _task = TaskType.Goto;
             _entityTaskToken = _entity.InvokeGoto(target, slot );
             PreviousTarget = target;
 
@@ -108,8 +68,6 @@ namespace Venus_RT.Scheduler
 
         public bool Map(ModuleName destination )
         {
-            _task = TaskType.Map;
-            
             _entityTaskToken = _entity.InvokeMap(destination.ToString());
             LogTaskStart(_task, $"{Module} mapping");
             PreviousTarget = destination;
@@ -124,36 +82,24 @@ namespace Venus_RT.Scheduler
         public bool CheckTaskDone()
         {
             bool ret = false;
-            switch (_task)
+            switch (_entityTaskToken)
             {
-                case TaskType.None:
+                case (int)TaskType.None:
                     ret = true;
                     break;
-                case TaskType.Pick:
-                    ret = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, (int)_hand);
-                    if (ret)
-                    {
-                        WaferArriveTicks[(int) _hand] = DateTime.Now.Ticks;
-                    }
-                    break;
-                case TaskType.Place:
-                    ret = WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, (int)_hand);
+                case (int)EfemEntity.MSG.Pick:
+                case (int)EfemEntity.MSG.Place:
+                case (int)EfemEntity.MSG.Swap:
+                    ret = IsAllWafersArrived();
                     break;
-                case TaskType.Map:
+
+                case (int)EfemEntity.MSG.Map:
                     ret = _entity.CheckAcked(_entityTaskToken) && _entity.IsIdle;
                     break;
-                case TaskType.Goto:
+                case (int)EfemEntity.MSG.Goto:
                     ret = _entity.CheckAcked(_entityTaskToken) && _entity.IsIdle;
                     break;
-                case TaskType.PickAndPlace:
-                    ret = WaferManager.Instance.CheckHasWafer(ModuleName.EfemRobot, (int)_taskSwapPickHand)
-                          && WaferManager.Instance.CheckNoWafer(ModuleName.EfemRobot, (int)_taskSwapPlaceHand);
-
-                    if (ret)
-                    {
-                        WaferArriveTicks[(int)_taskSwapPickHand] = DateTime.Now.Ticks;
-                    }
-                    break;
+                
             }
 
             if (ret && _task != TaskType.None)
@@ -164,5 +110,64 @@ namespace Venus_RT.Scheduler
 
             return ret;
         }
+
+        public bool PostMoveItems(MoveItem[] items)
+        {
+            if(ModuleHelper.IsLoadLock(items.First().Module))
+            {
+                _currentScheduler = new SchedulerItem();
+                _currentScheduler.MoveType = EfemEntity.MSG.Swap;
+                _currentScheduler.target = items.First().Module;
+                _currentScheduler.Status = RState.Init;
+                _currentScheduler.moveList = new Queue<MoveItem>(items);
+                
+            }
+            else
+            {
+                _currentScheduler = new SchedulerItem();
+                _currentScheduler.MoveType = items.First().TransferType == EnumMoveType.Pick ? EfemEntity.MSG.Pick : EfemEntity.MSG.Place;
+                _currentScheduler.target = items.First().Module;
+                _currentScheduler.Status = RState.Init;
+                _currentScheduler.moveList = new Queue<MoveItem>(items);
+            }
+
+            RunSchedulers();
+            return true;
+        }
+
+        bool RunSchedulers()
+        {
+            if (_entity.IsIdle && CheckTaskDone())
+            {
+                if(_currentScheduler.Status == RState.Init)
+                {
+                    foreach (var item in _currentScheduler.moveList)
+                    {
+                        LOG.Write(eEvent.EV_EFEM_ROBOT, ModuleName.EfemRobot, $"EFEM Robot Moving Items: {item.SourceModule} Slot {item.SourceSlot + 1} => {item.DestinationModule} Slot {item.DestinationSlot + 1}");
+                    }
+
+                    if (_entity.CheckToPostMessage((int)_currentScheduler.MoveType, _currentScheduler.moveList))
+                    {
+                        _currentScheduler.Status = RState.Running;
+                        _entityTaskToken = (int)_currentScheduler.MoveType;
+                    }
+                    else
+                        _entityTaskToken = (int)FSM_MSG.NONE;
+                }
+            }
+
+            return _currentScheduler.Status == RState.End;
+        }
+
+        private bool IsAllWafersArrived()
+        {
+            foreach(var item in _currentScheduler.moveList)
+            {
+                if (WaferManager.Instance.CheckNoWafer(item.DestinationModule, item.DestinationSlot))
+                    return false;
+            }
+
+            return true;
+        }
     }
 }

+ 1 - 0
Venus/Venus_RT/Modules/Schedulers/SchedulerTMRobot.cs

@@ -211,6 +211,7 @@ namespace Venus_RT.Modules.Schedulers
                 }
             }
 
+            RunSchedulers();
             return true;
         }