Browse Source

1add loop run vpw Recipe
2add diwloopdo

chenzk 18 hours ago
parent
commit
1698f6d95b

+ 1 - 0
Framework/Common/Common.csproj

@@ -224,6 +224,7 @@
     <Compile Include="CommonData\SRD\SRDLotTrackData.cs" />
     <Compile Include="CommonData\Transporter\TransporterData.cs" />
     <Compile Include="CommonData\Vpw\VpwCellCommonData.cs" />
+    <Compile Include="CommonData\Vpw\VpwLotTrackData.cs" />
     <Compile Include="CommonData\Vpw\VpwMainCommonData.cs" />
     <Compile Include="CommonData\WaferHolderMoveItem.cs" />
     <Compile Include="ControlDataContext\UserItem.cs" />

+ 49 - 0
Framework/Common/CommonData/Vpw/VpwLotTrackData.cs

@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MECF.Framework.Common.CommonData.Vpw
+{
+    public class VpwLotTrackData
+    {
+        public DateTime TimeStamp { get; set; }
+        /// <summary>
+        /// 状态机
+        /// </summary>
+        public string StateMachine { get; set; }
+        /// <summary>
+        /// 真空值
+        /// </summary>
+        public double VacuumPressure { get; set; }
+        /// <summary>
+        /// cell流量
+        /// </summary>
+        public double CellFlow { get; set; }
+        /// <summary>
+        /// DO
+        /// </summary>
+        public double DiwLoopDo { get; set; }
+        /// <summary>
+        /// 水压
+        /// </summary>
+        public double WaterPressure { get; set; }
+        /// <summary>
+        /// DripValve
+        /// </summary>
+        public bool DripValve { get; set; }
+        /// <summary>
+        /// SmallValve
+        /// </summary>
+        public bool SmallValve { get; set; }
+        /// <summary>
+        /// LargeValve
+        /// </summary>
+        public bool LargeValve { get; set; }
+        /// <summary>
+        /// chamber closed
+        /// </summary>
+        public bool ChamberClosed { get; set; }
+    }
+}

+ 1 - 0
PunkHPX8_Core/RtState.cs

@@ -143,5 +143,6 @@ namespace PunkHPX8_Core
         WaitForRunRecipe,
         RunReciping,
         ManualReciping,
+        CycleManualProcessing,
     }
 }

+ 14 - 0
PunkHPX8_MainPages/ViewModels/VPWCellViewModel.cs

@@ -117,6 +117,10 @@ namespace PunkHPX8_MainPages.ViewModels
         /// AutoMode页面功能启用
         /// </summary>
         private bool _isAutoEnabled;
+        /// <summary>
+        /// 水阻值
+        /// </summary>
+        private double _diwLoopDo;
         #endregion
 
 
@@ -291,6 +295,14 @@ namespace PunkHPX8_MainPages.ViewModels
             get { return _isAutoEnabled; }
             set { SetProperty(ref _isAutoEnabled, value); }
         }
+        /// <summary>
+        /// 水阻值
+        /// </summary>
+        public double DiwLoopDo
+        {
+            get { return _diwLoopDo; }
+            set { SetProperty(ref _diwLoopDo, value); }
+        }
         #endregion
 
         #endregion
@@ -325,6 +337,7 @@ namespace PunkHPX8_MainPages.ViewModels
             _rtDataKeys.Add($"{Module}.FsmState");
             _rtDataKeys.Add($"VPWMain1.{COMMONDATA}");
             _rtDataKeys.Add($"{Module}.AchievedCycle");
+            _rtDataKeys.Add($"{Module}.LoopDoValue");
 
             if (_timer == null)
             {
@@ -367,6 +380,7 @@ namespace PunkHPX8_MainPages.ViewModels
                         IsAutoEnabled = false;
                     }
                     AchievedRunRecipeCycle = CommonFunction.GetValue<int>(_rtDataValueDic, $"{Module}.AchievedCycle");
+                    DiwLoopDo = CommonFunction.GetValue<double>(_rtDataValueDic, $"{Module}.LoopDoValue");
                 }
             }
         }

+ 1 - 0
PunkHPX8_MainPages/Views/VPWCellView.xaml

@@ -63,6 +63,7 @@
                                            DrainValve="{Binding VpwCellCommonData.DrainValve}"
                                            VacuumValve="{Binding VpwCellCommonData.VacuumValve}"
                                            DIWFlow ="{Binding VpwCellCommonData.DiwFlow}"
