Browse Source

robot scheduler add vpw prepare

chenkui 4 days ago
parent
commit
e0e29761ad

+ 5 - 0
Framework/Common/Routine/RoutineBase.cs

@@ -51,6 +51,11 @@ namespace MECF.Framework.Common.Routine
             get { return Runner.CurrentStep.ToString();  }
         }
 
+        public string RoutineName
+        {
+            get; set;
+        }
+
         public RoutineBase(string module)
         {
             Module = module;

+ 1 - 1
Framework/Common/SubstrateTrackings/WaferManager.cs

@@ -775,7 +775,7 @@ namespace MECF.Framework.Common.SubstrateTrackings
             }
             if (CheckHasWafer(ModuleName.Aligner1, 0))
             {
-                reason = "EFEM Robot has wafer cache";
+                reason = "EFEM Aligner has wafer cache";
                 LOG.Write(eEvent.ERR_WAFER_MANAGER_FAILED, ModuleName.System,reason );
                 return false;
             }

+ 1 - 1
PunkHPX8_Core/RtState.cs

@@ -128,7 +128,7 @@ namespace PunkHPX8_Core
         Aborting,
         Idle,
         Initializing,
-        Purgeing,
+        Purging,
     
     }
     public enum VPWCellState

+ 0 - 2
PunkHPX8_RT/Dispatch/JobProcesser.cs

@@ -140,7 +140,6 @@ namespace PunkHPX8_RT.Dispatch
                 return false;
             }
 
-
             ControlJobInfo cj = new ControlJobInfo();
             cj.Name = jobId;
             cj.Module = module;
@@ -228,7 +227,6 @@ namespace PunkHPX8_RT.Dispatch
                 {                   
                     return true;
                 }
-
             }
             List<ProcessJobInfo> pjs = new List<ProcessJobInfo>();
             string[] seqs = seqSlot.Keys.ToArray();

+ 5 - 6
PunkHPX8_RT/Dispatch/WaferTask.cs

@@ -45,10 +45,6 @@ namespace PunkHPX8_RT.Dispatch
     {
         #region 内部变量
         /// <summary>
-        /// Wafer对象
-        /// </summary>
-        private WaferInfo _waferInfo;
-        /// <summary>
         /// 调度步骤
         /// </summary>
         private List<SchedulerSequence> _schedulerSequences;
@@ -98,7 +94,10 @@ namespace PunkHPX8_RT.Dispatch
         /// <summary>
         /// ProcessJob对象
         /// </summary>
-        public ProcessJobInfo ProcessJobInfo { get { return _waferInfo!=null? _waferInfo.ProcessJob:null; } }
+        public ProcessJobInfo ProcessJobInfo 
+        {
+            get; internal set; 
+        }
         #endregion
 
         #region 事件
@@ -118,10 +117,10 @@ namespace PunkHPX8_RT.Dispatch
         /// <param name="schedulerSequences"></param>
         public WaferTask(WaferInfo waferInfo, List<SchedulerSequence> schedulerSequences)
         {
-            _waferInfo = waferInfo;
             WaferId = waferInfo.WaferID;
             _schedulerSequences = schedulerSequences;
             State = WaferTaskState.Created;
+            ProcessJobInfo = waferInfo.ProcessJob;
         }
         /// <summary>
         /// 执行

+ 15 - 8
PunkHPX8_RT/Dispatch/WaferTaskManager.cs

@@ -19,6 +19,7 @@ using MECF.Framework.Common.ToolLayout;
 using PunkHPX8_RT.Devices.EFEM;
 using Aitex.Core.RT.Device;
 using MECF.Framework.RT.Core.Equipments;
+using PunkHPX8_RT.Modules.VpwMain;
 
 namespace PunkHPX8_RT.Dispatch
 {
@@ -264,6 +265,12 @@ namespace PunkHPX8_RT.Dispatch
                     }
                 }
             }
+            List<VpwCellEntity> vpwCellEntities = SchedulerSequenceManager.Instance.GetAvaibleVpwList(processJob.SequenceRecipe.SubstrateSize, false);
+            if (vpwCellEntities.Count == 0)
+            {
+                return;
+            }
+
             SequenceRecipe sequenceRecipe = processJob.SequenceRecipe;
             if (wafers.Count == 1)
             {
@@ -272,9 +279,9 @@ namespace PunkHPX8_RT.Dispatch
                 {
                     return;
                 }
-                CreateWaferTaskSchedulerSequence(wafers[0], sequenceRecipe, "");
+                CreateWaferTaskSchedulerSequence(wafers[0], sequenceRecipe, "", vpwCellEntities[0].Module);
                 mateWaferTask = wafers[0].WaferID;
-                CreateDummyWaferTaskSchedulerSequence(sequenceRecipe, dummyWaferInfo, mateWaferTask);
+                CreateDummyWaferTaskSchedulerSequence(sequenceRecipe, dummyWaferInfo, mateWaferTask, vpwCellEntities.Count == 1 ? vpwCellEntities[0].Module : vpwCellEntities[1].Module);
                 _waferTaskMatchDic[wafers[0].WaferID] = dummyWaferInfo.WaferID; 
                 LOG.WriteLog(eEvent.EV_SEQUENCE, "Scheduler", $"wafer {wafers[0].WaferID} match {dummyWaferInfo.WaferID}");
                 _waferTaskMatchDic[dummyWaferInfo.WaferID] = wafers[0].WaferID;
@@ -282,9 +289,9 @@ namespace PunkHPX8_RT.Dispatch
             }
             else if (wafers.Count >= 2)
             {
-                CreateWaferTaskSchedulerSequence(wafers[0], sequenceRecipe, "");
+                CreateWaferTaskSchedulerSequence(wafers[0], sequenceRecipe, "",vpwCellEntities[0].Module);
                 mateWaferTask = wafers[0].WaferID;
-                CreateWaferTaskSchedulerSequence(wafers[1], sequenceRecipe,mateWaferTask);
+                CreateWaferTaskSchedulerSequence(wafers[1], sequenceRecipe, mateWaferTask, vpwCellEntities.Count == 1 ? vpwCellEntities[0].Module : vpwCellEntities[1].Module);
                 _waferTaskMatchDic[wafers[0].WaferID] = wafers[1].WaferID;
                 _waferTaskMatchDic[wafers[1].WaferID] = wafers[0].WaferID;
             }
@@ -327,9 +334,9 @@ namespace PunkHPX8_RT.Dispatch
         /// <param name="pufModuleName"></param>
         /// <param name="waferHolderInfo"></param>
         /// <param name="sequenceRecipe"></param>
