Browse Source

add VPW Prepare routine

chenkui 3 days ago
parent
commit
28e1e8e4ab

+ 5 - 0
Framework/Common/ToolLayout/VpwCellItem.cs

@@ -13,5 +13,10 @@ namespace MECF.Framework.Common.ToolLayout
         /// VpwCell ID 
         /// </summary>
         public int VpwCellID { get; set; }
+
+        /// <summary>
+        /// Resistivity ID 
+        /// </summary>
+        public string ResistivityID { get; set; }
     }
 }

+ 1 - 0
Framework/Common/ToolLayout/VpwCellItemManager.cs

@@ -44,6 +44,7 @@ namespace MECF.Framework.Common.ToolLayout
             vpwCellItem.CellType = "Cell";
             LayoutCellItemManager.Instance.InitializeLayoutCellItem(vpwCellItem, element);
             vpwCellItem.VpwCellID = int.Parse(element.SelectSingleNode("VpwCellID").InnerText);
+            vpwCellItem.ResistivityID = element.SelectSingleNode("ResistivityID").InnerText;
             string key = $"{PREFIX}{vpwCellItem.VpwCellID}";
             vpwCellItem.ModuleName = key;
             vpwCellItem.ModuleType = ModuleType.Metal.ToString();

+ 5 - 0
PunkHPX8_Core/RtState.cs

@@ -138,5 +138,10 @@ namespace PunkHPX8_Core
         Initializing,
         Initialized,
         Idle,
+        Retrying,
+        Preparing,
+        WaitForRunRecipe,
+        RunReciping,
+        ManualReciping,
     }
 }

+ 2 - 36
PunkHPX8_RT/Config/Layout/ToolLayoutConfiguration.xml

@@ -114,16 +114,8 @@
 		</Item>
 
 		<!-- RESISTIVITY PROBES -->
-
 		<Item i:type="ResistivityProbe">
 			<Installed>true</Installed>
-			<Count>4</Count>
-			<ResistivityProbeID>1</ResistivityProbeID>
-			<SubType>STDThornton</SubType>
-		</Item>
-
-		<Item i:type="ResistivityProbe">
-			<Installed>false</Installed>
 			<Count>1</Count>
 			<ResistivityProbeID>2</ResistivityProbeID>
 			<SubType>STDThornton</SubType>
@@ -149,6 +141,7 @@
 					<CellID>14</CellID>
 					<NominalGantryPositionInMilliMeters>2219</NominalGantryPositionInMilliMeters>
 					<VpwCellID>1</VpwCellID>
+					<ResistivityID>RP1-1</ResistivityID>
 					<SubType>Stratus</SubType>
 				</Item>
 				<Item i:type="VpwCell">
@@ -156,38 +149,11 @@
 					<CellID>15</CellID>
 					<NominalGantryPositionInMilliMeters>2219</NominalGantryPositionInMilliMeters>
 					<VpwCellID>2</VpwCellID>
+					<ResistivityID>RP1-2</ResistivityID>
 					<SubType>Stratus</SubType>
 				</Item>
 			</Cells>
 		</Item>
-		
-		<!-- PREWET -->
-
-		<Item i:type="Prewet">
-			<Installed>false</Installed>
-			<CellID>20</CellID>
-			<NominalGantryPositionInMilliMeters>1135</NominalGantryPositionInMilliMeters>
-			<PrewetID>1</PrewetID>
-			<SubType>Scanning</SubType>
-			<LinmotID>LNM3-1</LinmotID>
-		</Item>
-
-		<!-- DRYERs -->
-
-		<Item i:type="Dryer">
-			<Installed>false</Installed>
-			<CellID>21</CellID>
-			<NominalGantryPositionInMilliMeters>957</NominalGantryPositionInMilliMeters>
-			<DryerID>1</DryerID>
-			<SubType>HVDHSIndependent</SubType>
-		</Item>
-		<Item i:type="Dryer">
-			<Installed>false</Installed>
-			<CellID>22</CellID>
-			<NominalGantryPositionInMilliMeters>873</NominalGantryPositionInMilliMeters>
-			<DryerID>2</DryerID>
-			<SubType>HVDHSIndependent</SubType>
-		</Item>
 		<!-- SRDs -->
 
 		<Item i:type="SRD">

+ 5 - 1
PunkHPX8_RT/Config/System.sccfg

@@ -13,7 +13,7 @@
 		<config default="true" name="DisplayPopDialogWhenJobComplete" nameView="Pop Dialog When Job Complete" description="是否弹出Job结束对话框" max="" min="" paramter="" tag="" unit="" type="Bool" />
 		<config default="True" name="IsIgnoreSaveDB" nameView="IsIgnoreSaveDB" description="IO实时数据是否保存数据库,2023/09/02暂时加参数设计" max="" min="" paramter="" tag="" unit="" type="Bool" visible="false"/>
 		<config default="10"  name="CheckResourceInterval" nameView="CheckResourceInterval" description="进程资源监视间隔,单位为分钟,0为不监视" max="60" min="0" paramter="" tag="" unit="min" type="Integer"/>
-		<config default="Cyber X8" name="Name" nameView="Name" description="Name" tag="" unit="" type="String" />
+		<config default="PunkHP8" name="Name" nameView="Name" description="Name" tag="" unit="" type="String" />
 		<config default="100" name="CompareInterval" nameView="CompareInterval" description="interval distance of comparing left/right side of target position" tag="" unit="mm" type="Double" />
 		<config default="1000"  name="DataCollectionInterval" nameView="DataCollectionInterval" description="插入数据时间间隔" max="2000" min="200" paramter="" tag="" unit="ms" type="Integer"/>
 		<configs name="Job" nameView="Job"  >