+                                           DIWLoopDo="{Binding DiwLoopDo}"
                                    
           
          ></UserControls:VPWCellUIControl>

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

@@ -116,8 +116,8 @@
 		<!-- RESISTIVITY PROBES -->
 		<Item i:type="ResistivityProbe">
 			<Installed>true</Installed>
-			<Count>1</Count>
-			<ResistivityProbeID>2</ResistivityProbeID>
+			<Count>2</Count>
+			<ResistivityProbeID>1</ResistivityProbeID>
 			<SubType>STDThornton</SubType>
 		</Item>
 		<!-- FFU -->

+ 17 - 0
PunkHPX8_RT/Devices/VpwCell/VpwCellDevice.cs

@@ -15,6 +15,7 @@ using MECF.Framework.Common.ToolLayout;
 using MECF.Framework.Common.Utilities;
 using PunkHPX8_RT.Devices.AXIS;
 using PunkHPX8_RT.Devices.Resistivity;
+using PunkHPX8_RT.Devices.VpwMain;
 using PunkHPX8_RT.Modules;
 using PunkHPX8_RT.Modules.VpwMain;
 using System;
@@ -51,6 +52,9 @@ namespace PunkHPX8_RT.Devices.VpwCell
         /// 数据
         /// </summary>
         private VpwCellCommonData _commonData=new VpwCellCommonData();
+        /// Vpw main数据
+        /// </summary>
+        private VpwMainCommonData _mainCommonData = new VpwMainCommonData();
         /// <summary>
         /// 持久性数值
         /// </summary>
@@ -67,6 +71,10 @@ namespace PunkHPX8_RT.Devices.VpwCell
         /// 水阻值
         /// </summary>
         private double _resistivityValue;
+        /// <summary>
+        /// main device
+        /// </summary>
+        private VpwMainDevice _vpwMainDevice;
         #endregion
 
         #region 属性
@@ -75,6 +83,10 @@ namespace PunkHPX8_RT.Devices.VpwCell
         /// </summary>
         public VpwCellCommonData CommonData { get { return _commonData; } }
         /// <summary>
+        /// vpw main数据
+        /// </summary>
+        public VpwMainCommonData MainCommonData { get { return _mainCommonData; } }
+        /// <summary>
         /// 操作模式
         /// </summary>
         public string OperationMode { get { return _vpwCellPersistentValue.OperatingMode; } }
@@ -122,6 +134,11 @@ namespace PunkHPX8_RT.Devices.VpwCell
             {
                 _resistivityController = DEVICE.GetDevice<ResistivityController>(vpwCellItem.ResistivityID);
             }
+            _vpwMainDevice = DEVICE.GetDevice<VpwMainDevice>($"VPWMain1");
+            if(_vpwMainDevice != null)
+            {
+                _mainCommonData = _vpwMainDevice.CommonData;
+            }
         }
         /// <summary>
         /// 初始化Routine

+ 124 - 0
PunkHPX8_RT/Modules/VpwCell/VpwCellEntity.cs

@@ -3,8 +3,10 @@ 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.Util;
 using Aitex.Core.Utilities;
+using CyberX12_RT.Modules.VpwCell;
 using MECF.Framework.Common.Alarm;
 using MECF.Framework.Common.CommonData;
 using MECF.Framework.Common.Equipment;
@@ -16,6 +18,7 @@ using MECF.Framework.Common.Routine;
 using MECF.Framework.Common.SubstrateTrackings;
 using MECF.Framework.Common.ToolLayout;
 using PunkHPX8_Core;
+using PunkHPX8_RT.Devices.LinMot;
 using PunkHPX8_RT.Devices.VpwCell;
 using PunkHPX8_RT.Modules.VpwCell;
 using System;
@@ -72,9 +75,45 @@ namespace PunkHPX8_RT.Modules.VpwMain
         /// </summary>
         private VpwManualRecipeRoutine _manualRecipeRoutine;
         /// <summary>
+        /// 循环routine
+        /// </summary>
+        private VpwCycleManualProcessRecipeRoutine _cycleManualProcessRoutine;
+        /// <summary>
         /// recipe完成次数
         /// </summary>
         private int _achievedCycle;