-        private void CreateWaferTaskSchedulerSequence(WaferInfo waferInfo, SequenceRecipe sequenceRecipe, string mateWafeTask)
+        private void CreateWaferTaskSchedulerSequence(WaferInfo waferInfo, SequenceRecipe sequenceRecipe, string mateWafeTask,ModuleName vpwModule)
         {
-            List<SchedulerSequence> sequences = SchedulerSequenceManager.Instance.AnalyWaferAllSchedulerSequence(waferInfo,sequenceRecipe);
+            List<SchedulerSequence> sequences = SchedulerSequenceManager.Instance.AnalyWaferAllSchedulerSequence(waferInfo,vpwModule,sequenceRecipe);
             WaferTask waferTask = new WaferTask(waferInfo, sequences);
             if (!string.IsNullOrEmpty(mateWafeTask))
             {
@@ -345,9 +352,9 @@ namespace PunkHPX8_RT.Dispatch
         /// <param name="waferInfo"></param>
         /// <param name="pufModuleName"></param>
         /// <param name="mateWaferTask"></param>
-        private void CreateDummyWaferTaskSchedulerSequence(SequenceRecipe sequenceRecipe,WaferInfo waferInfo,string mateWaferTask)
+        private void CreateDummyWaferTaskSchedulerSequence(SequenceRecipe sequenceRecipe,WaferInfo waferInfo,string mateWaferTask,ModuleName vpwModuleName)
         {
-            List<SchedulerSequence> sequences = SchedulerSequenceManager.Instance.AnalyDummyWaferAllSchedulerSequence(sequenceRecipe,waferInfo);
+            List<SchedulerSequence> sequences = SchedulerSequenceManager.Instance.AnalyDummyWaferAllSchedulerSequence(sequenceRecipe,vpwModuleName,waferInfo);
             
             WaferTask waferTask = new WaferTask(waferInfo,sequences);
             if (!string.IsNullOrEmpty(mateWaferTask))

+ 432 - 432
PunkHPX8_RT/Modules/PlatingCell/PlatingCellEntity.cs

@@ -1,430 +1,430 @@
-using Aitex.Core.Common;
-using Aitex.Core.RT.DataCenter;
-using Aitex.Core.RT.Device;
-using Aitex.Core.RT.Fsm;
-using Aitex.Core.RT.Log;
-using Aitex.Core.RT.OperationCenter;
-using Aitex.Core.RT.RecipeCenter;
-using Aitex.Core.RT.SCCore;
-using Aitex.Core.Util;
-using Aitex.Core.Utilities;
-using CyberX12_RT.Modules.VpwCell;
-using MECF.Framework.Common.Equipment;
-using MECF.Framework.Common.Persistent.Reservoirs;
-using MECF.Framework.Common.ProcessCell;
-using MECF.Framework.Common.RecipeCenter;
-using MECF.Framework.Common.Routine;
-using MECF.Framework.Common.SubstrateTrackings;
-using MECF.Framework.Common.ToolLayout;
-using MECF.Framework.RT.Core.Equipments;
-using PunkHPX8_Core;
-using PunkHPX8_RT.Devices.PlatingCell;
-using PunkHPX8_RT.Devices.PowerSupplier;
-using PunkHPX8_RT.Devices.Reservoir;
-using PunkHPX8_RT.Devices.Temperature;
-using PunkHPX8_RT.Modules.Reservoir;
-using PunkHPX8_RT.Modules.VpwCell;
-using PunkHPX8_RT.Modules.VpwMain;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace PunkHPX8_RT.Modules.PlatingCell
-{
-    public class PlatingCellEntity : Entity, IEntity, IModuleEntity
-    {
-        public enum PlatingCellMsg
-        {
-            NONE,
-            Error,
-            ResumeError,
-            Initialize,
-            Manual,
-            Auto,
-            CloseFlowValve,
-            OpenFlowValve,
-            RunRecipe,
-            Abort,
-            Init,
-            CCR,
-            CCRAbort
-        }
-
-        #region 常量
-        private const string STRATUS = "Stratus";
-        private const string AUTO = "Auto";
-        private const string MANUAL = "Manual";
-        private const string DISABLED = "Disabled";
-        private const string ENGINEERING = "Engineering";
-        private const string PRODUCTION = "Production";
-        #endregion
-
-        #region 内部变量
-        /// <summary>
-        /// 持久化数值
-        /// </summary>
-        private PlatingCellPersistentValue _persistentValue;
-        /// <summary>
-        /// 当前recipe
-        /// </summary>
-        private DepRecipe _currentRecipe;
-        /// <summary>
-        /// recipe时间
-        /// </summary>
-        private int _recipeTime;
-        /// <summary>
-        /// c&m Initialize routine
-        /// </summary>
-        private PlatingCellInitializeRoutine _initializeRoutine;
-        /// <summary>
-        /// CCR routine
-        /// </summary>
-        private PlatingCellCCRRoutine _platingCellCRRoutine;
+using Aitex.Core.Common;
+using Aitex.Core.RT.DataCenter;
+using Aitex.Core.RT.Device;
+using Aitex.Core.RT.Fsm;
+using Aitex.Core.RT.Log;
+using Aitex.Core.RT.OperationCenter;
+using Aitex.Core.RT.RecipeCenter;
+using Aitex.Core.RT.SCCore;
+using Aitex.Core.Util;
+using Aitex.Core.Utilities;
+using CyberX12_RT.Modules.VpwCell;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.Persistent.Reservoirs;
+using MECF.Framework.Common.ProcessCell;
+using MECF.Framework.Common.RecipeCenter;
+using MECF.Framework.Common.Routine;
+using MECF.Framework.Common.SubstrateTrackings;
+using MECF.Framework.Common.ToolLayout;
+using MECF.Framework.RT.Core.Equipments;
+using PunkHPX8_Core;
+using PunkHPX8_RT.Devices.PlatingCell;
+using PunkHPX8_RT.Devices.PowerSupplier;
+using PunkHPX8_RT.Devices.Reservoir;
+using PunkHPX8_RT.Devices.Temperature;
+using PunkHPX8_RT.Modules.Reservoir;
+using PunkHPX8_RT.Modules.VpwCell;
+using PunkHPX8_RT.Modules.VpwMain;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PunkHPX8_RT.Modules.PlatingCell
+{
+    public class PlatingCellEntity : Entity, IEntity, IModuleEntity
+    {
+        public enum PlatingCellMsg
+        {
+            NONE,
+            Error,
+            ResumeError,
+            Initialize,
+            Manual,
+            Auto,
+            CloseFlowValve,
+            OpenFlowValve,
+            RunRecipe,
+            Abort,
+            Init,
+            CCR,
+            CCRAbort
+        }
+
+        #region 常量
+        private const string STRATUS = "Stratus";
+        private const string AUTO = "Auto";
+        private const string MANUAL = "Manual";
+        private const string DISABLED = "Disabled";
+        private const string ENGINEERING = "Engineering";
+        private const string PRODUCTION = "Production";
+        #endregion
+
+        #region 内部变量
+        /// <summary>
+        /// 持久化数值
+        /// </summary>
+        private PlatingCellPersistentValue _persistentValue;
+        /// <summary>
+        /// 当前recipe
+        /// </summary>
+        private DepRecipe _currentRecipe;
+        /// <summary>
+        /// recipe时间
+        /// </summary>
+        private int _recipeTime;
+        /// <summary>
+        /// c&m Initialize routine
+        /// </summary>
+        private PlatingCellInitializeRoutine _initializeRoutine;
+        /// <summary>
+        /// CCR routine
+        /// </summary>
+        private PlatingCellCCRRoutine _platingCellCRRoutine;
         /// <summary>
         /// Run recipe routine
-        /// </summary>
-        private PlatingCellRunRecipeRoutine _runRecipeRoutine;
-        #endregion
-
-        #region 属性
-        /// <summary>
-        /// 模块名称
-        /// </summary>
-        public ModuleName Module { get; private set; }
-        /// <summary>
-        /// 是否Init
-        /// </summary>
-        public bool IsInit
-        {
-            get { return fsm.State == (int)PlatingCellState.Init; }
-        }
-        /// <summary>
-        /// 是否Idle
-        /// </summary>
-        public bool IsIdle
-        {
-            get
-            {
-                return fsm.State == (int)PlatingCellState.Idle;
-            }
-        }
-        /// <summary>
-        /// 是否错误
-        /// </summary>
-        public bool IsError
-        {
-            get { return fsm.State == (int)PlatingCellState.Error; }
-        }
-        /// <summary>
-        /// 正在忙碌
-        /// </summary>
-        public bool IsBusy
-        {
-            get { return fsm.State == (int)PlatingCellState.Initializing; }
-        }
-
-        /// <summary>
-        /// 化学液
-        /// </summary>
-        public string Chemistry
-        {
-            get { return _currentRecipe != null ? _currentRecipe.Chemistry : ""; }
-        }
-        /// <summary>
-        /// 是否禁用
-        /// </summary>
-        public bool IsDisable { get { return _persistentValue == null || _persistentValue.OperatingMode == DISABLED; } }
-
-        /// <summary>
-        /// 自动模式
-        /// </summary>
-        public bool IsAuto { get { return _persistentValue != null && _persistentValue.OperatingMode == AUTO; } }
-        /// <summary>
-        /// 自动模式
-        /// </summary>
-        public bool IsManual { get { return _persistentValue != null && _persistentValue.OperatingMode == MANUAL; } }
-        /// <summary>
-        /// 是否为工程模式
-        /// </summary>
-        public bool IsEngineering { get { return _persistentValue != null && _persistentValue.RecipeOperatingMode == ENGINEERING; } }
-        /// <summary>
-        /// 是否为产品模式
-        /// </summary>
-        public bool IsProduction { get { return _persistentValue != null && _persistentValue.RecipeOperatingMode == PRODUCTION; } }
-        /// <summary>
-        /// 状态机状态
-        /// </summary>
-        public PlatingCellState State { get { return (PlatingCellState)fsm.State; } }
-        /// <summary>
-        /// 是否初始化完成
-        /// </summary>
-        public bool IsInitialized { get { return fsm.State >= (int)PlatingCellState.Initialized; } }
-        /// <summary>
-        /// Reservoir项
-        /// </summary>
+        /// </summary>
+        private PlatingCellRunRecipeRoutine _runRecipeRoutine;
+        #endregion
+
+        #region 属性
+        /// <summary>
+        /// 模块名称
+        /// </summary>
+        public ModuleName Module { get; private set; }
+        /// <summary>
+        /// 是否Init
+        /// </summary>
+        public bool IsInit
+        {
+            get { return fsm.State == (int)PlatingCellState.Init; }
+        }
+        /// <summary>
+        /// 是否Idle
+        /// </summary>
+        public bool IsIdle
+        {
+            get
+            {
+                return fsm.State == (int)PlatingCellState.Idle;
+            }
+        }
+        /// <summary>
+        /// 是否错误
+        /// </summary>
+        public bool IsError
+        {
+            get { return fsm.State == (int)PlatingCellState.Error; }
+        }
+        /// <summary>
+        /// 正在忙碌
+        /// </summary>
+        public bool IsBusy
+        {
+            get { return fsm.State == (int)PlatingCellState.Initializing; }
+        }
+
+        /// <summary>
+        /// 化学液
+        /// </summary>
+        public string Chemistry
+        {
+            get { return _currentRecipe != null ? _currentRecipe.Chemistry : ""; }
+        }
+        /// <summary>
+        /// 是否禁用
+        /// </summary>
+        public bool IsDisable { get { return _persistentValue == null || _persistentValue.OperatingMode == DISABLED; } }
+
+        /// <summary>
+        /// 自动模式
+        /// </summary>
+        public bool IsAuto { get { return _persistentValue != null && _persistentValue.OperatingMode == AUTO; } }
+        /// <summary>
+        /// 自动模式
+        /// </summary>
+        public bool IsManual { get { return _persistentValue != null && _persistentValue.OperatingMode == MANUAL; } }
+        /// <summary>
+        /// 是否为工程模式
+        /// </summary>
+        public bool IsEngineering { get { return _persistentValue != null && _persistentValue.RecipeOperatingMode == ENGINEERING; } }
+        /// <summary>
+        /// 是否为产品模式
+        /// </summary>
+        public bool IsProduction { get { return _persistentValue != null && _persistentValue.RecipeOperatingMode == PRODUCTION; } }
+        /// <summary>
+        /// 状态机状态
+        /// </summary>
+        public PlatingCellState State { get { return (PlatingCellState)fsm.State; } }
+        /// <summary>
+        /// 是否初始化完成
+        /// </summary>
+        public bool IsInitialized { get { return fsm.State >= (int)PlatingCellState.Initialized; } }
+        /// <summary>
+        /// Reservoir项
+        /// </summary>
         private ReservoirItem _reservoirItem;
-        /// <summary>
-        /// Wafer信息
-        /// </summary>
+        /// <summary>
+        /// Wafer信息
+        /// </summary>
         public WaferInfo WaferInfo { get { return WaferManager.Instance.GetWafer(Module,0); } }
 
         /// <summary>
         /// 当前Metal设置的WaferSize
         /// </summary>
-        public int MetalWaferSize { get { return _persistentValue.PlatingCellWaferSize; } }
-        #endregion
-
-        /// <summary>
-        /// 构造函数
-        /// </summary>
-        /// <param name="module"></param>
-        public PlatingCellEntity(ModuleName module)
-        {
-            this.Module = module;
-            InitialFsm();
-        }
-        /// <summary>
-        /// 初始化
-        /// </summary>
-        /// <returns></returns>
-        protected override bool Init()
+        public int MetalWaferSize { get { return _persistentValue.PlatingCellWaferSize; } }
+        #endregion
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="module"></param>
+        public PlatingCellEntity(ModuleName module)
+        {
+            this.Module = module;
+            InitialFsm();
+        }
+        /// <summary>
+        /// 初始化
+        /// </summary>
+        /// <returns></returns>
+        protected override bool Init()
+        {
+            WaferManager.Instance.SubscribeLocation(Module, 1);
+            InitializeRoutine();
+            InitializeDATA();
+            InitializeOperation();
+            InitializeParameter();
+            return true;
+        }
+
+        /// <summary>
+        /// 初始化参数
+        /// </summary>
+        private void InitializeParameter()
+        {
+            _persistentValue = PlatingCellPersistentManager.Instance.GetPlatingCellPersistentValue(Module.ToString());
+            if (_persistentValue == null)
+            {
+                LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module.ToString(), "Persistent Value Object is not exist");
+            }
+        }
+      
+        /// <summary>
+        /// 初始化Routine
+        /// </summary>
+        private void InitializeRoutine()
+        {
+            _initializeRoutine = new PlatingCellInitializeRoutine(Module.ToString());
+            _platingCellCRRoutine = new PlatingCellCCRRoutine(Module.ToString());
+        }
+        /// <summary>
+        /// 初始化DATA
+        /// </summary>
+        private void InitializeDATA()
         {
-            WaferManager.Instance.SubscribeLocation(Module, 1);
-            InitializeRoutine();
-            InitializeDATA();
-            InitializeOperation();
-            InitializeParameter();
-            return true;
-        }
-
-        /// <summary>
-        /// 初始化参数
-        /// </summary>
-        private void InitializeParameter()
-        {
-            _persistentValue = PlatingCellPersistentManager.Instance.GetPlatingCellPersistentValue(Module.ToString());
-            if (_persistentValue == null)
-            {
-                LOG.WriteLog(eEvent.ERR_PLATINGCELL, Module.ToString(), "Persistent Value Object is not exist");
-            }
-        }
-      
-        /// <summary>
-        /// 初始化Routine
-        /// </summary>
-        private void InitializeRoutine()
-        {
-            _initializeRoutine = new PlatingCellInitializeRoutine(Module.ToString());
-            _platingCellCRRoutine = new PlatingCellCCRRoutine(Module.ToString());
-        }
-        /// <summary>
-        /// 初始化DATA
-        /// </summary>
-        private void InitializeDATA()
-        {
-            DATA.Subscribe($"{Module}.FsmState", () => ((PlatingCellState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.CurrentRecipe", () => _currentRecipe != null ? _currentRecipe.Ppid : "", SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.TotalTime", () => _recipeTime, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.TimeRemain", () => _recipeTime != 0 && _runRecipeRoutine != null ? (_recipeTime - Math.Round((double)_runRecipeRoutine.ElapsedMilliseconds / 1000, 0)) : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.Chemistry", () => _currentRecipe != null ? _currentRecipe.Chemistry : "", SubscriptionAttribute.FLAG.IgnoreSaveDB);
-
-            DATA.Subscribe($"{Module}.IsInit", () => IsInit, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.IsIdle", () => IsIdle, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.IsError", () => IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.IsBusy", () => IsBusy, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.IsDisable", () => IsDisable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-        }
-        /// <summary>
-        /// 初始化Operation
-        /// </summary>
-        private void InitializeOperation()
-        {
-            OP.Subscribe($"{Module}.InitializeAll", (cmd, args) => { return CheckToPostMessage<PlatingCellState, PlatingCellMsg>(eEvent.ERR_RESERVOIR, Module.ToString(), (int)PlatingCellMsg.Initialize); });
-            OP.Subscribe($"{Module}.ManualCCRStart", (cmd, args) => { return CheckToPostMessage<PlatingCellState, PlatingCellMsg>(eEvent.ERR_RESERVOIR, Module.ToString(), (int)PlatingCellMsg.CCR); });
-            OP.Subscribe($"{Module}.ManualCCRStop", (cmd, args) => { return CheckToPostMessage<PlatingCellState, PlatingCellMsg>(eEvent.ERR_RESERVOIR, Module.ToString(), (int)PlatingCellMsg.CCRAbort); });
-        }
-
-        /// 初始化状态机
-        /// </summary>
-        private void InitialFsm()
-        {
-            fsm = new StateMachine<PlatingCellEntity>(Module.ToString(), (int)PlatingCellState.Idle, 100);
-            fsm.EnableRepeatedMsg(true);
-
-            AnyStateTransition(PlatingCellMsg.Error, NullFunc, PlatingCellState.Error);
-            //Initialized
-            Transition(PlatingCellState.Error, PlatingCellMsg.Initialize, InitializeAll, PlatingCellState.Initializing);
-            Transition(PlatingCellState.Init, PlatingCellMsg.Initialize, InitializeAll, PlatingCellState.Initializing);
-            Transition(PlatingCellState.Idle, PlatingCellMsg.Initialize, InitializeAll, PlatingCellState.Initializing);
-            Transition(PlatingCellState.Initializing, FSM_MSG.TIMER, InitializeAllMonitor, PlatingCellState.Idle);
-
-            //CCR
-            Transition(PlatingCellState.Idle, PlatingCellMsg.CCR, ManualCCRStart, PlatingCellState.CCRing);
-            Transition(PlatingCellState.CCRing, FSM_MSG.TIMER, CCRMonitor, PlatingCellState.Idle);
+            DATA.Subscribe($"{Module}.FsmState", () => ((PlatingCellState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.CurrentRecipe", () => _currentRecipe != null ? _currentRecipe.Ppid : "", SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.TotalTime", () => _recipeTime, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.TimeRemain", () => _recipeTime != 0 && _runRecipeRoutine != null ? (_recipeTime - Math.Round((double)_runRecipeRoutine.ElapsedMilliseconds / 1000, 0)) : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.Chemistry", () => _currentRecipe != null ? _currentRecipe.Chemistry : "", SubscriptionAttribute.FLAG.IgnoreSaveDB);
+
+            DATA.Subscribe($"{Module}.IsInit", () => IsInit, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.IsIdle", () => IsIdle, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.IsError", () => IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.IsBusy", () => IsBusy, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.IsDisable", () => IsDisable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+        }
+        /// <summary>
+        /// 初始化Operation
+        /// </summary>
+        private void InitializeOperation()
+        {
+            OP.Subscribe($"{Module}.InitializeAll", (cmd, args) => { return CheckToPostMessage<PlatingCellState, PlatingCellMsg>(eEvent.ERR_RESERVOIR, Module.ToString(), (int)PlatingCellMsg.Initialize); });
+            OP.Subscribe($"{Module}.ManualCCRStart", (cmd, args) => { return CheckToPostMessage<PlatingCellState, PlatingCellMsg>(eEvent.ERR_RESERVOIR, Module.ToString(), (int)PlatingCellMsg.CCR); });
+            OP.Subscribe($"{Module}.ManualCCRStop", (cmd, args) => { return CheckToPostMessage<PlatingCellState, PlatingCellMsg>(eEvent.ERR_RESERVOIR, Module.ToString(), (int)PlatingCellMsg.CCRAbort); });
+        }
+
+        /// 初始化状态机
+        /// </summary>
+        private void InitialFsm()
+        {
+            fsm = new StateMachine<PlatingCellEntity>(Module.ToString(), (int)PlatingCellState.Idle, 100);
+            fsm.EnableRepeatedMsg(true);
+
+            AnyStateTransition(PlatingCellMsg.Error, NullFunc, PlatingCellState.Error);
+            //Initialized
+            Transition(PlatingCellState.Error, PlatingCellMsg.Initialize, InitializeAll, PlatingCellState.Initializing);
+            Transition(PlatingCellState.Init, PlatingCellMsg.Initialize, InitializeAll, PlatingCellState.Initializing);
+            Transition(PlatingCellState.Idle, PlatingCellMsg.Initialize, InitializeAll, PlatingCellState.Initializing);
+            Transition(PlatingCellState.Initializing, FSM_MSG.TIMER, InitializeAllMonitor, PlatingCellState.Idle);
+
+            //CCR
+            Transition(PlatingCellState.Idle, PlatingCellMsg.CCR, ManualCCRStart, PlatingCellState.CCRing);
+            Transition(PlatingCellState.CCRing, FSM_MSG.TIMER, CCRMonitor, PlatingCellState.Idle);
             Transition(PlatingCellState.CCRing, PlatingCellMsg.CCRAbort, CCRAbort, PlatingCellState.Init);
             //Cycle Manual Process
             Transition(PlatingCellState.Idle, PlatingCellMsg.RunRecipe, CycleManualProcess, PlatingCellState.RunReciping);
             Transition(PlatingCellState.RunReciping, FSM_MSG.TIMER, CycleManualMonitor, PlatingCellState.Idle);
-            Transition(PlatingCellState.RunReciping, VPWCellMsg.Abort, RunRecipeAbort, PlatingCellState.Idle);
-            //直接进入Idle
-            Transition(PlatingCellState.Initialized, FSM_MSG.TIMER, NullFunc, PlatingCellState.Idle);
-            //Enter Init
-            Transition(PlatingCellState.Idle, PlatingCellMsg.Init, NullFunc, PlatingCellState.Init);
-
-            EnumLoop<PlatingCellState>.ForEach((item) => { fsm.MapState((int)item, item.ToString()); });
-
-            EnumLoop<PlatingCellState>.ForEach((item) => { fsm.MapMessage((int)item, item.ToString()); });
-        }
-        /// <summary>
-        /// 手动CCR
-        /// </summary>
-        /// <returns></returns>
-        private bool ManualCCRStart(object[] param)
-        {
-            bool result = _platingCellCRRoutine.Start() == RState.Running;
-            return result;
-
-        }
-        /// <summary>
-        /// CCR 监控
-        /// </summary>
-        /// <param name="param"></param>
-        /// <returns></returns>
-        private bool CCRMonitor(object[] param)
-        {
-            RState rsstate = RState.Running;
-            rsstate = _platingCellCRRoutine.Monitor();
-            if (rsstate == RState.End)
-            {
-                return true;
-            }
-            else if (rsstate == RState.Failed || rsstate == RState.Timeout)
-            {
-                PostMsg(PlatingCellMsg.Error);
-                return false;
-            }
-            return false;
-        }
-        /// <summary>
-        /// CCR abort
-        /// </summary>
-        /// <param name="param"></param>
-        /// <returns></returns>
-        private bool CCRAbort(object[] param)
-        {
-            if(_platingCellCRRoutine.Monitor() == RState.Running)
-            {
-                _platingCellCRRoutine.Abort();
-            }
-            return true;
-        }
-        /// <summary>
-        /// 初始化
-        /// </summary>
-        /// <returns></returns>
-        private bool InitializeAll(object[] param)
-        {
-            if (_persistentValue == null)
-            {
-                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module.ToString(), "persistent is null");
-                return false;
-            }
-            if (fsm.State == (int)PlatingCellState.Initializing)
-            {
-                LOG.WriteLog(eEvent.WARN_PLATINGCELL, Module.ToString(), "state is Initializing,cannot do initialize");
-                return false;
-            }
-            if (!CheckReservoirInitialized())
-            {
-                LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not initialized");
-                return false;
-            }
-            if (!MetalUsageMointor(Module.ToString()))
-            {
-                return false;
-            }
-            if ("Auto".Equals(_persistentValue.OperatingMode))
-            {
-                if (!CheckReservoirIsAuto())
-                {
-                    LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not in Auto OperationMode");
-                    return false;
-                }
-            }
-            bool result = _initializeRoutine.Start(_persistentValue) == RState.Running;
-            return result;
-           
-        }
-        /// <summary>
-        /// 检验Reservoir是否Auto
-        /// </summary>
-        /// <returns></returns>
-        private bool CheckReservoirIsAuto()
-        {
-            string reservoir = ReservoirItemManager.Instance.GetReservoirByPlatingCell(Module.ToString());
-            ReservoirsPersistentValue reservoirsPersistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(reservoir);
-            if ("Auto".Equals(reservoirsPersistentValue.OperatingMode))
-            {
-                return true;
-            }
-            return false;
-        }
-        /// <summary>
-        /// 检验Reservoir是否Initialized
-        /// </summary>
-        /// <returns></returns>
-        private bool CheckReservoirInitialized()
-        {
-            string reservoir = ReservoirItemManager.Instance.GetReservoirByPlatingCell(Module.ToString());
-            ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(reservoir);
-            if (reservoirEntity != null)
-            {
-                return reservoirEntity.IsInitialized;
-            }
-            return false;
-        }
-        /// <summary>
-        /// 监控 PM Counter Metal用量
-        /// </summary>
-        private bool MetalUsageMointor(string Module)
-        {
-            return true;
-        }
-        /// <summary>
-        /// Initialize 监控
-        /// </summary>
-        /// <param name="param"></param>
-        /// <returns></returns>
-        private bool InitializeAllMonitor(object[] param)
-        {
-            RState rsstate = RState.Running;
-            rsstate = _initializeRoutine.Monitor();
-            if (rsstate == RState.End)
-            {
-                return true;
-            }
-            else if (rsstate == RState.Failed || rsstate == RState.Timeout)
-            {
-                PostMsg(PlatingCellMsg.Error);
-                return false;
-            }
-            return false;
-        }
-
-        /// <summary>
-        /// EnterInit
-        /// </summary>
-        public void EnterInit()
-        {
-            if ((PlatingCellState)fsm.State != PlatingCellState.Idle) return;
-            else
-            {
-                CheckToPostMessage<PlatingCellState, PlatingCellMsg>(eEvent.ERR_PLATINGCELL, Module.ToString(), (int)PlatingCellMsg.Init);
-            }
-        }
-
+            Transition(PlatingCellState.RunReciping, VPWCellMsg.Abort, RunRecipeAbort, PlatingCellState.Idle);
+            //直接进入Idle
+            Transition(PlatingCellState.Initialized, FSM_MSG.TIMER, NullFunc, PlatingCellState.Idle);
+            //Enter Init
+            Transition(PlatingCellState.Idle, PlatingCellMsg.Init, NullFunc, PlatingCellState.Init);
+
+            EnumLoop<PlatingCellState>.ForEach((item) => { fsm.MapState((int)item, item.ToString()); });
+
+            EnumLoop<PlatingCellState>.ForEach((item) => { fsm.MapMessage((int)item, item.ToString()); });
+        }
+        /// <summary>
+        /// 手动CCR
+        /// </summary>
+        /// <returns></returns>
+        private bool ManualCCRStart(object[] param)
+        {
+            bool result = _platingCellCRRoutine.Start() == RState.Running;
+            return result;
+
+        }
+        /// <summary>
+        /// CCR 监控
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool CCRMonitor(object[] param)
+        {
+            RState rsstate = RState.Running;
+            rsstate = _platingCellCRRoutine.Monitor();
+            if (rsstate == RState.End)
+            {
+                return true;
+            }
+            else if (rsstate == RState.Failed || rsstate == RState.Timeout)
+            {
+                PostMsg(PlatingCellMsg.Error);
+                return false;
+            }
+            return false;
+        }
+        /// <summary>
+        /// CCR abort
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool CCRAbort(object[] param)
+        {
+            if(_platingCellCRRoutine.Monitor() == RState.Running)
+            {
+                _platingCellCRRoutine.Abort();
+            }
+            return true;
+        }
+        /// <summary>
+        /// 初始化
+        /// </summary>
+        /// <returns></returns>
+        private bool InitializeAll(object[] param)
+        {
+            if (_persistentValue == null)
+            {
+                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module.ToString(), "persistent is null");
+                return false;
+            }
+            if (fsm.State == (int)PlatingCellState.Initializing)
+            {
+                LOG.WriteLog(eEvent.WARN_PLATINGCELL, Module.ToString(), "state is Initializing,cannot do initialize");
+                return false;
+            }
+            if (!CheckReservoirInitialized())
+            {
+                LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not initialized");
+                return false;
+            }
+            if (!MetalUsageMointor(Module.ToString()))
+            {
+                return false;
+            }
+            if ("Auto".Equals(_persistentValue.OperatingMode))
+            {
+                if (!CheckReservoirIsAuto())
+                {
+                    LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not in Auto OperationMode");
+                    return false;
+                }
+            }
+            bool result = _initializeRoutine.Start(_persistentValue) == RState.Running;
+            return result;
+           
+        }
+        /// <summary>
+        /// 检验Reservoir是否Auto
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckReservoirIsAuto()
+        {
+            string reservoir = ReservoirItemManager.Instance.GetReservoirByPlatingCell(Module.ToString());
+            ReservoirsPersistentValue reservoirsPersistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(reservoir);
+            if ("Auto".Equals(reservoirsPersistentValue.OperatingMode))
+            {
+                return true;
+            }
+            return false;
+        }
+        /// <summary>
+        /// 检验Reservoir是否Initialized
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckReservoirInitialized()
+        {
+            string reservoir = ReservoirItemManager.Instance.GetReservoirByPlatingCell(Module.ToString());
+            ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(reservoir);
+            if (reservoirEntity != null)
+            {
+                return reservoirEntity.IsInitialized;
+            }
+            return false;
+        }
+        /// <summary>
+        /// 监控 PM Counter Metal用量
+        /// </summary>
+        private bool MetalUsageMointor(string Module)
+        {
+            return true;
+        }
+        /// <summary>
+        /// Initialize 监控
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool InitializeAllMonitor(object[] param)
+        {
+            RState rsstate = RState.Running;
+            rsstate = _initializeRoutine.Monitor();
+            if (rsstate == RState.End)
+            {
+                return true;
+            }
+            else if (rsstate == RState.Failed || rsstate == RState.Timeout)
+            {
+                PostMsg(PlatingCellMsg.Error);
+                return false;
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// EnterInit
+        /// </summary>
+        public void EnterInit()
+        {
+            if ((PlatingCellState)fsm.State != PlatingCellState.Idle) return;
+            else
+            {
+                CheckToPostMessage<PlatingCellState, PlatingCellMsg>(eEvent.ERR_PLATINGCELL, Module.ToString(), (int)PlatingCellMsg.Init);
+            }
+        }
+
         #region cycle manual process
         /// <summary>
         /// process
@@ -474,20 +474,20 @@ namespace PunkHPX8_RT.Modules.PlatingCell
             }
             return true;
         }
-        #endregion
+        #endregion
+
+        public bool Check(int msg, out string reason, params object[] args)
+        {
+            reason = "";
+            return true;
+        }
+
+        public bool CheckAcked(int msg)
+        {
+            throw new NotImplementedException();
+        }
 
-        public bool Check(int msg, out string reason, params object[] args)
-        {
-            reason = "";
-            return true;
-        }
-
-        public bool CheckAcked(int msg)
-        {
-            throw new NotImplementedException();
-        }
-
-        public int Invoke(string function, params object[] args)
+        public int Invoke(string function, params object[] args)
         {
             switch (function)
             {
@@ -504,8 +504,8 @@ namespace PunkHPX8_RT.Modules.PlatingCell
                     {
                         return (int)FSM_MSG.NONE;
                     }
-            }
-            return (int)FSM_MSG.NONE;
-        }
-    }
-}
+            }
+            return (int)FSM_MSG.NONE;
+        }
+    }
+}

+ 35 - 6
PunkHPX8_RT/Modules/VpwCell/VpwCellEntity.cs

@@ -1,4 +1,5 @@
-using Aitex.Core.RT.DataCenter;
+using Aitex.Core.Common;
+using Aitex.Core.RT.DataCenter;
 using Aitex.Core.RT.Device;
 using Aitex.Core.RT.Fsm;
 using Aitex.Core.RT.Log;
@@ -106,7 +107,7 @@ namespace PunkHPX8_RT.Modules.VpwMain
         /// <summary>
         /// 工艺当前执行小步骤
         /// </summary>
-        private string _currentStateMachine = "Init";
+        private string _currentStepState = "Init";
         /// <summary>
         /// 工艺当前执行大步骤
         /// </summary>
@@ -185,6 +186,20 @@ namespace PunkHPX8_RT.Modules.VpwMain
         /// 当前Vpw设置的WaferSize
         /// </summary>
         public int VpwWaferSize { get { return _persistentValue.VpwCellWaferSize; } }
+        /// <summary>
+        /// Wafer信息
+        /// </summary>
+        public WaferInfo WaferInfo { get { return WaferManager.Instance.GetWafer(Module, 0); } }
+
+        /// <summary>
+        /// 当前状态机状态
+        /// </summary>
+        public int State { get { return fsm.State; } }
+
+        /// <summary>
+        /// 当前执行步骤
+        /// </summary>
+        public string CurrentStepState { get { return _currentStepState; } }
         #endregion
 
         /// <summary>
@@ -407,10 +422,17 @@ namespace PunkHPX8_RT.Modules.VpwMain
                         _prepareRoutine.ErrorMsg, _prepareRoutine.ErrorStep, (int)AlarmType.Error);
                 AlarmListManager.Instance.AddAlarm(alarmList);
                 PostMsg(VPWCellMsg.Error);
+                _currentStepState = "";
                 return false;
             }
 
-            return ret == RState.End;
+            _currentStepState = _prepareRoutine.CurrentStep;
+            bool result= ret == RState.End;
+            if (result)
+            {
+                _currentStepState = "";
+            }
+            return result;
         }
 
         /// <summary>
