Browse Source

add vpw purge

chenzk 1 day ago
parent
commit
c87ec4e86a

+ 1 - 0
PunkHPX8_Core/RtState.cs

@@ -127,6 +127,7 @@ namespace PunkHPX8_Core
         Initializing,
         Initialized,
         Idle,
+        Purgeing
     }
     public enum VPWCellState
     {

+ 37 - 1
PunkHPX8_MainPages/ViewModels/VPWMainViewModel.cs

@@ -55,6 +55,10 @@ namespace PunkHPX8_MainPages.ViewModels
         /// 是否是Manual模式
         /// </summary>
         private bool _isManualOperationMode;
+        /// <summary>
+        /// 是否在purge
+        /// </summary>
+        private bool _isPurge;
         #endregion
 
 
@@ -74,6 +78,14 @@ namespace PunkHPX8_MainPages.ViewModels
         /// AutoMode页面功能启用
         /// </summary>
         private bool _isAutoEnabled;
+        /// <summary>
+        /// cell 1 flow
+        /// </summary>
+        private double _vpw1CellFlow;
+        /// <summary>
+        /// cell 2 flow
+        /// </summary>
+        private double _vpw2CellFlow;
         #endregion
 
 
@@ -134,6 +146,10 @@ namespace PunkHPX8_MainPages.ViewModels
         /// 是否是Manual模式
         /// </summary>
         public bool IsManualOperationMode { get { return _isManualOperationMode; } set { SetProperty(ref _isManualOperationMode, value); } }
+        /// <summary>
+        /// 是否在purge
+        /// </summary>
+        public bool IsPurge { get { return _isPurge; } set { SetProperty(ref _isPurge, value); } }
         #endregion
 
 
@@ -159,6 +175,22 @@ namespace PunkHPX8_MainPages.ViewModels
             get { return _isAutoEnabled; }
             set { SetProperty(ref _isAutoEnabled, value); }
         }
+        /// <summary>
+        ///cell 1 flow
+        /// </summary>
+        public double Vpw1CellFlow
+        {
+            get { return _vpw1CellFlow; }
+            set { SetProperty(ref _vpw1CellFlow, value); }
+        }
+        /// <summary>
+        ///cell 2 flow
+        /// </summary>
+        public double Vpw2CellFlow
+        {
+            get { return _vpw2CellFlow; }
+            set { SetProperty(ref _vpw2CellFlow, value); }
+        }
         #endregion
 
         #endregion
@@ -189,7 +221,8 @@ namespace PunkHPX8_MainPages.ViewModels
             _rtDataKeys.Add($"{Module}.{PERSISTENT_VALUE}");
             _rtDataKeys.Add($"{Module}.{COMMONDATA}");
             _rtDataKeys.Add($"{Module}.FsmState");
-
+            _rtDataKeys.Add($"VPW1.DiwCellFlow");
+            _rtDataKeys.Add($"VPW2.DiwCellFlow");
             if (_timer == null)
             {
                 _timer = new DispatcherTimer();
@@ -213,6 +246,9 @@ namespace PunkHPX8_MainPages.ViewModels
                     VpwMainCommonData = CommonFunction.GetValue<VpwMainCommonData>(_rtDataValueDic, $"{Module}.{COMMONDATA}");
                     VpwMainPersistent = CommonFunction.GetValue<VpwMainPersistentValue>(_rtDataValueDic, $"{Module}.{PERSISTENT_VALUE}");
                     Status = CommonFunction.GetValue<string>(_rtDataValueDic, $"{Module}.FsmState");
+                    IsPurge = "Purgeing".Equals(Status) ? true : false;
+                    Vpw1CellFlow = CommonFunction.GetValue<double>(_rtDataValueDic, $"VPW1.DiwCellFlow");
+                    Vpw2CellFlow = CommonFunction.GetValue<double>(_rtDataValueDic, $"VPW2.DiwCellFlow");
                 }
             }
         }

+ 1 - 0
PunkHPX8_MainPages/Views/VPWCellView.xaml

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

+ 3 - 0
PunkHPX8_MainPages/Views/VPWMainView.xaml

@@ -67,6 +67,7 @@
         <Grid Grid.Row="4" Grid.Column="0">
             <UserControls:VPWMainPurgeControl ModuleName="{Binding Module}"
                                               PurgeValveEnable="{Binding VpwMainCommonData.DegasPurge}"
+                                              IsPurge="{Binding IsPurge}"
                 
                 ></UserControls:VPWMainPurgeControl>
         </Grid>