+        /// <summary>
+        /// Cycle次数
+        /// </summary>
+        private int _cycle = 0;
+        /// <summary>
+        /// 是否Retry
+        /// </summary>
+        private bool _isRetry = false;
+        /// <summary>
+        /// recipe时长
+        /// </summary>
+        private int _recipeTime;
+        /// <summary>
+        /// 当前Recipe
+        /// </summary>
+        private VpwRecipe _currentRecipe;
+        /// <summary>
+        /// run recipe start time
+        /// </summary>
+        private DateTime _runRecipeStartTime;
+        /// <summary>
+        ///  run recipe complete time
+        /// </summary>
+        private DateTime _runRecipeCompleteTime;
+        /// <summary>
+        /// 工艺当前执行小步骤
+        /// </summary>
+        private string _currentStateMachine = "Init";
+        /// <summary>
+        /// 工艺当前执行大步骤
+        /// </summary>
+        private string _currentStatus = "Init";
         #endregion
 
         #region 属性
@@ -132,6 +171,10 @@ namespace PunkHPX8_RT.Modules.VpwMain
         /// 是否为产品模式
         /// </summary>
         public bool IsProduction { get { return _persistentValue != null && _persistentValue.RecipeOperatingMode == PRODUCTION; } }
+        /// <summary>
+        /// recipe时长
+        /// </summary>
+        public int RecipeTime { get { return _recipeTime; } }
         #endregion
 
         /// <summary>
@@ -199,6 +242,9 @@ namespace PunkHPX8_RT.Modules.VpwMain
             //Manual Recipe
             Transition(VPWCellState.Idle, VpwCellMsg.ManualRecipe, ManualRunRecipe, VPWCellState.ManualReciping);
             Transition(VPWCellState.ManualReciping, FSM_MSG.TIMER, ManualRunRecipeMonitor, VPWCellState.Idle);
+            //Cycle Manual Process
+            Transition(VPWCellState.Idle, VpwCellMsg.CycleProcessRecipe, CycleManualProcess, VPWCellState.CycleManualProcessing);
+            Transition(VPWCellState.CycleManualProcessing, FSM_MSG.TIMER, CycleManualMonitor, VPWCellState.Idle);
             //Prepare
             Transition(VPWCellState.Idle, VpwCellMsg.Prepare, Prepare, VPWCellState.Preparing);
             Transition(VPWCellState.Preparing, FSM_MSG.TIMER, PrepareMonitor, VPWCellState.WaitForRunRecipe);
@@ -243,6 +289,7 @@ namespace PunkHPX8_RT.Modules.VpwMain
             _prepareRoutine=new VpwPrepareRoutine(Module.ToString());
             _recipeRoutine=new VpwRecipeRoutine(Module.ToString());
             _manualRecipeRoutine=new VpwManualRecipeRoutine(Module.ToString());
+            _cycleManualProcessRoutine = new VpwCycleManualProcessRecipeRoutine(Module.ToString());
         }
         /// <summary>
         /// 初始化操作
@@ -251,6 +298,22 @@ namespace PunkHPX8_RT.Modules.VpwMain
         {
             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); });
+            OP.Subscribe($"{Module}.CycleManualProcessRecipe", (cmd, args) =>
+            {
+                VpwRecipe recipe = RecipeFileManager.Instance.LoadGenericityRecipe<VpwRecipe>(args[0].ToString());
+                if (recipe == null)
+                {
+                    LOG.WriteLog(eEvent.ERR_VPW, Module.ToString(), $"{args[0]} recipe is null");
+                    return false;
+                }
+                object[] objects = new object[args.Length];
+                objects[0] = recipe;
+                for (int i = 1; i < args.Length; i++)
+                {
+                    objects[i] = args[i];
+                }
+                return CheckToPostMessage<VPWCellState, VpwCellMsg>(eEvent.ERR_PREWET, Module.ToString(), (int)VpwCellMsg.CycleProcessRecipe, objects);
+            });
         }
 
         #region InitializeAll
@@ -412,6 +475,67 @@ namespace PunkHPX8_RT.Modules.VpwMain
         }
         #endregion
 