@@ -451,10 +473,17 @@ namespace PunkHPX8_RT.Modules.VpwMain
                         _recipeRoutine.ErrorMsg, _recipeRoutine.ErrorStep, (int)AlarmType.Error);
                 AlarmListManager.Instance.AddAlarm(alarmList);
                 PostMsg(VPWCellMsg.Error);
+                _currentStepState = "";
                 return false;
             }
 
-            return ret == RState.End;
+            _currentStepState = _prepareRoutine.CurrentStep;
+            bool result= ret == RState.End;
+            if (result)
+            {
+                _currentStepState = "";
+            }
+            return result;
         }
 
         /// <summary>
@@ -499,11 +528,11 @@ namespace PunkHPX8_RT.Modules.VpwMain
         {
             RState state = _cycleManualProcessRoutine.Monitor();
             _currentStatus = _cycleManualProcessRoutine.CurrentStatus;
-            _currentStateMachine = _cycleManualProcessRoutine.CurrentStateMachine;
+            _currentStepState = _cycleManualProcessRoutine.CurrentStateMachine;
             if (state == RState.Failed || state == RState.Timeout)
             {
                 PostMsg(VPWCellMsg.Error);
-                _currentStateMachine = "Error";
+                _currentStepState = "Error";
                 _currentStatus = "Error";
 
                 _runRecipeCompleteTime = DateTime.Now;

+ 1 - 1
PunkHPX8_RT/Modules/VpwCell/VpwManualPrepareRoutine.cs

@@ -114,7 +114,7 @@ namespace PunkHPX8_RT.Modules.VpwCell
             {
                 return _vpwMainEntity.CheckToPostMessage<VPWMainState, VPWMainMsg>(eEvent.ERR_VPW, Module, (int)VPWMainMsg.Purge);
             }
-            else if (_vpwMainEntity.State == VPWMainState.Purgeing)
+            else if (_vpwMainEntity.State == VPWMainState.Purging)
             {
                 return true;
             }

+ 1 - 1
PunkHPX8_RT/Modules/VpwCell/VpwManualRecipeRoutine.cs

@@ -99,7 +99,7 @@ namespace PunkHPX8_RT.Modules.VpwCell
             Runner.Run(RecipeStep.Prepare, Prepare, _delay_1ms)
                 .WaitWithStopCondition(RecipeStep.WaitPrepare, () => CommonFunction.CheckRoutineEndState(_manualPrepareRoutine),
                     () => { return CheckSubRoutineError(_manualPrepareRoutine, _manualPrepareRoutine, 0); })
-                .Run(RecipeStep.VacuumPrewet, VacuumPrewet)
+                 .Run(RecipeStep.VacuumPrewet, VacuumPrewet)
                  .WaitWithStopCondition(RecipeStep.WaitVacuumPrewet, () => CommonFunction.CheckRoutineEndState(_vacuumPrewetRoutine),
                     () => { return CheckSubRoutineError(_vacuumPrewetRoutine, _vacuumPrewetRoutine, 1); })
                  .Run(RecipeStep.VentPrewet, VentPrewet)

+ 19 - 3
PunkHPX8_RT/Modules/VpwCell/VpwPrepareRoutine.cs

@@ -12,6 +12,7 @@ using PunkHPX8_RT.Devices.AXIS;
 using PunkHPX8_RT.Devices.VpwCell;
 using PunkHPX8_RT.Devices.VpwMain;
 using PunkHPX8_RT.Modules.VpwMain;
+using PunkHPX8_RT.Schedulers;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -31,6 +32,8 @@ namespace PunkHPX8_RT.Modules.VpwCell
             RotationPositionOffset,
             WaitRotation,
             CloseDrip,
+            WaitForChamberDown,
+            ChamerDown,
             Delay,
             End
         }
@@ -66,6 +69,7 @@ namespace PunkHPX8_RT.Modules.VpwCell
         /// <param name="module"></param>
         public VpwPrepareRoutine(string module) : base(module)
         {
+            RoutineName = "VpwPrepare";
         }
         /// <summary>
         /// 中止
@@ -87,7 +91,10 @@ namespace PunkHPX8_RT.Modules.VpwCell
                 .Run(PrepareStep.RotationPositionOffset,RotationPositionOffset,_delay_1ms)
                 .WaitWithStopCondition(PrepareStep.WaitRotation,CheckRotationStatus,CheckRotationStopStatus)
                 .Run(PrepareStep.CloseDrip,()=>_vpwCellDevice.FlowDripOff(),_delay_1ms)
-                .Delay(PrepareStep.Delay,_putDownAfterDripClose)
+                .Run(PrepareStep.ChamerDown, ChamberDown, () => {
+                    return _mainDevice.CommonData.ChamberOpened && !_mainDevice.CommonData.ChamberClosed;
+                },_delay_2s)
+                .Delay(PrepareStep.Delay,_putDownAfterDripClose)                
                 .End(PrepareStep.End,NullFun,_delay_1ms);
             return Runner.Status;
         }