@@ -254,6 +254,10 @@
 			<config default="400" name="PurgeMotorSpeed" nameView="PurgeMotorSpeed" max="5000.0" min="0" description="rotation default velocity in homing period." paramter="" tag="" unit="rpm" type="Double" />
 		</configs>
 	</configs>
+	<configs name="VPW1">
+		<config default="2000" name="PutDownAfterDripClose" nameView="PutDownAfterDripClose" description="Delay time for put down chamber after drip valve close" max="10000" min="1" paramter="" tag="" unit="ms" type="Integer"></config>
+		<config default="300" name="WaitForWaferTime" nameView="WaitForWaferTime" description="Wait for wafer to place into VPW" max="3600" min="1" paramter="" tag="" unit="s" type="Integer" visible="false"></config>
+	</configs>
 	<configs name="Linmot" nameView="Linmot">
 		<config default="5000" name="LinmotHoldoffMilliseconds" nameView="LinmotHoldoffMilliseconds" description="Linmot Hold off Milliseconds" max="10000" min="1" paramter="" tag="" unit="ms" type="Integer"></config>
 	</configs>

+ 46 - 1
PunkHPX8_RT/Devices/VpwCell/VpwCellDevice.cs

@@ -11,8 +11,10 @@ using MECF.Framework.Common.Persistent.SRD;
 using MECF.Framework.Common.Persistent.Temperature;
 using MECF.Framework.Common.Persistent.VpwCell;
 using MECF.Framework.Common.Persistent.VpwMain;
+using MECF.Framework.Common.ToolLayout;
 using MECF.Framework.Common.Utilities;
 using PunkHPX8_RT.Devices.AXIS;
+using PunkHPX8_RT.Devices.Resistivity;
 using PunkHPX8_RT.Modules;
 using PunkHPX8_RT.Modules.VpwMain;
 using System;
@@ -37,6 +39,7 @@ namespace PunkHPX8_RT.Devices.VpwCell
         private const string VENT_VALVE = "VentValve";
         private const string DRAIN_VALVE = "DrainValve";
         private const string PERSISTENT_VALUE = "PersistentValue";
+        private const string LOOPDO_VALUE = "LoopDoValue";
         #endregion
 
         #region 内部变量
@@ -56,6 +59,14 @@ namespace PunkHPX8_RT.Devices.VpwCell
         /// 水平电机
         /// </summary>
         private JetAxisBase _rotationAxis;
+        /// <summary>
+        /// 水阻计控制器
+        /// </summary>
+        private ResistivityController _resistivityController;
+        /// <summary>
+        /// 水阻值
+        /// </summary>
+        private double _resistivityValue;
         #endregion
 
         #region 属性
@@ -71,6 +82,10 @@ namespace PunkHPX8_RT.Devices.VpwCell
         /// 工程模式
         /// </summary>
         public string EngineerMode { get { return _vpwCellPersistentValue.RecipeOperatingMode; } }
+        /// <summary>
+        /// LoopDO数值
+        /// </summary>
+        public double LoopDOValue { get { return GetLoopDOValue(); } }
         #endregion
         /// <summary>
         /// 构造函数
@@ -101,7 +116,12 @@ namespace PunkHPX8_RT.Devices.VpwCell
         private void InitializeParameter()
         {
             _rotationAxis = DEVICE.GetDevice<JetAxisBase>($"{Module}.Rotation");
-            _vpwCellPersistentValue = VpwCellPersistentManager.Instance.GetPersistentValue(Module);           
+            _vpwCellPersistentValue = VpwCellPersistentManager.Instance.GetPersistentValue(Module);     
+            VpwCellItem vpwCellItem=VpwCellItemManager.Instance.GetVpwItem(Module);
+            if (vpwCellItem != null)
+            {
+                _resistivityController = DEVICE.GetDevice<ResistivityController>(vpwCellItem.ResistivityID);
+            }
         }
         /// <summary>
         /// 初始化Routine