+        #region cycle manual process
+        private bool CycleManualProcess(object[] param)
+        {
+            VpwRecipe recipe = param[0] as VpwRecipe;
+            _cycle = (int)param[1];
+
+            bool result = _cycleManualProcessRoutine.Start(param) == RState.Running;
+            if (result)
+            {
+                _isRetry = false;
+                if (CellItemRecipeTimeManager.Instance.ContainRecipe(recipe.Ppid))
+                {
+                    _recipeTime = _cycle * CellItemRecipeTimeManager.Instance.GetRecipeTotalTime(recipe.Ppid);
+                }
+                else
+                {
+                    _recipeTime = 0;
+                }
+                _currentRecipe = recipe;
+                _runRecipeStartTime = DateTime.Now;
+            }
+            return result;
+        }
+
+        private bool CycleManualMonitor(object[] param)
+        {
+            RState state = _cycleManualProcessRoutine.Monitor();
+            _currentStatus = _cycleManualProcessRoutine.CurrentStatus;
+            _currentStateMachine = _cycleManualProcessRoutine.CurrentStateMachine;
+            if (state == RState.Failed || state == RState.Timeout)
+            {
+                PostMsg(VpwCellMsg.Error);
+                _currentStateMachine = "Error";
+                _currentStatus = "Error";
+
+                _runRecipeCompleteTime = DateTime.Now;
+                _cycleManualProcessRoutine.VpwLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
+                //导出lotTrack数据
+                VpwLotTrackUtil.ExportVpwLotTrack(Module.ToString(), _cycleManualProcessRoutine.VpwLotTrackDatas,
+                    _cycleManualProcessRoutine.VpwLotTrackHeaderDatas, IsAuto, _isRetry);
+              
+                return false;
+            }
+            _achievedCycle = _cycleManualProcessRoutine.GetAchievedCycle();
+            bool result = state == RState.End;
+            if (result)
+            {
+                double elapsedMilliseconds = _cycleManualProcessRoutine.ElapsedMilliseconds;
+                int recipeTime = (int)Math.Floor(elapsedMilliseconds / _cycle / 1000);
+                CellItemRecipeTimeManager.Instance.UpdateRecipeTime(_currentRecipe.Ppid, recipeTime);
+                _runRecipeCompleteTime = DateTime.Now;
+                _cycleManualProcessRoutine.VpwLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
+                //导出lotTrack数据
+                VpwLotTrackUtil.ExportVpwLotTrack(Module.ToString(), _cycleManualProcessRoutine.VpwLotTrackDatas,
+                    _cycleManualProcessRoutine.VpwLotTrackHeaderDatas, IsAuto, _isRetry);
+            }
+            return result;
+        }
+
+        #endregion
+
         #region VpwCell Retry
         /// <summary>
         /// VpwCell

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

@@ -17,6 +17,7 @@ namespace PunkHPX8_RT.Modules.VpwCell
         Prepare,
         Retry,
         ManualRecipe,
-        RunRecipe
+        RunRecipe,
+        CycleProcessRecipe
     }
 }

+ 210 - 0
PunkHPX8_RT/Modules/VpwCell/VpwCycleManualProcessRecipeRoutine.cs