@@ -104,9 +111,9 @@ namespace PunkHPX8_RT.Modules.VpwCell
             }
             if (_vpwMainEntity.IsIdle)
             {
-                return _vpwMainEntity.CheckToPostMessage<VPWMainState, VPWMainMsg>(eEvent.ERR_VPW, Module, (int)VPWMainMsg.Purge);
+                return _vpwMainEntity.CheckToPostMessage<VPWMainState, VPWMainMsg>(eEvent.INFO_VPW, Module, (int)VPWMainMsg.Purge);
             }
-            else if (_vpwMainEntity.State == VPWMainState.Purgeing)
+            else if (_vpwMainEntity.State == VPWMainState.Purging)
             {
                 return true;
             }
@@ -167,6 +174,14 @@ namespace PunkHPX8_RT.Modules.VpwCell
             return result;
         }
         /// <summary>
+        /// 打开 Chamber
+        /// </summary>
+        /// <returns></returns>
+        private bool ChamberDown()
+        {
+            return _mainDevice.ChamberDown();
+        }
+        /// <summary>
         /// 启动
         /// </summary>
         /// <param name="objs"></param>
@@ -192,6 +207,7 @@ namespace PunkHPX8_RT.Modules.VpwCell
                 NotifyError(eEvent.ERR_VPW,"rotaion is not switch on",-1);
                 return false;
             }