@@ -80,6 +81,8 @@
                                            IsBoosterPumpOpen="{Binding VpwMainCommonData.BoosterPumpEnable}"
                                            IsDegasPumpOpen="{Binding VpwMainCommonData.DegasPumpEnable}"
                                            IsVacuumPumpOpen="{Binding VpwMainCommonData.VacuumPumpEnable}"
+                                           Cell1DIWFlow="{Binding Vpw1CellFlow}"
+                                           Cell2DIWFlow="{Binding Vpw2CellFlow}"
                 
                 ></UserControls:VPWMainUIControl>
         </Grid>

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

@@ -117,6 +117,7 @@ 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);
         }
         /// <summary>
         /// 订阅数据

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

@@ -195,6 +195,7 @@ namespace PunkHPX8_RT.Modules.VpwMain
         /// </summary>
         private void InitializeSVID()
         {
+
             DATA.Subscribe($"{Module}.OperatingMode", () => _persistentValue != null ? _persistentValue.OperatingMode : "None", SubscriptionAttribute.FLAG.IgnoreSaveDB);
 
         }

+ 2 - 1
PunkHPX8_RT/Modules/VpwMain/VPWMsg.cs

@@ -13,6 +13,7 @@ namespace PunkHPX8_RT.Modules.VpwMain
         ResumeError,
         Init,
         Abort,
-        EnterIdle
+        EnterIdle,
+        Purge
     }
 }

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

@@ -51,6 +51,11 @@ namespace PunkHPX8_RT.Modules.VpwMain
         /// Home Routine
         /// </summary>
         private VPWHomeRoutine _homeRoutine;
+        /// <summary>
+        /// purge Routine
+        /// </summary>
+        private VpwPurgeRoutine _vpwPurgeRoutine;
+
         #endregion
 
         #region 属性
@@ -149,6 +154,11 @@ namespace PunkHPX8_RT.Modules.VpwMain
             Transition(VPWMainState.Idle, VPWMainMsg.EnterIdle, NullFunc, VPWMainState.Idle);
             //Enter Init
             Transition(VPWMainState.Idle, VPWMainMsg.Init, NullFunc, VPWMainState.Init);
+            //Purge
+            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()); });
 
@@ -204,6 +214,7 @@ namespace PunkHPX8_RT.Modules.VpwMain
         private void InitializeRoutine()
         {
             _homeRoutine = new VPWHomeRoutine(Module.ToString());
+            _vpwPurgeRoutine = new VpwPurgeRoutine(Module.ToString());
           
         }
         /// <summary>
@@ -212,7 +223,43 @@ namespace PunkHPX8_RT.Modules.VpwMain
         private void InitializeOperation()
         {
             OP.Subscribe($"{Module}.InitializeAll", (cmd, args) => { return CheckToPostMessage<VPWMainState, VPWMainMsg>(eEvent.ERR_VPWMAIN, Module.ToString(), (int)VPWMainMsg.Initialize); });
+            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)
+        {
+            if (_vpwCellDevices == null || _vpwCellDevices.Count == 0)
+            {
+                LOG.WriteLog(eEvent.ERR_VPWMAIN, Module.ToString(), "cell device is empty");
+                return false;
+            }
+            foreach (var device in _vpwCellDevices)
+            {
+                VpwCellEntity vpwCellEntity = Singleton<RouteManager>.Instance.GetModule<VpwCellEntity>(device.Module);
+                if (vpwCellEntity.IsBusy)
+                {
+                    LOG.WriteLog(eEvent.ERR_VPWMAIN, Module.ToString(), $"cell device {device.Module} is busy,cannot purge");
+                    return false;
+                }
+            }
+            return _vpwPurgeRoutine.Start(_vpwCellDevices) == RState.Running;
+        }
+
+        private bool PurgeMonitor(object[] param)
+        {
+            RState ret = _vpwPurgeRoutine.Monitor();
+            if (ret == RState.Failed || ret == RState.Timeout)
+            {
+                PostMsg(VPWMainMsg.Error);
+                return false;
+            }
+            return ret == RState.End;
         }
+        #endregion
+
 
         #region InitializeAll
         /// <summary>

+ 554 - 0
PunkHPX8_RT/Modules/VpwMain/VpwPurgeRoutine.cs