@@ -0,0 +1,210 @@
+using Aitex.Core.RT.Device;
+using Aitex.Core.RT.Log;
+using Aitex.Core.RT.Routine;
+using Aitex.Core.RT.SCCore;
+using Aitex.Core.Util;
+using MECF.Framework.Common.CommonData;
+using MECF.Framework.Common.CommonData.Prewet;
+using MECF.Framework.Common.CommonData.Vpw;
+using MECF.Framework.Common.RecipeCenter;
+using MECF.Framework.Common.Routine;
+using PunkHPX8_Core;
+using PunkHPX8_RT.Devices.LinMot;
+using PunkHPX8_RT.Devices.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.VpwCell
+{
+    public class VpwCycleManualProcessRecipeRoutine : RoutineBase, IRoutine
+    {
+        private const int LOTTRACK_TIME = 1000;
+        private enum CycleManualRunRecipeStep
+        {
+            LoopStart,
+            LoopRunProcess,
+            LoopWaitRunProcess,
+            LoopDelay,
+            LoopEnd,
+            End
+        }
+        #region 内部变量
+        private VpwManualRecipeRoutine _processRecipeRoutine;
+        private int _cycle = 0;
+        private int _achievedCycle;
+        private object[] param;
+        /// <summary>
+        /// Vpw recipe
+        /// </summary>
+        private VpwRecipe _recipe;
+        /// <summary>
+        /// lock track time
+        /// </summary>
+        private DateTime _lotTackTime = DateTime.Now;
+        /// <summary>
+        /// LotTrack数据
+        /// </summary>
+        private List<VpwLotTrackData> _datas = new List<VpwLotTrackData>();
+        /// <summary>
+        /// LotTrack文件头数据
+        /// </summary>
+        private LotTrackFileHeaderCommonData _header = new LotTrackFileHeaderCommonData();
+        /// <summary>
+        /// 设备对象
+        /// </summary>
+        private VpwCellDevice _vpwCellDevice;
+        #endregion
+
+        #region 属性
+        /// <summary>
+        /// 当前执行到循环哪一步
+        /// </summary>
+        public string CurrentStatus
+        {
+            get { return Runner.CurrentStep.ToString(); }
+        }
+        /// <summary>
+        /// 当前执行到循环哪一步内的哪个动作
+        /// </summary>
+        public string CurrentStateMachine
+        {
+            get { return _processRecipeRoutine.CurrentStep; }
+        }
+        /// <summary>
+        /// LotTrack数据
+        /// </summary>
+        public List<VpwLotTrackData> VpwLotTrackDatas { get { return _datas; } }
+        /// <summary>
+        /// LotTrack文件头数据
+        /// </summary>
+        public LotTrackFileHeaderCommonData VpwLotTrackHeaderDatas { get { return _header; } }
+        #endregion
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="module"></param>
+        public VpwCycleManualProcessRecipeRoutine(string module) : base(module)
+        {
+            _processRecipeRoutine = new VpwManualRecipeRoutine(module);
+        }
+        /// <summary>
+        /// Abort
+        /// </summary>
+        public void Abort()
+        {
+            _processRecipeRoutine.Abort();
+            Runner.Stop("Vpw Cycle ManualRunRecipe Abort");
+        }
+
+        public RState Start(params object[] objs)
+        {
+            _cycle = (int)objs[1];
+            _achievedCycle = 0;
+            param = objs;
+            _vpwCellDevice = DEVICE.GetDevice<VpwCellDevice>(Module);
+            _datas.Clear();
+            _recipe = objs[0] as VpwRecipe;
+            if (_recipe == null)
+            {
+                LOG.WriteLog(eEvent.ERR_VPW, Module, "recipe is null");
+                return RState.Failed;
+            }
+            if (SC.ContainsItem("System.ToolID")) _header.ToolID = SC.GetStringValue("System.ToolID");
+            _header.SoftWareVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
+            _header.Recipe = $"{_recipe.Ppid}.vpw.rcp";
+            
+            //lotTract记录SequenceRecipe
+            //VpwCellEntity vpwCellEntity = Singleton<RouteManager>.Instance.GetModule<VpwCellEntity>(Module);
+            //if (vpwCellEntity.WaferHolderInfo != null && vpwCellEntity.WaferHolderInfo.SequenceRecipe != null && !string.IsNullOrEmpty(vpwCellEntity.WaferHolderInfo.SequenceRecipe.Ppid.ToString()))
+            //{
+            //    _header.SequenceRecipe = vpwCellEntity.WaferHolderInfo.SequenceRecipe.Ppid.ToString();
+            //    _header.ProcessTransferList = new List<string>();
+            //    _header.ProcessTransferList.AddRange(vpwCellEntity.WaferHolderInfo.SchedulerModules);
+            //    vpwCellEntity.WaferHolderInfo.SchedulerModules.Clear();
+            //}
+            
+            _lotTackTime = DateTime.Now;
+            return Runner.Start(Module, "Start Vpw Cycle ManualRunRecipe");
+        }
+        public RState Monitor()
+        {
+            LottrackRecord();
+            Runner.LoopStart(CycleManualRunRecipeStep.LoopStart, "Loop Start ManualRunRecipe", _cycle, NullFun, _delay_1ms)
+                .LoopRun(CycleManualRunRecipeStep.LoopRunProcess, () => _processRecipeRoutine.Start(param) == RState.Running, _delay_1ms)
+                .LoopRunWithStopStatus(CycleManualRunRecipeStep.LoopWaitRunProcess, () => CheckRoutineEndStatus(_processRecipeRoutine), () => CheckRoutineStopStatus(_processRecipeRoutine))
+                .LoopDelay(CycleManualRunRecipeStep.LoopDelay, _delay_1s)
+                .LoopEnd(CycleManualRunRecipeStep.LoopEnd, AchievedCycleCount, _delay_1ms)
+                .End(CycleManualRunRecipeStep.End, NullFun, _delay_1ms);
+            return Runner.Status;
+        }
+        private bool CheckRoutineEndStatus(IRoutine routine)
+        {
+            bool result = routine.Monitor() == RState.End;
+            return result;
+        }
+
+        private bool CheckRoutineStopStatus(IRoutine routine)
+        {
+            RState state = routine.Monitor();
+            if (state == RState.Failed || state == RState.Timeout)
+            {
+                AddLotTrackData();
+                return true;
+            }
+            return false;
+        }
+        /// <summary>
+        /// 统计完成的Cycle次数
+        /// </summary>
+        /// <returns></returns>
+        private bool AchievedCycleCount()
+        {
+            _achievedCycle += 1;
+            return true;
+        }
+        /// <summary>
+        /// 获取已经完成的Cycle次数
+        /// </summary>
+        /// <returns></returns>
+        public int GetAchievedCycle()
+        {
+            return _achievedCycle;
+        }
+        /// <summary>
+        /// 记录Lottrack
+        /// </summary>
+        private void LottrackRecord()
+        {
+            //记录Lottrack
+            if (DateTime.Now.Subtract(_lotTackTime).TotalMilliseconds >= LOTTRACK_TIME)
+            {
+                AddLotTrackData();
+                _lotTackTime = DateTime.Now;
+            }
+        }
+        /// <summary>
+        /// 获取Lot Track数据
+        /// </summary>
+        /// <returns></returns>
+        private void AddLotTrackData()
+        {
+            VpwLotTrackData data = new VpwLotTrackData();
+            data.TimeStamp = DateTime.Now;
+            data.StateMachine = CurrentStateMachine;
+            data.VacuumPressure = _vpwCellDevice.CommonData.VacuumPressure;
+            data.CellFlow = _vpwCellDevice.CommonData.DiwFlow;
+            data.DiwLoopDo = _vpwCellDevice.LoopDOValue;
+            data.WaterPressure = _vpwCellDevice.MainCommonData.DiwPressure;
+            data.DripValve = _vpwCellDevice.CommonData.FlowDrip;
+            data.SmallValve = _vpwCellDevice.CommonData.FlowSmall;
+            data.LargeValve = _vpwCellDevice.CommonData.FlowLarge;
+            data.ChamberClosed = _vpwCellDevice.MainCommonData.ChamberClosed;
+            _datas.Add(data);
+        }
+    }
+}