+
             return true;
         }
 

+ 16 - 11
PunkHPX8_RT/Modules/VpwMain/VpwMainEntity.cs

@@ -166,12 +166,9 @@ namespace PunkHPX8_RT.Modules.VpwMain
             //Enter Init
             Transition(VPWMainState.Idle, VPWMainMsg.Init, NullFunc, VPWMainState.Init);
             //Purge
-            Transition(VPWMainState.Idle, VPWMainMsg.Purge, Purge, VPWMainState.Purgeing);
-            Transition(VPWMainState.Purgeing, VPWMainMsg.Purge, NullFunc, VPWMainState.Purgeing);
-            Transition(VPWMainState.Purgeing, FSM_MSG.TIMER, PurgeMonitor, VPWMainState.Idle);
-           
-
-
+            Transition(VPWMainState.Idle, VPWMainMsg.Purge, Purge, VPWMainState.Purging);
+            Transition(VPWMainState.Purging, VPWMainMsg.Purge, NullFunc, VPWMainState.Purging);
+            Transition(VPWMainState.Purging, FSM_MSG.TIMER, PurgeMonitor, VPWMainState.Idle);
 
             EnumLoop<VPWMainState>.ForEach((item) => { fsm.MapState((int)item, item.ToString()); });
 
@@ -228,7 +225,6 @@ namespace PunkHPX8_RT.Modules.VpwMain
         {
             _homeRoutine = new VPWHomeRoutine(Module.ToString());
             _vpwPurgeRoutine = new VpwPurgeRoutine(Module.ToString());
-          
         }
         /// <summary>
         /// 初始化操作