@@ -0,0 +1,554 @@
+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.Equipment;
+using MECF.Framework.Common.Routine;
+using PunkHPX8_Core;
+using PunkHPX8_RT.Devices.VpwCell;
+using PunkHPX8_RT.Devices.VpwMain;
+using PunkHPX8_RT.Modules.VpwCell;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PunkHPX8_RT.Modules.VpwMain
+{
+    public class VpwPurgeRoutine : RoutineBase, IRoutine
+    {
+        private enum PurgeStep
+        {
+            ChameberUp,
+            SetRotationSpeed,
+            StartRotation,
+            CheckRotationRunning,
+            CloseDiwDegas,
+            N2PurgeDelay,
+            CloseN2Purge,
+            OpenDiwDegas,
+            FlowDelay,
+            CheckFlow,
+            CheckCellFlow,
+            StopRotation,
+            CheckStopStatus,
+            LastHomeRotation,
+            CheckLastHomeRotation,
+            CheckFlowOk,
+            ChamberDown,
+            LastCheckStatus,
+            End
+        }
+
+        #region 常量 
+        /// <summary>
+        /// 增加额外一分钟
+        /// </summary>
+        private const int PLUS_TIME = 60000;
+        #endregion
+
+
+        #region 内部变量
+        /// <summary>
+        /// Cell device集合
+        /// </summary>
+        private List<VpwCellDevice> _vpwCellDevices = new List<VpwCellDevice>();
+        /// <summary>
+        /// Main Device
+        /// </summary>
+        private VpwMainDevice _mainDevice;
+        /// <summary>
+        /// cell集合
+        /// </summary>
+        private List<VpwCellDevice> _cellLst = new List<VpwCellDevice>();
+        /// <summary>
+        /// N2 Purge时长
+        /// </summary>
+        private int _n2PurgeTime = 15000;
+        /// <summary>
+        /// Flow holder off time
+        /// </summary>
+        private int _flowFaultHolderoffTime = 15000;
+        /// <summary>
+        /// Degas delay时间
+        /// </summary>
+        private int _degasEnableDelayTime = 2000;
+        /// <summary>
+        /// 旋转速度
+        /// </summary>
+        private int _rotationSpeed = 0;
+        /// <summary>
+        /// 总流量起始流量数值
+        /// </summary>
+        private double _totalFlowStartLimit = 2.0;
+        /// <summary>
+        /// Cell起始流量数值
+        /// </summary>
+        private double _cellFlowStartLimit = 2.0;
+        /// <summary>
+        /// total flow合格
+        /// </summary>
+        private bool _totalFlowOk = false;
+        /// <summary>
+        /// cell flow合格集合
+        /// </summary>
+        private Dictionary<string, bool> _cellFlowOk = new Dictionary<string, bool>();
+        /// <summary>
+        /// 检验流量是否ok
+        /// </summary>
+        private bool _checkFlowOk = false;
+        /// <summary>
+        /// 总流量
+        /// </summary>
+        private double _totalFlow = 0;
+        /// <summary>
+        /// Cell注意集合
+        /// </summary>
+        private Dictionary<string, double> _cellFlows = new Dictionary<string, double>();
+        #endregion
+
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="module"></param>
+        /// <param name="device"></param>
+        public VpwPurgeRoutine(string module) : base(module)
+        {
+
+        }
+
+        /// <summary>
+        /// 中止
+        /// </summary>
+        public void Abort()
+        {
+            Runner.Stop("Purge abort");
+        }
+        /// <summary>
+        /// 监控
+        /// </summary>
+        /// <returns></returns>
+        public RState Monitor()
+        {
+            Runner.Run(PurgeStep.ChameberUp, _mainDevice.ChamberUp, CheckChamberClosed, _delay_1s)
+                .Run(PurgeStep.SetRotationSpeed, SetRotationSpeed, _delay_1s)
+                .Run(PurgeStep.StartRotation, StartRotation, _delay_1ms)
+                .Wait(PurgeStep.CheckRotationRunning, CheckRotationRunningStatus, 500)
+                .Run(PurgeStep.CloseDiwDegas, CloseDiwDegas)
+                .Delay(PurgeStep.N2PurgeDelay, _n2PurgeTime)
+                .Run(PurgeStep.CloseN2Purge, _mainDevice.N2PurgeValveOff, _delay_1ms)
+                .Run(PurgeStep.OpenDiwDegas, OpenDiwDegas, _delay_1ms)
+                .Delay(PurgeStep.FlowDelay, _flowFaultHolderoffTime)
+                .Run(PurgeStep.CheckFlow, CheckTotalFlow, _delay_1ms)
+                .Run(PurgeStep.CheckCellFlow, CheckCellFlow, _delay_1ms)
+                .Run(PurgeStep.StopRotation, StopRotationAxis, _delay_1ms)
+                .WaitWithStopCondition(PurgeStep.CheckStopStatus, CheckStopPostionEndStatus, CheckStopPostionStopStatus)
+                .Run(PurgeStep.LastHomeRotation, HomeAllRotation, _delay_1ms)
+                .WaitWithStopCondition(PurgeStep.CheckLastHomeRotation, CheckAllRotationHomeStatus, CheckAllRotationHomeStopStatus)
+                .Run(PurgeStep.CheckFlowOk, CheckFlowOk, _delay_1ms)
+                .RunIf(PurgeStep.ChamberDown, _checkFlowOk, () => { return _mainDevice.ChamberDown(); },
+                    () => { return !_mainDevice.CommonData.ChamberClosed && _mainDevice.CommonData.ChamberOpened; })
+                .Run(PurgeStep.LastCheckStatus, LastCheckResult, _delay_1ms)
+                .End(PurgeStep.End, NullFun, _delay_1ms);
+            return Runner.Status;
+        }
+        /// <summary>
+        /// 检验Chamber关闭
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckChamberClosed()
+        {
+            return _mainDevice.CommonData.ChamberClosed && !_mainDevice.CommonData.ChamberOpened;
+        }
+        private bool SetRotationSpeed()
+        {
+            bool result = true;
+            foreach (var item in _cellLst)
+            {
+                result &= item.SetRotationSpeed(_rotationSpeed);
+            }
+            return result;
+        }
+        /// <summary>
+        /// 打开所有cell valve
+        /// </summary>
+        /// <returns></returns>
+        private bool OpenCellDrainValve()
+        {
+            foreach (var device in _cellLst)
+            {
+                bool result = device.DrainValveOn();
+                if (!result)
+                {
+                    LOG.WriteLog(eEvent.ERR_VPWMAIN, Module, $"{device.Module} open drain valve failed");
+                    CloseCellDrainValve();
+                    return false;
+                }
+            }
+            return true;
+        }
+        /// <summary>
+        /// 检验Cell Drain状态
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckCellDrainValveStatus()
+        {
+            foreach (var item in _cellLst)
+            {
+                bool result = item.CommonData.DrainValve;
+                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>
+        private bool HomeAllRotation()
+        {
+            foreach (var item in _cellLst)
+            {
+                bool result = item.HomeRotation();
+                if (!result)
+                {
+                    CloseCellDrainValve();
+                    return false;
+                }
+            }
+            return true;
+        }
+        /// <summary>
+        /// 检验所有Rotation Home成功
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckAllRotationHomeStatus()
+        {
+            int count = 0;
+            foreach (var item in _cellLst)
+            {
+                bool result = item.CheckHomeEndStatus();
+                if (result)
+                {
+                    count++;
+                }
+            }
+            bool success = count == _cellLst.Count;
+            if (success)
+            {
+                foreach (var item in _cellLst)
+                {
+                    item.SetRotationSpeed(_rotationSpeed);
+                }
+            }
+            return success;
+        }
+        /// <summary>
+        /// rotation电机 home是否停止
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckAllRotationHomeStopStatus()
+        {
+            foreach (var item in _cellLst)
+            {
+                bool result = item.CheckRotationStopStatus();
+                if (result)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+        /// <summary>
+        /// 启动rotation
+        /// </summary>
+        /// <returns></returns>
+        private bool StartRotation()
+        {
+            int totalTime = (_n2PurgeTime + _flowFaultHolderoffTime+ PLUS_TIME) / 1000;
+            int targetPsition = _rotationSpeed * totalTime;
+            foreach (var item in _cellLst)
+            {
+                bool result = item.RotationProfilePosition(targetPsition);
+                if (!result)
+                {
+                    StopAllRotation();
+                    return false;
+                }
+            }
+            return true;
+        }
+        /// <summary>
+        /// 检验Rotation是否运动
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckRotationRunningStatus()
+        {
+            foreach (var item in _cellLst)
+            {
+                bool result = item.CheckRotationRunning();
+                if (!result)
+                {
+                    StopAllRotation();
+                    return false;
+                }
+            }
+            return true;
+        }
+        /// <summary>
+        /// 停止所有rotation电机
+        /// </summary>
+        private void StopAllRotation()
+        {
+            foreach (var item in _cellLst)
+            {
+                item.StopProfilePosition();
+            }
+        }
+        /// <summary>
+        /// 关闭DiwDegas等
+        /// </summary>
+        /// <returns></returns>
+        private bool CloseDiwDegas()
+        {
+            int count = 0;
+            count += _mainDevice.DiwDegasValveOff() ? 1 : 0;
+            count += _mainDevice.N2PurgeValveOn() ? 1 : 0;
+            foreach (var item in _cellLst)
+            {
+                count += item.FlowDripOn() ? 1 : 0;
+                count += item.FlowSmallOn() ? 1 : 0;
+                count += item.FlowLargeOn() ? 1 : 0;
+            }
+
+            return count == _cellLst.Count * 3 + 2;
+        }
+        /// <summary>
+        /// 打开DiwDegas
+        /// </summary>
+        /// <returns></returns>
+        private bool OpenDiwDegas()
+        {
+            return _mainDevice.DiwDegasValveOff();
+        }
+        /// <summary>
+        /// 检验流量
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckTotalFlow()
+        {
+            double totalFlow = _mainDevice.CommonData.DiwTotalFlow;
+            if (totalFlow < _totalFlowStartLimit)
+            {
+                _totalFlowOk = false;
+            }
+            else
+            {
+                _totalFlowOk = true;
+            }
+            _totalFlow = totalFlow;
+            return true;
+        }
+        /// <summary>
+        /// 检验CellFlow
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckCellFlow()
+        {
+            foreach (var item in _cellLst)
+            {
+                double cellFlow = item.CommonData.DiwFlow;
+                if (cellFlow < _cellFlowStartLimit)
+                {
+                    _cellFlowOk[item.Module] = false;
+                }
+                else
+                {
+                    _cellFlowOk[item.Module] = true;
+                    item.FlowSmallOff();
+                    item.FlowLargeOff();
+                }
+                _cellFlows[item.Module] = cellFlow;
+            }
+
+            return true;
+        }
+        /// <summary>
+        /// 停止rotation
+        /// </summary>
+        /// <returns></returns>
+        public bool StopRotationAxis()
+        {
+            foreach (var item in _cellLst)
+            {
+                bool result = item.StopProfilePosition();
+                if (!result)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+        /// <summary>
+        /// 检验停止是否完成
+        /// </summary>
+        /// <returns></returns>
+        public bool CheckStopPostionEndStatus()
+        {
+            foreach (var item in _cellLst)
+            {
+                bool result = item.CheckRotationEndStatus();
+                if (!result)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// 检验停止失败状态
+        /// </summary>
+        /// <returns></returns>
+        public bool CheckStopPostionStopStatus()
+        {
+            foreach (var item in _cellLst)
+            {
+                bool result = item.CheckRotationStopStatus();
+                if (result)
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+        /// <summary>
+        /// 检验流量是否ok
+        /// </summary>
+        /// <returns></returns>
+        private bool CheckFlowOk()
+        {
+            if (!_totalFlowOk)
+            {
+                _checkFlowOk = false;
+                return true;
+            }
+            foreach (var item in _cellLst)
+            {
+                if (!_cellFlowOk[item.Module])
+                {
+                    _checkFlowOk = false;
+                    return true;
+                }
+            }
+            _checkFlowOk = true;
+            return true;
+        }
+        /// <summary>
+        /// 最后确认结果
+        /// </summary>
+        /// <returns></returns>
+        private bool LastCheckResult()
+        {
+            AllCellPostMsg();
+            if (_totalFlowOk)
+            {
+                return true;
+            }
+            else
+            {
+                LOG.WriteLog(eEvent.ERR_VPWMAIN, Module, $"total flow {_totalFlow} is less than {_totalFlowStartLimit}");
+                return false;
+            }
+        }
+        /// <summary>
+        /// 所有cell推送消息
+        /// </summary>
+        private void AllCellPostMsg()
+        {
+            foreach (var item in _cellLst)
+            {
+                VpwCellEntity vpwCellEntity = Singleton<RouteManager>.Instance.GetModule<VpwCellEntity>(item.Module);
+                if (!_cellFlowOk[item.Module])
+                {
+                    vpwCellEntity.PostMsg((int)VpwCellMsg.Error);
+                    LOG.WriteLog(eEvent.ERR_VPW, item.Module, $"cell flow {_cellFlows[item.Module]} is less than {_cellFlowStartLimit}");
+                }
+            }
+        }
+
+        /// <summary>
+        /// 检验Rotation电机是否上电
+        /// </summary>
+        /// <param name="device"></param>
+        /// <returns></returns>
+        private bool CheckRotationSwitchOn(VpwCellDevice device)
+        {
+            if (!device.CheckRotationSwitchOn())
+            {
+                LOG.WriteLog(eEvent.ERR_VPWMAIN, Module, $"{device.Module} rotation is not switch on");
+                return false;
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// 启动
+        /// </summary>
+        /// <param name="objs"></param>
+        /// <returns></returns>
+        public RState Start(params object[] objs)
+        {
+            List<VpwCellDevice> lstDevice = (List<VpwCellDevice>)objs[0];
+            _vpwCellDevices.Clear();
+            _cellFlows.Clear();
+            _cellLst.Clear();
+            _cellFlowOk.Clear();
+            _totalFlowOk = false;
+            _checkFlowOk = false;
+            _totalFlow = 0;
+            for (int i = 0; i < lstDevice.Count; i++)
+            {
+                _vpwCellDevices.Add(lstDevice[i]);
+                VpwCellEntity vpwCellEntity = Singleton<RouteManager>.Instance.GetModule<VpwCellEntity>(lstDevice[i].Module);
+                if (vpwCellEntity.IsAuto || vpwCellEntity.IsManual)
+                {
+                    _cellLst.Add(lstDevice[i]);
+                    if (!CheckRotationSwitchOn(lstDevice[i]))
+                    {
+                        return RState.Failed;
+                    }
+                    _cellFlowOk[lstDevice[i].Module] = false;
+                }
+            }
+            _mainDevice = DEVICE.GetDevice<VpwMainDevice>(Module.ToString());
+            _n2PurgeTime = SC.GetValue<int>("VPWMain.Plumbing.N2PurgeTime");
+            _flowFaultHolderoffTime = SC.GetValue<int>("VPWMain.Plumbing.FlowFaultHoldoffTime");
+            double purgeMotorSpeed = SC.GetValue<double>("VPWMain.Plumbing.PurgeMotorSpeed");
+            _rotationSpeed = (int)(Math.Round(purgeMotorSpeed * 360 / 60, 0));
+            _totalFlowStartLimit = SC.GetValue<double>("VPWMain.Plumbing.TotalFlowStartLowLimit");
+            _cellFlowStartLimit = SC.GetValue<double>("VPWMain.Plumbing.CellFlowStartLowLimit");
+            _degasEnableDelayTime = SC.GetValue<int>("VPWMain.Plumbing.DegasEnableDelayTime");
+            return Runner.Start(Module, "VPW Purge");
+        }
+ 
+
+    }
+}

+ 1 - 0
PunkHPX8_RT/PunkHPX8_RT.csproj

@@ -313,6 +313,7 @@
     <Compile Include="Modules\Dummy\DummyEntity.cs" />
     <Compile Include="Modules\DVIDName.cs" />
     <Compile Include="Modules\VpwCell\VpwCellEntity.cs" />
+    <Compile Include="Modules\VpwMain\VpwPurgeRoutine.cs" />
     <Compile Include="Modules\VpwMain\VpwSimpleHomeRoutine.cs" />
     <Compile Include="Modules\VpwCell\VpwCellMsg.cs" />
     <Compile Include="Modules\VpwMain\VPWHomeRoutine.cs" />

+ 20 - 0
PunkHPX8_Themes/UserControls/VPWCellUIControl.xaml

@@ -158,6 +158,26 @@
             </Border>
         </Grid>
 
+        <Grid Height="50" Width="120" Canvas.Left="220" Canvas.Top="14"  >
+            <Grid.RowDefinitions>
+                <RowDefinition Height="20"></RowDefinition>
+                <RowDefinition Height="30"></RowDefinition>
+            </Grid.RowDefinitions>
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="60"></ColumnDefinition>
+                <ColumnDefinition Width="60"></ColumnDefinition>
+            </Grid.ColumnDefinitions>
+            <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Margin="0,0,10,0">
+                <Label Content="Diw Cell Flow" FontSize="10" FontWeight="Bold" VerticalContentAlignment="Center" HorizontalContentAlignment="Left" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0"/>
+            </Grid>
+            <Border Grid.Row="1" Grid.Column="0"  Margin="5,5,5,5" Background="Black" Width="50" VerticalAlignment="Center" HorizontalAlignment="Right">
+                <TextBlock  Text="{Binding ElementName=self,Path=DIWFlow}" Foreground="Lime" FontSize="16" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Left"/>
+            </Border>
+            <Border Grid.Row="1" Grid.Column="1"  Margin="0,5,0,5 " Background="Black" Height="22" Width="40" VerticalAlignment="Center" HorizontalAlignment="Left">
+                <TextBlock  Text="L/min" Foreground="Lime" FontSize="12" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+            </Border>
+        </Grid>
+
         <Grid Height="50" Width="120" Canvas.Left="76" Canvas.Top="377"  >
             <Grid.RowDefinitions>
                 <RowDefinition Height="20"></RowDefinition>

+ 17 - 0
PunkHPX8_Themes/UserControls/VPWCellUIControl.xaml.cs

@@ -164,6 +164,23 @@ namespace PunkHPX8_Themes.UserControls
             }
         }
 
+        public static readonly DependencyProperty DIWFlowProperty = DependencyProperty.Register(
+       "DIWFlow", typeof(double), typeof(VPWCellUIControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
+        /// <summary>
+        /// DIWFlow
+        /// </summary>
+        public double DIWFlow
+        {
+            get
+            {
+                return (double)this.GetValue(DIWFlowProperty);
+            }
+            set
+            {
+                this.SetValue(DIWFlowProperty, value);
+            }
+        }
+
         public static readonly DependencyProperty CellVacuumProperty = DependencyProperty.Register(
         "CellVacuum", typeof(double), typeof(VPWCellUIControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
         /// <summary>

+ 41 - 0
PunkHPX8_Themes/UserControls/VPWMainUIControl.xaml

@@ -189,5 +189,46 @@
             <Polygon Width="10" Points="0,10 20,0 20,20" Fill="Black" StrokeThickness="1" HorizontalAlignment="Left" VerticalAlignment="Center"></Polygon>
             <Polygon Points="0,0 30,0 30,4 0,4" Fill="Black" StrokeThickness="1" Canvas.Left="10" Canvas.Top="8" HorizontalAlignment="Left" VerticalAlignment="Center"></Polygon>
         </Canvas>
+
+        <Grid Height="50" Width="120" Canvas.Left="229" Canvas.Top="265" HorizontalAlignment="Left" VerticalAlignment="Top"  >
+            <Grid.RowDefinitions>
+                <RowDefinition Height="20"></RowDefinition>
+                <RowDefinition Height="30"></RowDefinition>
+            </Grid.RowDefinitions>
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="60"></ColumnDefinition>
+                <ColumnDefinition Width="60"></ColumnDefinition>
+            </Grid.ColumnDefinitions>
+            <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Margin="0,0,10,0">
+                <Label Content="Cell1 Flow" FontSize="10" FontWeight="Bold" VerticalContentAlignment="Center" HorizontalContentAlignment="Left" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0"/>
+            </Grid>
+            <Border Grid.Row="1" Grid.Column="0"  Margin="5,5,5,5" Background="Black" Width="50" VerticalAlignment="Center" HorizontalAlignment="Right">
+                <TextBlock  Text="{Binding ElementName=self,Path=Cell1DIWFlow}" Foreground="Lime" FontSize="16" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Left"/>
+            </Border>
+            <Border Grid.Row="1" Grid.Column="1"  Margin="0,5,0,5 " Background="Black" Height="22" Width="40" VerticalAlignment="Center" HorizontalAlignment="Left">
+                <TextBlock  Text="L/min" Foreground="Lime" FontSize="12" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+            </Border>
+        </Grid>
+
+        <Grid Height="50" Width="120" Canvas.Left="529" Canvas.Top="265" HorizontalAlignment="Left" VerticalAlignment="Top"  >
+            <Grid.RowDefinitions>
+                <RowDefinition Height="20"></RowDefinition>
+                <RowDefinition Height="30"></RowDefinition>
+            </Grid.RowDefinitions>
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="60"></ColumnDefinition>
+                <ColumnDefinition Width="60"></ColumnDefinition>
+            </Grid.ColumnDefinitions>
+            <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Margin="0,0,10,0">
+                <Label Content="Cell2 Flow" FontSize="10" FontWeight="Bold" VerticalContentAlignment="Center" HorizontalContentAlignment="Left" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0"/>
+            </Grid>
+            <Border Grid.Row="1" Grid.Column="0"  Margin="5,5,5,5" Background="Black" Width="50" VerticalAlignment="Center" HorizontalAlignment="Right">
+                <TextBlock  Text="{Binding ElementName=self,Path=Cell2DIWFlow}" Foreground="Lime" FontSize="16" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Left"/>
+            </Border>
+            <Border Grid.Row="1" Grid.Column="1"  Margin="0,5,0,5 " Background="Black" Height="22" Width="40" VerticalAlignment="Center" HorizontalAlignment="Left">
+                <TextBlock  Text="L/min" Foreground="Lime" FontSize="12" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+            </Border>
+        </Grid>
+
     </Canvas>
 </UserControl>

+ 34 - 0
PunkHPX8_Themes/UserControls/VPWMainUIControl.xaml.cs

@@ -197,6 +197,40 @@ namespace PunkHPX8_Themes.UserControls
             }
         }
 
+        public static readonly DependencyProperty Cell1DIWFlowProperty = DependencyProperty.Register(
+ "Cell1DIWFlow", typeof(double), typeof(VPWMainUIControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
+        /// <summary>
+        /// Cell1DIWFlow
+        /// </summary>
+        public double Cell1DIWFlow
+        {
+            get
+            {
+                return (double)this.GetValue(Cell1DIWFlowProperty);
+            }
+            set
+            {
+                this.SetValue(Cell1DIWFlowProperty, value);
+            }
+        }
+
+        public static readonly DependencyProperty Cell2DIWFlowProperty = DependencyProperty.Register(
+"Cell2DIWFlow", typeof(double), typeof(VPWMainUIControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
+        /// <summary>
+        /// Cell2DIWFlow
+        /// </summary>
+        public double Cell2DIWFlow
+        {
+            get
+            {
+                return (double)this.GetValue(Cell2DIWFlowProperty);
+            }
+            set
+            {
+                this.SetValue(Cell2DIWFlowProperty, value);
+            }
+        }
+
         private void OpenDIWProcessValve_Click(object sender, RoutedEventArgs e)
         {
             InvokeClient.Instance.Service.DoOperation($"{ModuleName}.DiwProcessOn");

+ 50 - 2
PunkHPX8_Twincate/PunkHPX8/PlcTest/POUs/MAIN.TcPOU

@@ -200,8 +200,10 @@ END_IF
 
 IF VPW_DO_16CHANNEL_EL2809_101_7=TRUE THEN
 	VPW_DI_16CHANNEL_EL1819_N100_9:=FALSE;
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_1:=10000;
 ELSE IF VPW_DO_16CHANNEL_EL2809_101_7=FALSE THEN
 	VPW_DI_16CHANNEL_EL1819_N100_9:=TRUE;
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_1:=0;
 END_IF
 END_IF
 
@@ -214,7 +216,38 @@ ELSE
 	VPW_DI_16CHANNEL_EL1819_N100_2:=TRUE;
 	
 END_IF
-]]></ST>
+
+IF VPW_PNEU_SMC_EX260_BYTE0.2=TRUE THEN
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_2:=6000;
+END_IF
+
+IF VPW_PNEU_SMC_EX260_BYTE0.3=TRUE THEN
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_2:=16000;
+END_IF
+
+IF VPW_PNEU_SMC_EX260_BYTE0.4=TRUE THEN
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_2:=22000;
+END_IF
+
+IF VPW_PNEU_SMC_EX260_BYTE0.4=FALSE AND VPW_PNEU_SMC_EX260_BYTE0.3=FALSE AND VPW_PNEU_SMC_EX260_BYTE0.2=FALSE THEN
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_2:=0;
+END_IF
+
+IF VPW_PNEU_SMC_EX260_BYTE0.5=TRUE THEN
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_3:=6000;
+END_IF
+
+IF VPW_PNEU_SMC_EX260_BYTE0.6=TRUE THEN
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_3:=16000;
+END_IF
+
+IF VPW_PNEU_SMC_EX260_BYTE0.7=TRUE THEN
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_3:=22000;
+END_IF
+
+IF VPW_PNEU_SMC_EX260_BYTE0.5=FALSE AND VPW_PNEU_SMC_EX260_BYTE0.6=FALSE AND VPW_PNEU_SMC_EX260_BYTE0.7=FALSE THEN
+	VPW_AI_8CHANNEL_4_20mA_EL3058_N102_3:=0;
+END_IF]]></ST>
     </Implementation>
     <LineIds Name="MAIN">
       <LineId Id="52" Count="5" />
@@ -227,8 +260,23 @@ END_IF
       <LineId Id="18" Count="0" />
       <LineId Id="135" Count="42" />
       <LineId Id="134" Count="0" />
-      <LineId Id="287" Count="16" />
+      <LineId Id="287" Count="2" />
+      <LineId Id="412" Count="0" />
+      <LineId Id="290" Count="1" />
+      <LineId Id="413" Count="0" />
+      <LineId Id="292" Count="11" />
+      <LineId Id="415" Count="0" />
+      <LineId Id="414" Count="0" />
+      <LineId Id="416" Count="0" />
+      <LineId Id="425" Count="0" />
+      <LineId Id="427" Count="2" />
       <LineId Id="286" Count="0" />
+      <LineId Id="433" Count="2" />
+      <LineId Id="432" Count="0" />
+      <LineId Id="439" Count="2" />
+      <LineId Id="438" Count="0" />
+      <LineId Id="443" Count="14" />
+      <LineId Id="442" Count="0" />
     </LineIds>
   </POU>
 </TcPlcObject>