+ 102 - 0
PunkHPX8_RT/Modules/VpwCell/VpwLotTrackUtil.cs

@@ -0,0 +1,102 @@
+using Aitex.Common.Util;
+using Aitex.Core.Common;
+using Aitex.Core.RT.Log;
+using MECF.Framework.Common.CommonData;
+using MECF.Framework.Common.CommonData.Prewet;
+using MECF.Framework.Common.CommonData.Vpw;
+using MECF.Framework.Common.SubstrateTrackings;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace CyberX12_RT.Modules.VpwCell
+{
+    public class VpwLotTrackUtil
+    {
+        /// <summary>
+        /// CSV文件分隔符
+        /// </summary>
+        private const char CVS_SPLIT_CHAR = ',';
+        /// <summary>
+        /// 导出至csv
+        /// </summary>
+        /// <param name="moduleName"></param>
+        /// <param name="datas"></param>
+
+        public static async void ExportVpwLotTrack(string moduleName, List<VpwLotTrackData> datas, LotTrackFileHeaderCommonData headerData, bool isAuto, bool isRetry)
+        {
+            await Task.Run(() =>
+            {
+                try
+                {
+                    if (datas == null || datas.Count == 0) return;
+
+                    string strPath;
+                    FileInfo fi;
+                    if (isAuto)
+                    {
+                        //Atuo下strPath路径待修正
+                        strPath = $"{moduleName}_M{DateTime.Now.ToString("MM")}_D{DateTime.Now.ToString("dd")}_H{DateTime.Now.ToString("HH")}_M{DateTime.Now.ToString("mm")}_S{DateTime.Now.ToString("ss")}.csv";
+                        fi = new FileInfo(PathManager.GetLotTrackFilePath() + $"Auto\\{DateTime.Now.Year}\\{DateTime.Now.Month}\\" + strPath);
+                    }
+                    else
+                    {
+                        strPath = $"{moduleName}_M{DateTime.Now.ToString("MM")}_D{DateTime.Now.ToString("dd")}_H{DateTime.Now.ToString("HH")}_M{DateTime.Now.ToString("mm")}_S{DateTime.Now.ToString("ss")}.csv";
+                        fi = new FileInfo(PathManager.GetLotTrackFilePath() + $"Manual\\{DateTime.Now.Year}\\{DateTime.Now.Month}\\" + strPath);
+                    }
+                    //目录不存在则创建
+                    if (!fi.Directory.Exists)
+                    {
+                        fi.Directory.Create();
+                    }
+                    FileStream fs = new FileStream(fi.FullName, System.IO.FileMode.Append, System.IO.FileAccess.Write);
+                    StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
+                    if (!isAuto)
+                    {
+                        sw.WriteLine(fi.FullName);
+                        sw.WriteLine($"Date:{DateTime.Now.ToShortDateString()}");
+                        sw.WriteLine($"ToolID:{headerData.ToolID}");
+                        sw.WriteLine($"SW Version:{headerData.SoftWareVersion}");
+                        sw.WriteLine($"Sequence Recipe:{headerData.SequenceRecipe}");
+                    }
+                    if ((!isRetry && isAuto) || !isAuto)
+                    {
+                        if (headerData.ProcessTransferList != null)
+                        {
+                            foreach (var item in headerData.ProcessTransferList)
+                            {
+                                sw.WriteLine(item);
+                            }
+                        }
+                        sw.WriteLine(moduleName);
+                        sw.WriteLine($"Recipe:{headerData.Recipe}");
+                        sw.WriteLine($"SingleWafer:{headerData.IsSingleWafe}");
+                        sw.WriteLine($"ProcessTime:{headerData.ProcessTime}");
+                        sw.Write(CVS_SPLIT_CHAR);
+                        string str = $"TimeStamp{CVS_SPLIT_CHAR}StateMachine{CVS_SPLIT_CHAR}VacuumPressure{CVS_SPLIT_CHAR}CellFlow{CVS_SPLIT_CHAR}DiwLoopDo{CVS_SPLIT_CHAR}" +
+                            $"WaterPressure{CVS_SPLIT_CHAR}DripValve{CVS_SPLIT_CHAR}SmallValve{CVS_SPLIT_CHAR}LargeValve{CVS_SPLIT_CHAR}ChamberClosed";
+                        sw.WriteLine(str);
+                    }
+                        
+                    for (int i = 0; i < datas.Count; i++)
+                    {
+                        VpwLotTrackData data = datas[i];
+                        string tmp = $"{CVS_SPLIT_CHAR}{data.TimeStamp.ToString("HH:mm:ss")}{CVS_SPLIT_CHAR}{data.StateMachine}{CVS_SPLIT_CHAR}{data.VacuumPressure.ToString("F3")}{CVS_SPLIT_CHAR}{data.CellFlow.ToString("F3")}" +
+                            $"{CVS_SPLIT_CHAR}{data.DiwLoopDo}{CVS_SPLIT_CHAR}{data.WaterPressure}{CVS_SPLIT_CHAR}{data.DripValve}{CVS_SPLIT_CHAR}{data.SmallValve.ToString()}{CVS_SPLIT_CHAR}" +
+                            $"{data.LargeValve}{CVS_SPLIT_CHAR}{data.ChamberClosed}";
+                        sw.WriteLine(tmp);
+                    }
+                    sw.WriteLine("");
+                    sw.Close();
+                    fs.Close();
+                }
+                catch
+                {
+                    LOG.WriteLog(eEvent.ERR_PREWET, moduleName, $"{moduleName} LotTrack file writing is failed!");
+                }
+            });
+            
+        }
+    }
+}