@@ -118,6 +138,31 @@ namespace PunkHPX8_RT.Devices.VpwCell
             DATA.Subscribe($"{Module}.{COMMON_DATA}", () => CommonData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.{PERSISTENT_VALUE}", () => _vpwCellPersistentValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.DiwCellFlow", () => CommonData.DiwFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.{LOOPDO_VALUE}", ()=> { return GetLoopDOValue(); }, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+        }
+        /// <summary>
+        /// 获取Loop do数值
+        /// </summary>
+        /// <returns></returns>
+        private double GetLoopDOValue()
+        {
+            if (_resistivityController != null)
+            {
+                string value = _resistivityController.ResisitivityValue;
+                if (double.TryParse(value, out _resistivityValue))
+                {
+                    return _resistivityValue;
+                }
+                else
+                {
+                    _resistivityValue = 0;
+                    return 0;
+                }
+            }
+            else
+            {
+                return 0;
+            }
         }
         /// <summary>
         /// 订阅数据

+ 1 - 1
PunkHPX8_RT/Modules/EFEM/EfemPlaceRoutine.cs

@@ -180,7 +180,7 @@ namespace PunkHPX8_RT.Modules.EFEM
                 Runner.WaitIf(PlaceStep.WaitIdle, _isAligner, WaitModuleReady)
                     .RunIf(PlaceStep.SetAlignWaferSize, _isAligner, SetAlignerWaferSize, _delay_1ms)
                      .Wait(PlaceStep.WaitWaferSizeIdle, WaitModuleReady)
-                    .RunIf(PlaceStep.SetAlignWaferSize, _isAligner, SetAlignerDistance, _delay_1ms)
+                    .RunIf(PlaceStep.SetAlignDistance, _isAligner, SetAlignerDistance, _delay_1ms)
                      .Wait(PlaceStep.WaitAlignDistanceIdle, WaitModuleReady)
                     .Wait(PlaceStep.WaitModuleReady, WaitModuleReady)
                         .Run(PlaceStep.Placing1,           Place1,         Place1Done,     _moveTimeout)

+ 170 - 1
PunkHPX8_RT/Modules/VpwCell/VpwCellEntity.cs

@@ -5,10 +5,14 @@ using Aitex.Core.RT.Log;
 using Aitex.Core.RT.OperationCenter;
 using Aitex.Core.Util;
 using Aitex.Core.Utilities;
+using MECF.Framework.Common.Alarm;
+using MECF.Framework.Common.CommonData;
 using MECF.Framework.Common.Equipment;
 using MECF.Framework.Common.Persistent.Temperature;
 using MECF.Framework.Common.Persistent.VpwCell;
 using MECF.Framework.Common.Persistent.VpwMain;
+using MECF.Framework.Common.RecipeCenter;
+using MECF.Framework.Common.Routine;
 using MECF.Framework.Common.SubstrateTrackings;
 using MECF.Framework.Common.ToolLayout;
 using PunkHPX8_Core;
@@ -55,6 +59,18 @@ namespace PunkHPX8_RT.Modules.VpwMain
         /// Home Routine
         /// </summary>
         private VPWHomeRoutine _homeRoutine;
+        /// <summary>
+        /// Prepare
+        /// </summary>
+        private VpwPrepareRoutine _prepareRoutine;
+        /// <summary>
+        /// recipe routine
+        /// </summary>
+        private VpwRecipeRoutine _recipeRoutine;
+        /// <summary>
+        /// 手动recipe routine
+        /// </summary>
+        private VpwManualRecipeRoutine _manualRecipeRoutine;
         #endregion
 
         #region 属性
@@ -176,6 +192,20 @@ namespace PunkHPX8_RT.Modules.VpwMain
             Transition(VPWCellState.Idle, VpwCellMsg.EnterIdle, NullFunc, VPWCellState.Idle);
             //Enter Init
             Transition(VPWCellState.Idle, VpwCellMsg.Init, NullFunc, VPWCellState.Init);
+            //Manual Recipe
+            Transition(VPWCellState.Idle, VpwCellMsg.ManualRecipe, ManualRunRecipe, VPWCellState.ManualReciping);
+            Transition(VPWCellState.ManualReciping, FSM_MSG.TIMER, ManualRunRecipeMonitor, VPWCellState.Idle);
+            //Prepare
+            Transition(VPWCellState.Idle, VpwCellMsg.Prepare, Prepare, VPWCellState.Preparing);
+            Transition(VPWCellState.Preparing, FSM_MSG.TIMER, PrepareMonitor, VPWCellState.WaitForRunRecipe);
+            Transition(VPWCellState.WaitForRunRecipe, VpwCellMsg.RunRecipe, RunRecipe, VPWCellState.RunReciping);
+            Transition(VPWCellState.RunReciping, FSM_MSG.TIMER, RunRecipeMonitor, VPWCellState.Idle);
+
+            //Retry
+            Transition(VPWCellState.Error, VpwCellMsg.Retry, NullFunc, VPWCellState.Retrying);
+            Transition(VPWCellState.Retrying, FSM_MSG.TIMER, VpwCellRetry, VPWCellState.Retrying);
+            Transition(VPWCellState.Retrying, VpwCellMsg.Prepare, RetryPrepare, VPWCellState.Preparing);
+            Transition(VPWCellState.Retrying, VpwCellMsg.RunRecipe, RetryRunRecipe, VPWCellState.RunReciping);
         }
         /// <summary>
         /// 初始化数据
@@ -205,13 +235,17 @@ namespace PunkHPX8_RT.Modules.VpwMain
         private void InitializeRoutine()
         {
             _homeRoutine = new VPWHomeRoutine(Module.ToString());
+            _prepareRoutine=new VpwPrepareRoutine(Module.ToString());
+            _recipeRoutine=new VpwRecipeRoutine(Module.ToString());
+            _manualRecipeRoutine=new VpwManualRecipeRoutine(Module.ToString());
         }
         /// <summary>
         /// 初始化操作
         /// </summary>
         private void InitializeOperation()
         {
-            OP.Subscribe($"{Module}.InitializeAll", (cmd, args) => { return CheckToPostMessage<VPWCellState, VpwCellMsg>(eEvent.ERR_VPWMAIN, Module.ToString(), (int)VpwCellMsg.Initialize); });
+            OP.Subscribe($"{Module}.InitializeAll", (cmd, args) => { return CheckToPostMessage<VPWCellState, VpwCellMsg>(eEvent.ERR_VPW, Module.ToString(), (int)VpwCellMsg.Initialize); });
+            OP.Subscribe($"{Module}.Prepare", (cmd, args) => { return CheckToPostMessage<VPWCellState, VpwCellMsg>(eEvent.ERR_VPW, Module.ToString(), (int)VpwCellMsg.Prepare); });
         }
 
         #region InitializeAll
@@ -256,6 +290,141 @@ namespace PunkHPX8_RT.Modules.VpwMain
         }
         #endregion
 