@@ -239,7 +235,6 @@ namespace PunkHPX8_RT.Modules.VpwMain
             OP.Subscribe($"{Module}.Purge", (cmd, args) => { return CheckToPostMessage<VPWMainState, VPWMainMsg>(eEvent.ERR_VPWMAIN, Module.ToString(), (int)VPWMainMsg.Purge); });
         }
 
-
         #region Purge
         
         private bool Purge(object[] param)
@@ -279,7 +274,6 @@ namespace PunkHPX8_RT.Modules.VpwMain
         }
         #endregion
 
-
         #region InitializeAll
         /// <summary>
         /// Initialize
@@ -301,9 +295,20 @@ namespace PunkHPX8_RT.Modules.VpwMain
                     LOG.WriteLog(eEvent.ERR_VPWMAIN, Module.ToString(), $"cell device {device.Module} is busy,cannot initialize");
                     return false;
                 }
-                vpwCellEntity.CheckToPostMessage<VPWCellState, VPWCellMsg>(eEvent.INFO_VPW, device.Module, (int)VPWCellMsg.MainInitialize);
             }
-            return _homeRoutine.Start(_vpwCellDevices) == RState.Running;
+            bool result= _homeRoutine.Start(_vpwCellDevices) == RState.Running;
+            if (result)
+            {
+                foreach (var device in _vpwCellDevices)
+                {
+                    VpwCellEntity vpwCellEntity = Singleton<RouteManager>.Instance.GetModule<VpwCellEntity>(device.Module);
+                    if (vpwCellEntity.IsAuto)
+                    {
+                        vpwCellEntity.CheckToPostMessage<VPWCellState, VPWCellMsg>(eEvent.INFO_VPW, device.Module, (int)VPWCellMsg.MainInitialize);
+                    }
+                }
+            }
+            return true;
         }
 
         