+ 2 - 0
PunkHPX8_RT/PunkHPX8_RT.csproj

@@ -312,7 +312,9 @@
     <Compile Include="Devices\Temperature\TemperatureController.cs" />
     <Compile Include="Modules\Dummy\DummyEntity.cs" />
     <Compile Include="Modules\DVIDName.cs" />
+    <Compile Include="Modules\VpwCell\VpwLotTrackUtil.cs" />
     <Compile Include="Modules\VpwCell\VpwCellEntity.cs" />
+    <Compile Include="Modules\VpwCell\VpwCycleManualProcessRecipeRoutine.cs" />
     <Compile Include="Modules\VpwCell\VpwPrepareRoutine.cs" />
     <Compile Include="Modules\VpwCell\VpwManualPrepareRoutine.cs" />
     <Compile Include="Modules\VpwCell\VpwRecipeRoutine.cs" />

+ 4 - 4
PunkHPX8_Simulator/Devices/WagoSocketSimulator.cs

@@ -96,10 +96,10 @@ namespace PunkHPX8_Simulator.Devices
 
         public WagoSocketSimulator(int port):base(port) 
         {
-            SimulatorCommManager.Instance.OnUpdateVariableValueChanged += UpdataDataCausedByOtherModule;
-            MotorSimulator.Instance.OnUpdateWagoDatasChanged += UpdataDataCausedByOtherModule;
-            InitializeData(port);
-            _port = port;
+            //SimulatorCommManager.Instance.OnUpdateVariableValueChanged += UpdataDataCausedByOtherModule;
+            //MotorSimulator.Instance.OnUpdateWagoDatasChanged += UpdataDataCausedByOtherModule;
+            //InitializeData(port);
+            //_port = port;
         }  
         private void UpdataDataCausedByOtherModule(string sourceName,string name, bool value, bool invert)
         {

+ 17 - 17
PunkHPX8_Simulator/Views/WagoView.xaml.cs

@@ -28,7 +28,7 @@ namespace PunkHPX8_Simulator.Views
     {
         public WagoView()
         {
-            InitializeComponent();
+            //InitializeComponent();
             this.Loaded += OnViewLoaded;
         }
 
@@ -230,24 +230,24 @@ namespace PunkHPX8_Simulator.Views
         public WagoViewModel(string str) : base("WagoViewModel")
         {
 
-            DOSelectionChangedCommand = new DelegateCommand<object>(DOSelectionChangedAction);
-            DISelectionChangedCommand = new DelegateCommand<object>(DISelectionChangedAction);
-            AOSelectionChangedCommand = new DelegateCommand<object>(AOSelectionChangedAction);
-            AISelectionChangedCommand = new DelegateCommand<object>(AISelectionChangedAction);
+            //DOSelectionChangedCommand = new DelegateCommand<object>(DOSelectionChangedAction);
+            //DISelectionChangedCommand = new DelegateCommand<object>(DISelectionChangedAction);
+            //AOSelectionChangedCommand = new DelegateCommand<object>(AOSelectionChangedAction);
+            //AISelectionChangedCommand = new DelegateCommand<object>(AISelectionChangedAction);
             
-            SetDOCommand = new DelegateCommand<object>(SetDOAction);
-            SetDICommand = new DelegateCommand<object>(SetDIAction);
-            SetAOCommand = new DelegateCommand<object>(SetAOAction);
-            SetAICommand = new DelegateCommand<object>(SetAIAction);
+            //SetDOCommand = new DelegateCommand<object>(SetDOAction);
+            //SetDICommand = new DelegateCommand<object>(SetDIAction);
+            //SetAOCommand = new DelegateCommand<object>(SetAOAction);
+            //SetAICommand = new DelegateCommand<object>(SetAIAction);
             
-            int.TryParse(str, out int port);
-            _sim = new WagoSocketSimulator(port);
-            Init(_sim);
-            InitData(port);
-            _sim.OnDIVariableValueChanged += DISelectionChangedAction;
-            _sim.OnAIVariableValueChanged += AISelectionChangedAction;
-            _sim.OnAOVariableValueChanged += AOSelectionChangedAction;
-            _sim.OnDOVariableValueChanged += DOSelectionChangedAction;
+            //int.TryParse(str, out int port);
+            //_sim = new WagoSocketSimulator(port);
+            //Init(_sim);
+            //InitData(port);
+            //_sim.OnDIVariableValueChanged += DISelectionChangedAction;
+            //_sim.OnAIVariableValueChanged += AISelectionChangedAction;
+            //_sim.OnAOVariableValueChanged += AOSelectionChangedAction;
+            //_sim.OnDOVariableValueChanged += DOSelectionChangedAction;
         }
 
         private void SetDIAction(object obj)