+        #region Prepare
+        /// <summary>
+        /// Prepare
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool Prepare(object[] param)
+        {
+            VpwRecipe recipe = param[0] as VpwRecipe;
+            return _prepareRoutine.Start(recipe) == RState.Running;
+        }
+        /// <summary>
+        /// Prepare 监控
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool PrepareMonitor(object[] param)
+        {
+            RState ret = _prepareRoutine.Monitor();
+            if (ret == RState.Failed || ret == RState.Timeout)
+            {
+                AlarmList alarmList = new AlarmList(Module.ToString(), ((VPWCellState)fsm.State).ToString(), (int)VpwCellMsg.Prepare,
+                        _prepareRoutine.ErrorMsg, _prepareRoutine.ErrorStep, (int)AlarmType.Error);
+                AlarmListManager.Instance.AddAlarm(alarmList);
+                PostMsg(VpwCellMsg.Error);
+                return false;
+            }
+
+            return ret == RState.End;
+        }
+
+        /// <summary>
+        /// Retry Prepare
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool RetryPrepare(object[] param)
+        {
+            int stepIndex = (int)param[0];
+            bool result = _prepareRoutine.Retry(stepIndex) == RState.Running;
+            return result;
+        }
+        #endregion
+
+        #region Run Recipe
+        /// <summary>
+        /// run recipe
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool RunRecipe(object[] param)
+        {
+            VpwRecipe recipe = param[0] as VpwRecipe;
+            return _recipeRoutine.Start(recipe) == RState.Running;
+        }
+        /// <summary>
+        /// Prepare 监控
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool RunRecipeMonitor(object[] param)
+        {
+            RState ret = _recipeRoutine.Monitor();
+            if (ret == RState.Failed || ret == RState.Timeout)
+            {
+                AlarmList alarmList = new AlarmList(Module.ToString(), ((VPWCellState)fsm.State).ToString(), (int)VpwCellMsg.RunRecipe,
+                        _recipeRoutine.ErrorMsg, _recipeRoutine.ErrorStep, (int)AlarmType.Error);
+                AlarmListManager.Instance.AddAlarm(alarmList);
+                PostMsg(VpwCellMsg.Error);
+                return false;
+            }
+
+            return ret == RState.End;
+        }
+
+        /// <summary>
+        /// Retry RunRecipe
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool RetryRunRecipe(object[] param)
+        {
+            int stepIndex = (int)param[0];
+            bool result = _recipeRoutine.Retry(stepIndex) == RState.Running;
+            return result;
+        }
+        #endregion
+
+        #region Manual Run Recipe
+        /// <summary>
+        /// run recipe
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool ManualRunRecipe(object[] param)
+        {
+            VpwRecipe recipe = param[0] as VpwRecipe;
+            return _manualRecipeRoutine.Start(recipe) == RState.Running;
+        }
+        /// <summary>
+        /// Prepare 监控
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool ManualRunRecipeMonitor(object[] param)
+        {
+            RState ret = _manualRecipeRoutine.Monitor();
+            if (ret == RState.Failed || ret == RState.Timeout)
+            {
+                PostMsg(VpwCellMsg.Error);
+                return false;
+            }
+
+            return ret == RState.End;
+        }
+        #endregion
+
+        #region VpwCell Retry
+        /// <summary>
+        /// VpwCell
+        /// </summary>
+        /// <param name="param"></param>
+        /// <returns></returns>
+        private bool VpwCellRetry(object[] param)
+        {
+            AlarmList alarmList = AlarmListManager.Instance.GetAlarmListByModule(Module.ToString());
+            if (alarmList != null)
+            {
+                CheckToPostMessage<VPWCellState, VpwCellMsg>(eEvent.WARN_VPW, Module.ToString(), alarmList.ModuleCmd,
+                    alarmList.ModuleStep);
+            }
+            return false;
+        }
+        #endregion
+
         public bool Check(int msg, out string reason, params object[] args)
         {
             reason = "";

+ 5 - 1
PunkHPX8_RT/Modules/VpwCell/VpwCellMsg.cs

@@ -13,6 +13,10 @@ namespace PunkHPX8_RT.Modules.VpwCell
         ResumeError,
         Init,
         Abort,
-        EnterIdle
+        EnterIdle,
+        Prepare,
+        Retry,
+        ManualRecipe,
+        RunRecipe
     }
 }

+ 248 - 0
PunkHPX8_RT/Modules/VpwCell/VpwManualPrepareRoutine.cs