+ 2 - 0
PunkHPX8_RT/PunkHPX8_RT.csproj

@@ -374,6 +374,7 @@
     <Compile Include="Schedulers\SchedulerSequence.cs" />
     <Compile Include="Schedulers\SchedulerSequenceRecipeManager.cs" />
     <Compile Include="Schedulers\SchedulerSyncModuleMessage.cs" />
+    <Compile Include="Schedulers\VPW\SchedulerVPW.cs" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Instances\RtInstance.cs" />
@@ -592,6 +593,7 @@
   <ItemGroup>
     <WCFMetadata Include="Connected Services\" />
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PreBuildEvent>python.exe  ../../Config/VenusPreProcess.py</PreBuildEvent>

+ 45 - 2
PunkHPX8_RT/Schedulers/EfemRobot/SchedulerRobot.cs

@@ -13,6 +13,8 @@ using System.Text;
 using System.Threading.Tasks;
 using MECF.Framework.Common.SubstrateTrackings;
 using PunkHPX8_RT.Modules.SRD;
+using PunkHPX8_RT.Modules.VpwMain;
+using PunkHPX8_RT.Modules.VpwCell;
 
 namespace PunkHPX8_RT.Schedulers.EfemRobot
 {
@@ -67,7 +69,8 @@ namespace PunkHPX8_RT.Schedulers.EfemRobot
             }
             MoveItem moveItem = (MoveItem)parameter;
             if (moveItem.SourceModule != ModuleName.Unknown&&moveItem.DestinationModule!=ModuleName.Unknown)
-            {                
+            {
+                SynchorinzeModuleMessages(syncMessages);
                 _state = RState.Running;
                 if (RobotMoveHelper.Instance.IsIdle)
                 {
@@ -105,7 +108,6 @@ namespace PunkHPX8_RT.Schedulers.EfemRobot
                 reason = "parameter is null";
                 return true;
             }
-
             if (_state == RState.Running)
             {
                 reason = "scheduler module is already running";
@@ -142,6 +144,47 @@ namespace PunkHPX8_RT.Schedulers.EfemRobot
                     return false;
                 }
             }
+
+            if (!WaferManager.Instance.CheckHasWafer(moveItem.SourceModule, moveItem.SourceSlot))
+            {
+                reason = $"{moveItem.SourceModule} slot {moveItem.SourceSlot} has no wafer";
+                return false;
+            }
+            if (WaferManager.Instance.CheckHasWafer(moveItem.DestinationModule, moveItem.DestinationSlot))
+            {
+                reason = $"{moveItem.DestinationSlot} slot {moveItem.SourceSlot} has wafer";
+                return false;
+            }
+
+            if (ModuleHelper.IsVPWCell(moveItem.DestinationModule)||ModuleHelper.IsVPWCell(moveItem.SourceModule))
+            {
+                VpwCellEntity vpwEntity = Singleton<RouteManager>.Instance.GetModule<VpwCellEntity>(moveItem.DestinationModule.ToString());
+                if (vpwEntity != null)
+                {
+                    if (vpwEntity.State == (int)VPWCellState.WaitForRunRecipe)
+                    {
+                        return true;
+                    }
+                    else
+                    {
+                        if (vpwEntity.IsIdle)
+                        {
+                            if (sequenceIndex + 1 < schedulerSequences.Count)
+                            {
+                                SchedulerSequence nextSequence = schedulerSequences[sequenceIndex + 1];
+                                vpwEntity.CheckToPostMessage<VPWCellState, VPWCellMsg>(eEvent.INFO_VPW, Module.ToString(),
+                                    (int)VPWCellMsg.Prepare, nextSequence.Recipe);
+                            }
+                        }
+                        reason = $"{vpwEntity.Module} state is not WaitForRunRecipe";
+                        return false;
+                    }
+                }
+                else
+                {
+                    reason = $"{moveItem.DestinationModule} is null";
+                }
+            }
             return true;
         }
         /// <summary>

+ 31 - 0
PunkHPX8_RT/Schedulers/SchedulerManager.cs

@@ -14,6 +14,7 @@ using PunkHPX8_RT.Schedulers.Srd;
 using PunkHPX8_RT.Dispatch;
 using PunkHPX8_RT.Modules;
 using Aitex.Core.RT.SCCore;
+using PunkHPX8_RT.Modules.VpwMain;
 
 namespace PunkHPX8_RT.Schedulers
 {
@@ -51,6 +52,7 @@ namespace PunkHPX8_RT.Schedulers
             AddScheduleModule(ModuleType.EfemRobot, new SchedulerRobot(ModuleName.EfemRobot));
             AddScheduleModule(ModuleType.Aligner, new SchedulerAligner(ModuleName.Aligner1));
             InitializeSchedulerModules(SrdItemManager.Instance.InstalledModules,ModuleType.SRD,typeof(SchedulerSrd));
+            InitializeSchedulerModules(VpwCellItemManager.Instance.InstalledModules, ModuleType.VPW, typeof(SchedulerVPW));
         }
         /// <summary>
         /// 重置
@@ -124,5 +126,34 @@ namespace PunkHPX8_RT.Schedulers
         {
             return _scheduleModuleTypeDic.ContainsKey(moduleType) ? _scheduleModuleTypeDic[moduleType]: null;
         }
+        /// <summary>
+        /// 获取配对的VPW
+        /// </summary>
+        /// <returns></returns>
+        public VpwCellEntity GetMatchedVpw(string module)
+        {
+            VpwCellEntity vpwCellEntity1 = Singleton<RouteManager>.Instance.GetModule<VpwCellEntity>(ModuleName.VPW1.ToString());
+            VpwCellEntity vpwCellEntity2 = Singleton<RouteManager>.Instance.GetModule<VpwCellEntity>(ModuleName.VPW2.ToString());
+            if (vpwCellEntity1 == null || vpwCellEntity2 == null)
+            {
+                return null;
+            }
+            if (!vpwCellEntity1.IsAuto || !vpwCellEntity2.IsAuto)
+            {
+                return null;
+            }
+            if(!WaferManager.Instance.CheckHasWafer(ModuleName.VPW1,0)||!WaferManager.Instance.CheckHasWafer(ModuleName.VPW2,0))
+            {
+                return null;
+            }
+            if (module == ModuleName.VPW1.ToString())
+            {
+                return vpwCellEntity2;
+            }
+            else
+            {
+                return vpwCellEntity1;
+            }
+        }
     }
 }

+ 37 - 12
PunkHPX8_RT/Schedulers/SchedulerSequenceManager.cs

@@ -28,6 +28,8 @@ using PunkHPX8_RT.Devices.EFEM;
 using Aitex.Sorter.Common;
 using PunkHPX8_RT.Modules.Reservoir;
 using PunkHPX8_RT.Modules.PlatingCell;