@@ -0,0 +1,248 @@
+using Aitex.Core.RT.Device;
+using Aitex.Core.RT.Log;
+using Aitex.Core.RT.Routine;
+using Aitex.Core.RT.SCCore;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.RecipeCenter;
+using MECF.Framework.Common.Routine;
+using MECF.Framework.Common.SubstrateTrackings;
+using PunkHPX8_Core;
+using PunkHPX8_RT.Devices.AXIS;
+using PunkHPX8_RT.Devices.VpwCell;
+using PunkHPX8_RT.Devices.VpwMain;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PunkHPX8_RT.Modules.VpwCell
+{
+    public class VpwManualPrepareRoutine : RoutineBase, IRoutine
+    {
+        private enum PrepareStep
+        {
+            CheckPreCondition,
+            Purge,
+            WaitPurge,
+            RotationPositionOffset,
+            WaitRotation,
+            CloseDrip,
+            Delay,
+            WaitWafer,
+            ChamberUp,
+            CloseDrain,
+            CheckLoopDO,
+            End
+        }
+        #region 内部变量
+        /// <summary>
+        /// recipe
+        /// </summary>
+        private VpwRecipe _recipe;
+        /// <summary>
+        /// 电机
+        /// </summary>
+        private JetAxisBase _rotationAxis;
+        /// <summary>
+        /// 设备
+        /// </summary>
+        private VpwCellDevice _vpwCellDevice;
+        /// <summary>
+        /// Main设备
+        /// </summary>
+        private VpwMainDevice _mainDevice;
+        /// <summary>
+        /// 延迟时间
+        /// </summary>
+        private int _putDownAfterDripClose = 2000;
+        /// <summary>
+        /// 等待Wafer放入时间
+        /// </summary>
+        private int _waitForWaferTime = 300000;
+        #endregion
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="module"></param>
+        public VpwManualPrepareRoutine(string module) : base(module)
+        {
+        }
+        /// <summary>
+        /// 中止
+        /// </summary>
+        public void Abort()
+        {
+            Runner.Stop("Manual abort");
+        }
+        /// <summary>
+        /// 监控
+        /// </summary>
+        /// <returns></returns>
+        public RState Monitor()
+        {
+            Runner.Run(PrepareStep.CheckPreCondition,CheckPreCondition,_delay_1ms)
+                .RunIf(PrepareStep.Purge,_recipe.PurgeEnable,Purge,_delay_1ms)
+                .WaitWithStopConditionIf(PrepareStep.WaitPurge,_recipe.PurgeEnable,CheckPurgeStatus,CheckPurgeStopStatus)
+                .Run(PrepareStep.RotationPositionOffset,RotationPositionOffset,_delay_1ms)
+                .WaitWithStopCondition(PrepareStep.WaitRotation,CheckRotationStatus,CheckRotationStopStatus)
+                .Run(PrepareStep.CloseDrip,()=>_vpwCellDevice.FlowDripOff(),_delay_1ms)
+                .Delay(PrepareStep.Delay,_putDownAfterDripClose)
+                .Wait(PrepareStep.WaitWafer,CheckWaferExsit,_waitForWaferTime)
+                .Run(PrepareStep.ChamberUp,ChamberUp,CheckChamberClosed)
+                .Run(PrepareStep.CloseDrain,_vpwCellDevice.DrainValveOff,_delay_1ms)
+                .Run(PrepareStep.CheckLoopDO,CheckLoopDO,_delay_1ms)
+                .End(PrepareStep.End,NullFun,_delay_1ms);
+            return Runner.Status;
+        }
+        /// <summary>
+        /// Purge routine
+        /// </summary>
+        /// <returns></returns>
+        private bool Purge()
+        {
+            return true;
+        }
+        /// <summary>
+        /// 检验Purge执行是否结束
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckPurgeStatus()
+        {
+            return true;
+        }
+        /// <summary>
+        /// 检验Purger执行是否出现异常
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckPurgeStopStatus()
+        {
+            return false;
+        }
+        /// <summary>
+        /// Position运行至offset
+        /// </summary>
+        /// <returns></returns>
+        private bool RotationPositionOffset()
+        {
+            bool result= _rotationAxis.PositionStation("ChuckPlaceOffset");
+            if (!result)
+            {
+                NotifyError(eEvent.ERR_VPW, "rotation start position to ChuckPlaceOffset failed", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 检验电机是否完成运动
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckRotationStatus()
+        {
+            return _rotationAxis.Status == RState.End;
+        }
+        /// <summary>
+        /// 检验电机运动是否出现异常
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckRotationStopStatus()
+        {
+            bool result= _rotationAxis.Status == RState.Failed;
+            if (result)
+            {
+                NotifyError(eEvent.ERR_VPW, "rotation position to ChuckPlaceOffset failed", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 检验是否存在Wafer
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckWaferExsit()
+        {
+            return WaferManager.Instance.CheckHasWafer(Module, 0);
+        }
+        /// <summary>
+        /// chamber up
+        /// </summary>
+        /// <returns></returns>
+        private bool ChamberUp()
+        {
+            bool result=_mainDevice.ChamberUp();
+            if (!result)
+            {
+                NotifyError(eEvent.ERR_VPW, "chamber up failed", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 检验Chamber是否关闭
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckChamberClosed()
+        {
+            return _mainDevice.CommonData.ChamberClosed && !_mainDevice.CommonData.ChamberOpened;
+        }
+        /// <summary>
+        /// Check LoopDO数值
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckLoopDO()
+        {
+            double loopDoValue = _vpwCellDevice.LoopDOValue;
+            bool result = loopDoValue < _recipe.DiwLoopDoSet;
+            if (!result) 
+            {
+                NotifyError(eEvent.ERR_VPW, $"LoopDO value {loopDoValue} is less than {_recipe.DiwLoopDoSet}", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 启动
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <returns></returns>
+        public RState Start(params object[] objs)
+        {
+            _recipe=(VpwRecipe)objs[0];
+            _rotationAxis = DEVICE.GetDevice<JetAxisBase>($"{Module}.Rotation");
+            _vpwCellDevice = DEVICE.GetDevice<VpwCellDevice>(Module);
+            _mainDevice = DEVICE.GetDevice<VpwMainDevice>(ModuleName.VPWMain1.ToString());
+            _putDownAfterDripClose = SC.GetValue<int>($"{Module}.PutDownAfterDripClose");
+            _waitForWaferTime = SC.GetValue<int>($"{Module}.WaitForWaferTime") * 1000;
+            return Runner.Start(Module, $"{Module} prepare");
+        }
+        /// <summary>
+        /// 检验前置条件
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckPreCondition()
+        {
+            if (!_rotationAxis.IsSwitchOn)
+            {
+                NotifyError(eEvent.ERR_VPW,"rotaion is not switch on",-1);
+                return false;
+            }
+            if (!_rotationAxis.IsHomed)
+            {
+                NotifyError(eEvent.ERR_VPW, "rotaion is not homed", -1);
+                return false;
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// 重试
+        /// </summary>
+        /// <param name="step"></param>
+        public RState Retry(int step)
+        {
+            if (_recipe == null)
+            {
+                NotifyError(eEvent.ERR_RINSE, "recipe is null", -1);
+                return RState.Failed;
+            }
+            List<Enum> preStepIds = new List<Enum>();
+            return Runner.Retry(PrepareStep.CheckPreCondition, preStepIds, Module, "Prepare Retry");
+        }
+    }
+}

+ 47 - 0
PunkHPX8_RT/Modules/VpwCell/VpwManualRecipeRoutine.cs

@@ -0,0 +1,47 @@
+using Aitex.Core.RT.Routine;
+using MECF.Framework.Common.Routine;
+using PunkHPX8_Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PunkHPX8_RT.Modules.VpwCell
+{
+    public class VpwManualRecipeRoutine : RoutineBase, IRoutine
+    {
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="module"></param>
+        public VpwManualRecipeRoutine(string module) : base(module)
+        {
+        }
+
+        /// <summary>
+        /// 中止
+        /// </summary>
+        public void Abort()
+        {
+            Runner.Stop("Manual stop");
+        }
+        /// <summary>
+        /// 监控
+        /// </summary>
+        /// <returns></returns>
+        public RState Monitor()
+        {
+            return Runner.Status;
+        }
+        /// <summary>
+        /// 启动
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <returns></returns>
+        public RState Start(params object[] objs)
+        {
+            return Runner.Start(Module, "start run recipe");
+        }
+    }
+}

+ 240 - 0
PunkHPX8_RT/Modules/VpwCell/VpwPrepareRoutine.cs

@@ -0,0 +1,240 @@
+using Aitex.Core.RT.Device;
+using Aitex.Core.RT.Log;
+using Aitex.Core.RT.Routine;
+using Aitex.Core.RT.SCCore;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.RecipeCenter;
+using MECF.Framework.Common.Routine;
+using MECF.Framework.Common.SubstrateTrackings;
+using PunkHPX8_Core;
+using PunkHPX8_RT.Devices.AXIS;
+using PunkHPX8_RT.Devices.VpwCell;
+using PunkHPX8_RT.Devices.VpwMain;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PunkHPX8_RT.Modules.VpwCell
+{
+    public class VpwPrepareRoutine : RoutineBase, IRoutine
+    {
+        private enum PrepareStep
+        {
+            CheckPreCondition,
+            Purge,
+            WaitPurge,
+            RotationPositionOffset,
+            WaitRotation,
+            CloseDrip,
+            Delay,
+            End
+        }
+        #region 内部变量
+        /// <summary>
+        /// recipe
+        /// </summary>
+        private VpwRecipe _recipe;
+        /// <summary>
+        /// 电机
+        /// </summary>
+        private JetAxisBase _rotationAxis;
+        /// <summary>
+        /// 设备
+        /// </summary>
+        private VpwCellDevice _vpwCellDevice;
+        /// <summary>
+        /// 延迟时间
+        /// </summary>
+        private int _putDownAfterDripClose = 2000;
+        /// <summary>
+        /// 等待Wafer放入时间
+        /// </summary>
+        private int _waitForWaferTime = 300000;
+        /// <summary>
+        /// Main设备
+        /// </summary>
+        private VpwMainDevice _mainDevice;
+        #endregion
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="module"></param>
+        public VpwPrepareRoutine(string module) : base(module)
+        {
+        }
+        /// <summary>
+        /// 中止
+        /// </summary>
+        public void Abort()
+        {
+            Runner.Stop("Manual abort");
+        }
+        /// <summary>
+        /// 监控
+        /// </summary>
+        /// <returns></returns>
+        public RState Monitor()
+        {
+            Runner.Run(PrepareStep.CheckPreCondition,CheckPreCondition,_delay_1ms)
+                .RunIf(PrepareStep.Purge,_recipe.PurgeEnable,Purge,_delay_1ms)
+                .WaitWithStopConditionIf(PrepareStep.WaitPurge,_recipe.PurgeEnable,CheckPurgeStatus,CheckPurgeStopStatus)
+                .Run(PrepareStep.RotationPositionOffset,RotationPositionOffset,_delay_1ms)
+                .WaitWithStopCondition(PrepareStep.WaitRotation,CheckRotationStatus,CheckRotationStopStatus)
+                .Run(PrepareStep.CloseDrip,()=>_vpwCellDevice.FlowDripOff(),_delay_1ms)
+                .Delay(PrepareStep.Delay,_putDownAfterDripClose)
+                .End(PrepareStep.End,NullFun,_delay_1ms);
+            return Runner.Status;
+        }
+        /// <summary>
+        /// Purge routine
+        /// </summary>
+        /// <returns></returns>
+        private bool Purge()
+        {
+            return true;
+        }
+        /// <summary>
+        /// 检验Purge执行是否结束
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckPurgeStatus()
+        {
+            return true;
+        }
+        /// <summary>
+        /// 检验Purger执行是否出现异常
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckPurgeStopStatus()
+        {
+            return false;
+        }
+        /// <summary>
+        /// Position运行至offset
+        /// </summary>
+        /// <returns></returns>
+        private bool RotationPositionOffset()
+        {
+            bool result= _rotationAxis.PositionStation("ChuckPlaceOffset");
+            if (!result)
+            {
+                NotifyError(eEvent.ERR_VPW, "rotation start position to ChuckPlaceOffset failed", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 检验电机是否完成运动
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckRotationStatus()
+        {
+            return _rotationAxis.Status == RState.End;
+        }
+        /// <summary>
+        /// 检验电机运动是否出现异常
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckRotationStopStatus()
+        {
+            bool result= _rotationAxis.Status == RState.Failed;
+            if (result)
+            {
+                NotifyError(eEvent.ERR_VPW, "rotation position to ChuckPlaceOffset failed", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 检验是否存在Wafer
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckWaferExsit()
+        {
+            return WaferManager.Instance.CheckHasWafer(Module, 0);
+        }
+        /// <summary>
+        /// chamber up
+        /// </summary>
+        /// <returns></returns>
+        private bool ChamberUp()
+        {
+            bool result=_mainDevice.ChamberUp();
+            if (!result)
+            {
+                NotifyError(eEvent.ERR_VPW, "chamber up failed", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 检验Chamber是否关闭
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckChamberClosed()
+        {
+            return _mainDevice.CommonData.ChamberClosed && !_mainDevice.CommonData.ChamberOpened;
+        }
+        /// <summary>
+        /// Check LoopDO数值
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckLoopDO()
+        {
+            double loopDoValue = _vpwCellDevice.LoopDOValue;
+            bool result = loopDoValue < _recipe.DiwLoopDoSet;
+            if (!result) 
+            {
+                NotifyError(eEvent.ERR_VPW, $"LoopDO value {loopDoValue} is less than {_recipe.DiwLoopDoSet}", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 启动
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <returns></returns>
+        public RState Start(params object[] objs)
+        {
+            _recipe=(VpwRecipe)objs[0];
+            _rotationAxis = DEVICE.GetDevice<JetAxisBase>($"{Module}.Rotation");
+            _vpwCellDevice = DEVICE.GetDevice<VpwCellDevice>(Module);
+            _mainDevice = DEVICE.GetDevice<VpwMainDevice>(ModuleName.VPWMain1.ToString());
+            _putDownAfterDripClose = SC.GetValue<int>($"{Module}.PutDownAfterDripClose");
+            _waitForWaferTime = SC.GetValue<int>($"{Module}.WaitForWaferTime") * 1000;
+            return Runner.Start(Module, $"{Module} prepare");
+        }
+        /// <summary>
+        /// 检验前置条件
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckPreCondition()
+        {
+            if (!_rotationAxis.IsSwitchOn)
+            {
+                NotifyError(eEvent.ERR_VPW,"rotaion is not switch on",-1);
+                return false;
+            }
+            if (!_rotationAxis.IsHomed)
+            {
+                NotifyError(eEvent.ERR_VPW, "rotaion is not homed", -1);
+                return false;
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// 重试
+        /// </summary>
+        /// <param name="step"></param>
+        public RState Retry(int step)
+        {
+            if (_recipe == null)
+            {
+                NotifyError(eEvent.ERR_RINSE, "recipe is null", -1);
+                return RState.Failed;
+            }
+            List<Enum> preStepIds = new List<Enum>();
+            return Runner.Retry(PrepareStep.CheckPreCondition, preStepIds, Module, "Prepare Retry");
+        }
+    }
+}

+ 132 - 0
PunkHPX8_RT/Modules/VpwCell/VpwRecipeRoutine.cs

@@ -0,0 +1,132 @@
+using Aitex.Core.RT.Device;
+using Aitex.Core.RT.Log;
+using Aitex.Core.RT.Routine;
+using MECF.Framework.Common.Equipment;
+using MECF.Framework.Common.RecipeCenter;
+using MECF.Framework.Common.Routine;
+using PunkHPX8_Core;
+using PunkHPX8_RT.Devices.VpwCell;
+using PunkHPX8_RT.Devices.VpwMain;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PunkHPX8_RT.Modules.VpwCell
+{
+    public class VpwRecipeRoutine : RoutineBase, IRoutine
+    {
+        private enum RecipeStep
+        {
+            ChamberUp,
+            CloseDrain,
+            CheckLoopDO,
+            End
+        }
+        #region 内部变量
+        /// <summary>
+        /// recipe
+        /// </summary>
+        private VpwRecipe _recipe;
+        /// <summary>
+        /// 设备
+        /// </summary>
+        private VpwCellDevice _vpwCellDevice;
+        /// <summary>
+        /// Main设备
+        /// </summary>
+        private VpwMainDevice _mainDevice;
+        #endregion
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="module"></param>
+        public VpwRecipeRoutine(string module) : base(module)
+        {
+        }
+
+        /// <summary>
+        /// 中止
+        /// </summary>
+        public void Abort()
+        {
+            Runner.Stop("Manual stop");
+        }
+        /// <summary>
+        /// 监控
+        /// </summary>
+        /// <returns></returns>
+        public RState Monitor()
+        {
+            Runner.Run(RecipeStep.ChamberUp, ChamberUp, CheckChamberClosed)
+                .Run(RecipeStep.CloseDrain, _vpwCellDevice.DrainValveOff, _delay_1ms)
+                .Run(RecipeStep.CheckLoopDO, CheckLoopDO, _delay_1ms)
+                .End(RecipeStep.End, NullFun, _delay_1ms);
+            return Runner.Status;
+        }
+        /// <summary>
+        /// chamber up
+        /// </summary>
+        /// <returns></returns>
+        private bool ChamberUp()
+        {
+            bool result = _mainDevice.ChamberUp();
+            if (!result)
+            {
+                NotifyError(eEvent.ERR_VPW, "chamber up failed", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 检验Chamber是否关闭
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckChamberClosed()
+        {
+            return _mainDevice.CommonData.ChamberClosed && !_mainDevice.CommonData.ChamberOpened;
+        }
+        /// <summary>
+        /// Check LoopDO数值
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckLoopDO()
+        {
+            double loopDoValue = _vpwCellDevice.LoopDOValue;
+            bool result = loopDoValue < _recipe.DiwLoopDoSet;
+            if (!result)
+            {
+                NotifyError(eEvent.ERR_VPW, $"LoopDO value {loopDoValue} is less than {_recipe.DiwLoopDoSet}", -1);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 启动
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <returns></returns>
+        public RState Start(params object[] objs)
+        {
+            _recipe = objs[0] as VpwRecipe;
+            _vpwCellDevice = DEVICE.GetDevice<VpwCellDevice>(Module);
+            _mainDevice = DEVICE.GetDevice<VpwMainDevice>(ModuleName.VPWMain1.ToString());
+            return Runner.Start(Module, "start run recipe");
+        }
+
+
+        /// <summary>
+        /// 重试
+        /// </summary>
+        /// <param name="step"></param>
+        public RState Retry(int step)
+        {
+            if (_recipe == null)
+            {
+                NotifyError(eEvent.ERR_RINSE, "recipe is null", -1);
+                return RState.Failed;
+            }
+            List<Enum> preStepIds = new List<Enum>();
+            return Runner.Retry(RecipeStep.ChamberUp, preStepIds, Module, "Run recipe Retry");
+        }
+    }
+}

+ 3 - 18
PunkHPX8_RT/Modules/VpwMain/VPWHomeRoutine.cs

@@ -153,6 +153,8 @@ namespace PunkHPX8_RT.Modules.VpwMain
                 .Run(HomeStep.CheckCellFlow,CheckCellFlow,_delay_1ms)
                 .Run(HomeStep.StopRotation,StopRotationAxis,_delay_1ms)
                 .WaitWithStopCondition(HomeStep.CheckRotationStatus,CheckStopPostionEndStatus,CheckStopPostionStopStatus)
+                .Run(HomeStep.LastHomeRotation,HomeAllRotation,_delay_1ms)
+                .WaitWithStopCondition(HomeStep.CheckLastHomeRotation, CheckAllRotationHomeStatus, CheckAllRotationHomeStopStatus)
                 .Run(HomeStep.CheckFlowOk,CheckFlowOk,_delay_1ms)
                 .DelayIf(HomeStep.DegasDelay,_checkFlowOk,_degasEnableDelayTime)
                 .RunIf(HomeStep.OpenDegas,_checkFlowOk,OpenDegasPump,_delay_1ms)
@@ -182,7 +184,6 @@ namespace PunkHPX8_RT.Modules.VpwMain
                 if (!result)
                 {
                     LOG.WriteLog(eEvent.ERR_VPWMAIN, Module, $"{device.Module} open drain valve failed");
-                    CloseCellDrainValve();
                     return false;
                 }
             }
@@ -200,23 +201,12 @@ namespace PunkHPX8_RT.Modules.VpwMain
                 if (!result)
                 {
                     LOG.WriteLog(eEvent.ERR_VPWMAIN, Module, $"{item.Module} drain valve is not opened");
-                    CloseCellDrainValve();
                     return false;
                 }
             }
             return true;
         }
         /// <summary>
-        /// 关闭所有cell的Drain valve
-        /// </summary>
-        private void CloseCellDrainValve()
-        {
-            foreach (var item in _cellLst)
-            {
-                item.DrainValveOff();
-            }
-        }
-        /// <summary>
         /// Home All Rotation
         /// </summary>
         /// <returns></returns>
@@ -227,7 +217,6 @@ namespace PunkHPX8_RT.Modules.VpwMain
                 bool result = item.HomeRotation();
                 if (!result)
                 {
-                    CloseCellDrainValve();
                     return false;
                 }
             }
@@ -269,7 +258,6 @@ namespace PunkHPX8_RT.Modules.VpwMain
                 bool result = item.CheckRotationStopStatus();
                 if (result)
                 {
-                    CloseCellDrainValve();
                     return true;
                 }
             }
@@ -289,7 +277,6 @@ namespace PunkHPX8_RT.Modules.VpwMain
                 if (!result)
                 {
                     StopAllRotation();
-                    CloseCellDrainValve();
                     return false;
                 }
             }
@@ -307,7 +294,6 @@ namespace PunkHPX8_RT.Modules.VpwMain
                 if (!result)
                 {
                     StopAllRotation();
-                    CloseCellDrainValve();
                     return false;
                 }
             }
@@ -413,8 +399,7 @@ namespace PunkHPX8_RT.Modules.VpwMain
             {
                 bool result = item.StopProfilePosition();
                 if (!result)
-                {
-                    CloseCellDrainValve();                    
+                {             
                     return false;
                 }
             }

+ 0 - 2
PunkHPX8_RT/Modules/VpwMain/VpwMainEntity.cs

@@ -158,8 +158,6 @@ namespace PunkHPX8_RT.Modules.VpwMain
             Transition(VPWMainState.Idle, VPWMainMsg.Purge, Purge, VPWMainState.Purgeing);
             Transition(VPWMainState.Purgeing, FSM_MSG.TIMER, PurgeMonitor, VPWMainState.Idle);
 
-
-
             EnumLoop<VPWMainState>.ForEach((item) => { fsm.MapState((int)item, item.ToString()); });
 
             EnumLoop<VPWMainMsg>.ForEach((item) => { fsm.MapMessage((int)item, item.ToString()); });

+ 4 - 0
PunkHPX8_RT/PunkHPX8_RT.csproj

@@ -313,6 +313,10 @@
     <Compile Include="Modules\Dummy\DummyEntity.cs" />
     <Compile Include="Modules\DVIDName.cs" />
     <Compile Include="Modules\VpwCell\VpwCellEntity.cs" />
+    <Compile Include="Modules\VpwCell\VpwPrepareRoutine.cs" />
+    <Compile Include="Modules\VpwCell\VpwManualPrepareRoutine.cs" />
+    <Compile Include="Modules\VpwCell\VpwRecipeRoutine.cs" />
+    <Compile Include="Modules\VpwCell\VpwManualRecipeRoutine.cs" />
     <Compile Include="Modules\VpwMain\VpwPurgeRoutine.cs" />
     <Compile Include="Modules\VpwMain\VpwSimpleHomeRoutine.cs" />
     <Compile Include="Modules\VpwCell\VpwCellMsg.cs" />