+using PunkHPX8_RT.Modules.VpwMain;
+using PunkHPX8_RT.Modules.VpwCell;
 
 namespace PunkHPX8_RT.Schedulers
 {
@@ -143,7 +145,7 @@ namespace PunkHPX8_RT.Schedulers
         /// </summary>
         /// <param name="sequenceRecipe"></param>
         /// <returns></returns>
-        public List<SchedulerSequence> AnalyDummyWaferAllSchedulerSequence(SequenceRecipe sequenceRecipe,WaferInfo waferInfo)
+        public List<SchedulerSequence> AnalyDummyWaferAllSchedulerSequence(SequenceRecipe sequenceRecipe, ModuleName vpw, WaferInfo waferInfo)
         {
             List<SchedulerSequence> schedulerSequences = new List<SchedulerSequence>();
             int index = 0;
@@ -153,6 +155,9 @@ namespace PunkHPX8_RT.Schedulers
             schedulerSequences.Add(efemRobotSequence);
             SchedulerSequence alignerSequence = CreateAlignerSequence(sequenceRecipe, ref index);
             schedulerSequences.Add(alignerSequence);
+            MoveItem alignerToMoveItem = new MoveItem(ModuleName.Aligner1, 0, vpw, 0, Hand.Blade1, Flip.Upper, Flip.Upper);
+            SchedulerSequence alignerRobotSequence = CreateEfemRobotSequence(alignerToMoveItem, null, sequenceRecipe.SubstrateSize, ref index);
+            schedulerSequences.Add(alignerRobotSequence);
             //解析sequence recipe后续的工序
             var sequences = AnalyseSequenceRecipeScheduler(sequenceRecipe, false);
             if (sequences.Count == 0)
@@ -164,17 +169,8 @@ namespace PunkHPX8_RT.Schedulers
             {
                 return schedulerSequences;
             }
-            SchedulerSequence lastSequence=sequences[sequences.Count - 1];
-            MoveItem alignerToFirstMoveItem = new MoveItem();
-            alignerToFirstMoveItem.SourceModule = ModuleName.Aligner1;
-            alignerToFirstMoveItem.SourceSlot = 0;
-            alignerToFirstMoveItem.DestinationType = firstSequence.ModuleType;
-            alignerToFirstMoveItem.DestinationSlot = 0;
-            alignerToFirstMoveItem.RobotHand = Hand.Blade1;
-            alignerToFirstMoveItem.PickRobotFlip = Flip.Upper;
-            alignerToFirstMoveItem.PlaceRobotFlip = Flip.Upper;
-            SchedulerSequence alignerToFirstSequence = CreateEfemRobotSequence(moveItem, null, sequenceRecipe.SubstrateSize, ref index);
-            schedulerSequences.Add(efemRobotSequence);
+            firstSequence.SchedulerModule = SchedulerManager.Instance.GetScheduler(vpw);
+            firstSequence.ModuleName = vpw;
             //调整工序后面的索引
             foreach (SchedulerSequence item in sequences)
             {
@@ -183,6 +179,7 @@ namespace PunkHPX8_RT.Schedulers
             }
             schedulerSequences.AddRange(sequences);
 
+            SchedulerSequence lastSequence=sequences[sequences.Count - 1];
             //若无SRD,直接从VPW转LoadPort
             MoveItem srdToLoadPortItem = new MoveItem();
             srdToLoadPortItem.SourceModule = ModuleName.Unknown;
@@ -546,6 +543,34 @@ namespace PunkHPX8_RT.Schedulers
             return metals;
         }
 
+        /// <summary>
+        /// 获取可用的VPW集合
+        /// </summary>
+        /// <param name="chemistry"></param>
+        /// <returns></returns>
+        public List<VpwCellEntity> GetAvaibleVpwList(int waferSize, bool isEmpty)
+        {
+            List<IModuleEntity> vpwEtities = Singleton<RouteManager>.Instance.GetModulesByModuleType(ModuleType.VPW);
+            List<string> avaibles = new List<string>();
+            List<VpwCellEntity> vpws = new List<VpwCellEntity>();
+            foreach (IModuleEntity item in vpwEtities)
+            {
+                VpwCellEntity entity = (VpwCellEntity)item;
+                if (!CheckAvaibleModule(entity, ModuleType.VPW, ""))
+                {
+                    continue;
+                }
+                if (entity.VpwWaferSize != waferSize)
+                {
+                    continue;
+                }
+                if (!isEmpty || (isEmpty && entity.WaferInfo == null))
+                {
+                    vpws.Add(entity);
+                }
+            }
+            return vpws;
+        }
     }
 
 

+ 13 - 0
PunkHPX8_RT/Schedulers/SchedulerSequenceRecipeManager.cs

@@ -7,6 +7,7 @@ using MECF.Framework.Common.ToolLayout;
 using PunkHPX8_RT.Modules;
 using PunkHPX8_RT.Modules.PlatingCell;
 using PunkHPX8_RT.Modules.Reservoir;
+using PunkHPX8_RT.Modules.VpwMain;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -80,6 +81,18 @@ namespace PunkHPX8_RT.Schedulers
                         return false;
                     }
                 }
+                else if (moduleType == ModuleType.VPW)
+                {
+                    List<VpwCellEntity> cells = SchedulerSequenceManager.Instance.GetAvaibleVpwList(sequenceRecipe.SubstrateSize, false);
+                    if (cells.Count == 0)
+                    {
+                        if (showError)
+                        {
+                            LOG.WriteLog(eEvent.ERR_SEQUENCE, "System", $"sequece {sequenceRecipe.Ppid} vpw has not avaible cell");
+                        }
+                        return false;
+                    }
+                }
                 else 
                 {
                     ModuleName moduleName= SchedulerSequenceManager.Instance.GetAvaibleModuleCell(sequenceRecipe.SequenceType,moduleType);

+ 118 - 0
PunkHPX8_RT/Schedulers/VPW/SchedulerVPW.cs

@@ -0,0 +1,118 @@
+using Aitex.Common.Util;
+using Aitex.Core.Common;
+using Aitex.Core.RT.Log;
+using Aitex.Core.Util;
+using PunkHPX8_Core;
+using PunkHPX8_RT.Modules;
+using PunkHPX8_RT.Modules.SRD;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.RecipeCenter;
+using MECF.Framework.Common.SubstrateTrackings;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using PunkHPX8_RT.Modules.VpwMain;
+using PunkHPX8_RT.Modules.VpwCell;
+
+namespace PunkHPX8_RT.Schedulers.Srd
+{
+    public class SchedulerVPW : SchedulerModule
+    {
+        #region 内部变量
+        private VpwCellEntity _vpwEntity;
+        private bool _isStartRunRecipe = false;
+        #endregion
+
+        #region 属性
+        /// <summary>
+        /// 是否空闲
+        /// </summary>
+        public override bool IsIdle
+        {
+            get { return _state == RState.End; }
+        }
+        /// <summary>
+        /// 是否错误
+        /// </summary>
+        public override bool IsError
+        {
+            get { return _state == RState.Failed || _state == RState.Timeout; }
+        }
+        #endregion
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="moduleName"></param>
+        public SchedulerVPW(ModuleName moduleName) : base(moduleName.ToString())
+        {
+            _vpwEntity = Singleton<RouteManager>.Instance.GetModule<VpwCellEntity>(moduleName.ToString());
+        }
+        /// <summary>
+        /// 执行
+        /// </summary>
+        /// <param name="parameter"></param>
+        /// <returns></returns>
+        public override bool RunProcess(object recipe, object parameter, List<SchedulerSyncModuleMessage> syncModuleMessages)
+        {
+            if (!(recipe is VpwRecipe))
+            {
+                _state = RState.Failed;
+                LOG.WriteLog(eEvent.ERR_SRD, Module.ToString(), "recipe is invalid");
+                return false;
+            }
+            _isStartRunRecipe = false;
+            VpwRecipe vpwRecipe = (VpwRecipe)recipe;
+            bool result = _vpwEntity.CheckToPostMessage<VPWCellState, VPWCellMsg>(eEvent.INFO_VPW, Module.ToString(), (int)VPWCellMsg.RunRecipe, vpwRecipe, 1);
+            if (result)
+            {
+                _state = RState.Running;
+            }
+            return result;
+        }
+        /// <summary>
+        /// 监控执行
+        /// </summary>
+        /// <returns></returns>
+        public override bool MonitorProcess(SchedulerSequence schedulerSequence,bool hasMatchWafer)
+        {
+            if (!_isStartRunRecipe)
+            {
+                _isStartRunRecipe = _vpwEntity.State == (int)VPWCellState.RunReciping;
+            }
+            if (_isStartRunRecipe && _vpwEntity.IsIdle)
+            {
+                _state = RState.End;
+                _isStartRunRecipe = false;
+            }
+            return true;
+        }
+        /// <summary>
+        /// 检验前置条件
+        /// </summary>
+        /// <param name="sequenceIndex"></param>
+        /// <param name="parameter"></param>
+        /// <returns></returns>
+        public override bool CheckPrecondition(List<SchedulerSequence> schedulerSequences, int sequenceIndex, object parameter, string materialId,ref string reason)
+        {
+            if (_state == RState.Running)
+            {
+                reason = "scheduler module is already running";
+                return false;
+            }
+            if (_vpwEntity.IsBusy)
+            {
+                reason = $"{_vpwEntity.Module} is busy";
+                return false;
+            }
+
+            if(WaferManager.Instance.CheckNoWafer(Module,0))
+            {
+                reason = $"{_vpwEntity.Module} has no wafer";
+                return false;
+            }
+            return true;
+        }
+    }
+}