Browse Source

revise reservoir/metal

chenzk 3 weeks ago
parent
commit
dce33ff7d5
34 changed files with 2436 additions and 1148 deletions
  1. 1 1
      CyberX8_MainPages/ViewModels/StandardHotReservoirsViewModel.cs
  2. 0 2
      CyberX8_MainPages/Views/StandardHotReservoirsView.xaml
  3. 15 1
      CyberX8_RT/Config/DBModel.sql
  4. 4 4
      CyberX8_RT/Config/Devices/FestoControllerCfg-Simulator.xml
  5. 36 122
      CyberX8_RT/Config/Devices/ModuleIOCfg.xml
  6. 1 0
      CyberX8_RT/Config/Devices/SMCCfg.xml
  7. 8 8
      CyberX8_RT/Config/Devices/WagoControllerCfg-Simulator.xml
  8. 5 5
      CyberX8_RT/Config/Layout/ToolLayoutConfiguration.xml
  9. 183 44
      CyberX8_RT/Config/System.sccfg
  10. 58 54
      CyberX8_RT/Devices/Facilities/SystemFacilities.cs
  11. 101 69
      CyberX8_RT/Devices/Metal/CompactMembranMetalDevice.cs
  12. 49 24
      CyberX8_RT/Devices/Metal/MetalCellDevice.cs
  13. 8 9
      CyberX8_RT/Devices/Metal/StandardHotMetalDevice.cs
  14. 631 264
      CyberX8_RT/Devices/Reservoir/CompactMembranReservoirDevice.cs
  15. 14 13
      CyberX8_RT/Devices/Reservoir/ReservoirDiReplenHelper.cs
  16. 585 218
      CyberX8_RT/Devices/Reservoir/StandardHotReservoirDevice.cs
  17. 13 12
      CyberX8_RT/Devices/Reservoir/TotalReservoirDevice.cs
  18. 7 21
      CyberX8_RT/Devices/Temperature/TemperatureController.cs
  19. 334 78
      CyberX8_RT/Modules/Metal/MetalEntity.cs
  20. 14 14
      CyberX8_RT/Modules/Metal/StandardHotInitializeRoutine.cs
  21. 16 10
      CyberX8_RT/Modules/Metal/StandardHotRunRecipeRoutine.cs
  22. 47 43
      CyberX8_RT/Modules/Reservoir/ReservoirEntity.cs
  23. 59 57
      CyberX8_RT/Modules/Reservoir/StandardHotReservoirInitializeRoutine.cs
  24. 1 0
      CyberX8_Simulator/Config/SimulatorIOMapCfg.xml
  25. 45 7
      CyberX8_Simulator/Devices/WagoSocketSimulator.cs
  26. 84 20
      Framework/Common/Alarm/AlarmListManager.cs
  27. 7 6
      Framework/Common/CommonData/AlarmList.cs
  28. 3 0
      Framework/Common/CommonData/Reservoir/StandardHotReservoirData.cs
  29. 18 13
      Framework/Common/DBCore/MetalUsageRecorder.cs
  30. 9 9
      Framework/Common/DBCore/ReservoirUsageRecorder.cs
  31. 9 0
      Framework/Common/ProcessCell/MetalUsage.cs
  32. 30 14
      Framework/Common/ToolLayout/MetalUsageManager.cs
  33. 2 2
      Framework/Common/ToolLayout/ReservoirUsageManager.cs
  34. 39 4
      Framework/SimulatorCore/Commons/TemperatureControllerSerialPortDevice.cs

+ 1 - 1
CyberX8_MainPages/ViewModels/StandardHotReservoirsViewModel.cs

@@ -1046,7 +1046,7 @@ namespace CyberX8_MainPages.ViewModels
                         //Low Level报警灯
                         IsLowLevel = ReservoirData.LowLevel;
                         //HighSafety
-                        if(CommonSafetyData != null) IsHighSafety = CommonSafetyData.ReservoirHighLevel;
+                        IsHighSafety = ReservoirData.SafetyHighLevel;
                         //HedFlow管流
                         HEDFlowIsOn = (ReservoirData.HedFlow > 0) ? true : false;
                         //DIReplenFault

+ 0 - 2
CyberX8_MainPages/Views/StandardHotReservoirsView.xaml

@@ -574,8 +574,6 @@ Visibility="{Binding IsError,Converter={StaticResource boolToVisibility2}}" Canv
                                       TempValue="{Binding TemperatureControlData.ReserviorTemperature}" ModuleName="{Binding TemperatureControlData.Name}"
                                       Status="{Binding TemperatureControlData.Status}" DisableStatus="{Binding TCEnableStatus}"/>
         </Canvas>
-
-        <Button Visibility="{Binding IsDosingSystemEnabled,Converter={StaticResource boolToVisibility2}}" Style="{StaticResource SysBtnStyle}" Command="{Binding JumpDosingSystemCommand}" Grid.Column="1" Height="30" Width="100" HorizontalAlignment="Left" VerticalAlignment="Bottom"  Content="Dosing System" Canvas.Left="1745" Canvas.Top="763"/>
     </Canvas>
 
 </UserControl>

+ 15 - 1
CyberX8_RT/Config/DBModel.sql

@@ -398,8 +398,22 @@ begin
 					ALTER TABLE "metal_usage"
 					OWNER TO postgres;
 					GRANT SELECT ON TABLE "metal_usage" TO postgres;
-
 	end if; 
+    if not exists(select * from information_schema.columns 
+		where table_catalog = CURRENT_CATALOG  and table_schema = CURRENT_SCHEMA  and table_name = 'metal_usage' and column_name = 'anode_a_bath_usage') then
+
+		Alter TABLE "metal_usage" ADD column anode_a_bath_usage integer default 0;
+	end if;
+    if not exists(select * from information_schema.columns 
+		where table_catalog = CURRENT_CATALOG  and table_schema = CURRENT_SCHEMA  and table_name = 'metal_usage' and column_name = 'anode_b_bath_usage') then
+
+		Alter TABLE "metal_usage" ADD column anode_b_bath_usage integer default 0;
+	end if;
+	if not exists(select * from information_schema.columns 
+		where table_catalog = CURRENT_CATALOG  and table_schema = CURRENT_SCHEMA  and table_name = 'metal_usage' and column_name = 'bath_reset_time') then
+
+		Alter TABLE "metal_usage" ADD column bath_reset_time timestamp without time zone DEFAULT CURRENT_TIMESTAMP;
+	end if;
 
 ------------------------------------------------------------------------------------------------
  if not exists(select * from information_schema.tables  

+ 4 - 4
CyberX8_RT/Config/Devices/FestoControllerCfg-Simulator.xml

@@ -13,13 +13,13 @@
 		<DO Name="Festo.DO9"  Address="40004" Invert="false" Bit="1"/>
 		<DO Name="c_QDRD1_DI_FILL" Address="40004" Invert="false" Bit="2"/>
 		<DO Name="c_QDRD1_DUMP" Address="40004" Invert="false" Bit="3"/>
-		<DO Name="c_RESERVOIR1_DI_REPLEN" Address="40004" Invert="false" Bit="4"/>
+		<DO Name="c_RES1_DI_REPLEN" Address="40004" Invert="false" Bit="4"/>
 		<DO Name="c_QDRD2_DI_FILL" Address="40004" Invert="false" Bit="5"/>
 		<DO Name="c_QDRD2_DUMP" Address="40004" Invert="false" Bit="6"/>
-		<DO Name="c_RESERVOIR2_DI_REPLEN" Address="40004" Invert="false" Bit="7"/>
+		<DO Name="c_RES2_DI_REPLEN" Address="40004" Invert="false" Bit="7"/>
 		<DO Name="c_QDRD3_DI_FILL" Address="40005" Invert="false" Bit="0"/>
 		<DO Name="c_QDRD3_DUMP" Address="40005" Invert="false" Bit="1"/>
-		<DO Name="c_RESERVOIR3_DI_REPLEN" Address="40005" Invert="false" Bit="2"/>
+		<DO Name="c_RES3_DI_REPLEN" Address="40005" Invert="false" Bit="2"/>
 		<DO Name="c_PH2_FLOW_VALVE" Address="40005" Invert="false" Bit="3"/>
 		<DO Name="Festo.DO20" Address="40005" Invert="false" Bit="4"/>
 		<DO Name="Festo.DO21" Address="40005" Invert="false" Bit="5"/>
@@ -65,7 +65,7 @@
 		<DO Name="Festo.DO3"  Address="40003" Invert="false" Bit="3"/>
 		<DO Name="Festo.DO4"  Address="40003" Invert="false" Bit="4"/>
 		<DO Name="Festo.DO5"  Address="40003" Invert="false" Bit="5"/>
-		<DO Name="c_RESERVOIR4_DI_REPLEN"  Address="40003" Invert="false" Bit="6"/>
+		<DO Name="c_RES4_DI_REPLEN"  Address="40003" Invert="false" Bit="6"/>
 		<DO Name="Festo.DO7"  Address="40003" Invert="false" Bit="7"/>
 		<DO Name="c_METAL3_CIRCULATION"  Address="40004" Invert="false" Bit="0"/>
 		<DO Name="Festo.DO9"  Address="40004" Invert="false" Bit="1"/>

+ 36 - 122
CyberX8_RT/Config/Devices/ModuleIOCfg.xml

@@ -398,36 +398,13 @@
 	</Module>
   
 	<Module Name="Reservoir1">
-	<IO Name="Reservoir1.EvaporatorLevel" IOName="r_DI_EVAPORATOR_LEVEL"/>
-	<IO Name="Reservoir1.CADiReplen" IOName="c_RES1_CA_DI_REPLEN"/>
-	<IO Name="Reservoir1.ANDiReplen" IOName="c_RES1_AN_DI_REPLEN"/>
-	<IO Name="Reservoir1.CAWaterLevel" IOName="r_RES1_CA_LEVEL_raw"/>
-	<IO Name="Reservoir1.ANWaterLevel" IOName="r_RES1_AN_LEVEL_raw"/>
-	<IO Name="Reservoir1.ANPump" IOName="c_RES1_AN_PUMP"/>	
-	<IO Name="Reservoir1.ANByPass" IOName="c_RES1_AN_BYPASS"/>		
-	<IO Name="Reservoir1.CrossDoseEnable" IOName="c_RES1_CROSSDOSE_ENABLE"/>
-	<IO Name="Reservoir1.TransferPumpSTMStatus" IOName="c_RES1_AN_TRANSFER_PUMP.STMStatus"/>
-	<IO Name="Reservoir1.TransferPumpPOSStatus" IOName="c_RES1_AN_TRANSFER_PUMP.POSStatus"/>
-	<IO Name="Reservoir1.TransferPumpActualPosition" IOName="c_RES1_AN_TRANSFER_PUMP.ActualPosition"/>
-	<IO Name="Reservoir1.TransferPumpEnable" IOName="c_RES1_AN_TRANSFER_PUMP.Enable"/>
-	<IO Name="Reservoir1.TransferPumpReset" IOName="c_RES1_AN_TRANSFER_PUMP.Reset"/>
-	<IO Name="Reservoir1.TransferPumpExecute" IOName="c_RES1_AN_TRANSFER_PUMP.Execute"/>
-	<IO Name="Reservoir1.TransferPumpTargetPosition" IOName="c_RES1_AN_TRANSFER_PUMP.TargetPosition"/>
-	<IO Name="Reservoir1.TransferPumpSpeed" IOName="c_RES1_AN_TRANSFER_PUMP.Speed"/>
-	<IO Name="Reservoir1.TransferPumpStartType" IOName="c_RES1_AN_TRANSFER_PUMP.StartType"/>
-	<IO Name="Reservoir1.TransferPumpAcceleration" IOName="c_RES1_AN_TRANSFER_PUMP.Acceleration"/>
-	<IO Name="Reservoir1.TransferPumpDeceleration" IOName="c_RES1_AN_TRANSFER_PUMP.Deceleration"/>
-	<IO Name="Reservoir1.ANBypassFlow" IOName="r_RES1_AN_BYPASS_FLOW"/>
-	<IO Name="Reservoir1.ANADrainPump" IOName="c_RES1_AN_A_DRAIN_PUMP"/>
-	<IO Name="Reservoir1.ANBDrainPump" IOName="c_RES1_AN_B_DRAIN_PUMP"/>
-	<IO Name="Reservoir1.CAPumpEnable" IOName="c_RES1_CA_PUMP_ENABLE"/>
-	<IO Name="Reservoir1.CAPumpSpeed" IOName="c_RES1_CA_PUMP_SPEED"/>
-	<IO Name="Reservoir1.CAByPass" IOName="c_RES1_CA_BYPASS"/>
-	<IO Name="Reservoir1.CAPumpRunning" IOName="r_RES1_CA_PUMP_RUNNING"/>
-	<IO Name="Reservoir1.CAHedFlow" IOName="r_RES1_CA_HED_FLOW"/>
-	<IO Name="Reservoir1.CDAFlowValve" IOName="c_RES1_DI_EVAP_FLOW_ENABLE"/>
-	<IO Name="Reservoir1.ANSampleFlow" IOName="c_RES1_AN_SAMPLE_FLOW_ENABLE"/>
-	<IO Name="Reservoir1.CASampleFlow" IOName="c_RES1_CA_SAMPLE_FLOW_ENABLE"/>
+	<IO Name="Reservoir1.Flow" IOName="r_RES1_CMM_FLOW"/>
+	<IO Name="Reservoir1.DiReplen" IOName="c_RES1_DI_REPLEN"/>
+	<IO Name="Reservoir1.PHFlowValve" IOName="c_PH1_FLOW_VALVE"/>
+	<IO Name="Reservoir1.WaterLevel" IOName="r_RES1_LEVEL_raw"/>
+	<IO Name="Reservoir1.LowLevel" IOName="r_RES1_LOW_LEVEL"/>
+	<IO Name="Reservoir1.SafetyHighLevel" IOName="r_RES1_HIGH_LEVEL"/>
+	<IO Name="Reservoir1.HedFlow" IOName="r_RES1_HED_FLOW"/>
 	</Module>
 	<Module Name="Reservoir2">
 	<IO Name="Reservoir2.Flow" IOName="r_RES2_CMM_FLOW"/>
@@ -436,6 +413,7 @@
 	<IO Name="Reservoir2.PHValue" IOName="r_pH2"/>
 	<IO Name="Reservoir2.WaterLevel" IOName="r_RES2_LEVEL_raw"/>
 	<IO Name="Reservoir2.LowLevel" IOName="r_RES2_LOW_LEVEL"/>
+    <IO Name="Reservoir2.SafetyHighLevel" IOName="r_RES2_HIGH_LEVEL"/>
 	<IO Name="Reservoir2.HedFlow" IOName="r_RES2_HED_FLOW"/>
 	<IO Name="Reservoir2.Replen1PumpSpeed" IOName="c_M3_REPLEN1_SPEED"/>
 	<IO Name="Reservoir2.Replen2PumpSpeed" IOName="c_M3_REPLEN2_SPEED"/>
@@ -443,73 +421,39 @@
 	<IO Name="Reservoir2.Replen2Level" IOName="r_M3_REPLEN2_LEVEL"/>
 	</Module>
 	<Module Name="Reservoir3">
-	<IO Name="Reservoir3.CADiReplen" IOName="c_RES3_CA_DI_REPLEN"/>
-	<IO Name="Reservoir3.ANDiReplen" IOName="c_RES3_AN_DI_REPLEN"/>
-	<IO Name="Reservoir3.CAWaterLevel" IOName="r_RES3_CA_LEVEL_raw"/>
-	<IO Name="Reservoir3.ANWaterLevel" IOName="r_RES3_AN_LEVEL_raw"/>
-	<IO Name="Reservoir3.ANPump" IOName="c_RES3_AN_PUMP"/>
-	<IO Name="Reservoir3.ANByPass" IOName="c_RES3_AN_BYPASS"/>	
-	<IO Name="Reservoir3.CrossDoseEnable" IOName="c_RES3_CROSSDOSE_ENABLE"/>
-	<IO Name="Reservoir3.TransferPumpSTMStatus" IOName="c_RES3_AN_TRANSFER_PUMP.STMStatus"/>
-	<IO Name="Reservoir3.TransferPumpPOSStatus" IOName="c_RES3_AN_TRANSFER_PUMP.POSStatus"/>
-	<IO Name="Reservoir3.TransferActualPosition" IOName="c_RES3_AN_TRANSFER_PUMP.ActualPosition"/>
-	<IO Name="Reservoir3.TransferPumpEnable" IOName="c_RES3_AN_TRANSFER_PUMP.Enable"/>
-	<IO Name="Reservoir3.TransferPumpReset" IOName="c_RES3_AN_TRANSFER_PUMP.Reset"/>
-	<IO Name="Reservoir3.TransferPumpExecute" IOName="c_RES3_AN_TRANSFER_PUMP.Execute"/>
-	<IO Name="Reservoir3.TransferPumpTargetPosition" IOName="c_RES3_AN_TRANSFER_PUMP.TargetPosition"/>
-	<IO Name="Reservoir3.TransferPumpSpeed" IOName="c_RES3_AN_TRANSFER_PUMP.Speed"/>
-	<IO Name="Reservoir3.TransferPumpStartType" IOName="c_RES3_AN_TRANSFER_PUMP.StartType"/>
-	<IO Name="Reservoir3.TransferPumpAcceleration" IOName="c_RES3_AN_TRANSFER_PUMP.Acceleration"/>
-	<IO Name="Reservoir3.TransferPumpDeceleration" IOName="c_RES3_AN_TRANSFER_PUMP.Deceleration"/>
-	<IO Name="Reservoir3.ANBypassFlow" IOName="r_RES3_AN_BYPASS_FLOW"/>
-	<IO Name="Reservoir3.ANADrainPump" IOName="c_RES3_AN_A_DRAIN_PUMP"/>
-	<IO Name="Reservoir3.ANBDrainPump" IOName="c_RES3_AN_B_DRAIN_PUMP"/>
-	<IO Name="Reservoir3.CAPumpSpeed" IOName="c_RES3_CA_PUMP_SPEED"/>
-	<IO Name="Reservoir3.CAPumpEnable" IOName="c_RES3_CA_PUMP_ENABLE"/>
-	<IO Name="Reservoir3.CAByPass" IOName="c_RES3_CA_BYPASS"/>
-	<IO Name="Reservoir3.CAPumpRunning" IOName="r_RES3_CA_PUMP_RUNNING"/>
-	<IO Name="Reservoir3.CAHedFlow" IOName="r_RES3_CA_HED_FLOW"/>
-	<IO Name="Reservoir3.CDAFlowValve" IOName="c_RES3_DI_EVAP_FLOW_ENABLE"/>
-	<IO Name="Reservoir3.ANTransferFlow" IOName="r_RES3_AN_TRANSFER_FLOW"/>
-	<IO Name="Reservoir3.ANSampleFlow" IOName="c_RES3_AN_SAMPLE_FLOW_ENABLE"/>
-	<IO Name="Reservoir3.CASampleFlow" IOName="c_RES3_CA_SAMPLE_FLOW_ENABLE"/>
+	<IO Name="Reservoir3.Flow" IOName="r_RES3_CMM_FLOW"/>
+	<IO Name="Reservoir3.DiReplen" IOName="c_RES3_DI_REPLEN"/>
+	<IO Name="Reservoir3.WaterLevel" IOName="r_RES3_LEVEL_raw"/>
+	<IO Name="Reservoir3.LowLevel" IOName="r_RES3_LOW_LEVEL"/>
+    <IO Name="Reservoir3.SafetyHighLevel" IOName="r_RES3_HIGH_LEVEL"/>
+	<IO Name="Reservoir3.HedFlow" IOName="r_RES3_HED_FLOW"/>
+	</Module>
+    <Module Name="Reservoir4">
+	<IO Name="Reservoir4.Flow" IOName="r_RES4_CMM_FLOW"/>
+	<IO Name="Reservoir4.DiReplen" IOName="c_RES4_DI_REPLEN"/>
+	<IO Name="Reservoir4.WaterLevel" IOName="r_RES4_LEVEL_raw"/>
+	<IO Name="Reservoir4.LowLevel" IOName="r_RES4_LOW_LEVEL"/>
+    <IO Name="Reservoir4.SafetyHighLevel" IOName="r_RES4_HIGH_LEVEL"/>
+	<IO Name="Reservoir4.HedFlow" IOName="r_RES4_HED_FLOW"/>
 	</Module>
   
 	<Module Name="Metal1">
-	<IO Name="Metal1.ANAPinEnable" IOName="c_CELL1_AN_A_PIN_ENABLE"/>	
-	<IO Name="Metal1.ANBPinEnable" IOName="c_CELL1_AN_B_PIN_ENABLE"/>
-	<IO Name="Metal1.ANAPoutEnable" IOName="c_CELL1_AN_A_POUT_ENABLE"/>	
-	<IO Name="Metal1.ANBPoutEnable" IOName="c_CELL1_AN_B_POUT_ENABLE"/>  
-	<IO Name="Metal1.CellFlow" IOName="r_CELL1_FLOW"/>
-	<IO Name="Metal1.ANACellFlow" IOName="r_CELL1_AN_A_FLOW"/>
-	<IO Name="Metal1.ANBCellFlow" IOName="r_CELL1_AN_B_FLOW"/>
-	<IO Name="Metal1.WHClamp" IOName="c_METAL1_WS_CLAMP_ON"/>
-	<IO Name="Metal1.WHUnclamp" IOName="c_METAL1_WS_CLAMP_OFF"/>
-	<IO Name="Metal1.CellFlowValve" IOName="c_CELL1_FLOW"/>
-	</Module>
-	<Module Name="Metal2">  
-	<IO Name="Metal2.ANAPinEnable" IOName="c_CELL2_AN_A_PIN_ENABLE"/>	
-	<IO Name="Metal2.ANBPinEnable" IOName="c_CELL2_AN_B_PIN_ENABLE"/>
-	<IO Name="Metal2.ANAPoutEnable" IOName="c_CELL2_AN_A_POUT_ENABLE"/>	
-	<IO Name="Metal2.ANBPoutEnable" IOName="c_CELL2_AN_B_POUT_ENABLE"/>
-	<IO Name="Metal2.CellFlow" IOName="r_CELL2_FLOW"/> 
-	<IO Name="Metal2.ANACellFlow" IOName="r_CELL2_AN_A_FLOW"/>
-	<IO Name="Metal2.ANBCellFlow" IOName="r_CELL2_AN_B_FLOW"/>
-	<IO Name="Metal2.WHClamp" IOName="c_METAL2_WS_CLAMP_ON"/>
-	<IO Name="Metal2.WHUnclamp" IOName="c_METAL2_WS_CLAMP_OFF"/> 
-	<IO Name="Metal2.CellFlowValve" IOName="c_CELL2_FLOW"/>
+	<IO Name="Metal1.CellFlow" IOName="r_PUMP1_FLOW"/>
+	<IO Name="Metal1.CellPump" IOName="c_METAL1_PUMP_ON"/>
+	<IO Name="Metal1.Circulation" IOName="c_METAL1_CIRCULATION"/>
+	<IO Name="Metal1.WaferHolderClamp" IOName="c_METAL1_WH_CLAMP"/>
+	</Module>
+	<Module Name="Metal2">
+	<IO Name="Metal2.CellFlow" IOName="r_PUMP2_FLOW"/>
+	<IO Name="Metal2.CellPump" IOName="c_METAL2_PUMP_ON"/>
+	<IO Name="Metal2.Circulation" IOName="c_METAL2_CIRCULATION"/>
+	<IO Name="Metal2.WaferHolderClamp" IOName="c_METAL2_WH_CLAMP"/>
 	</Module>
 	<Module Name="Metal3">
-	<IO Name="Metal3.ANAPinEnable" IOName="c_CELL3_AN_A_PIN_ENABLE"/>	
-	<IO Name="Metal3.ANBPinEnable" IOName="c_CELL3_AN_B_PIN_ENABLE"/>
-	<IO Name="Metal3.ANAPoutEnable" IOName="c_CELL3_AN_A_POUT_ENABLE"/>	
-	<IO Name="Metal3.ANBPoutEnable" IOName="c_CELL3_AN_B_POUT_ENABLE"/>  
-	<IO Name="Metal3.CellFlow" IOName="r_CELL3_FLOW"/>	
-	<IO Name="Metal3.ANACellFlow" IOName="r_CELL3_AN_A_FLOW"/>
-	<IO Name="Metal3.ANBCellFlow" IOName="r_CELL3_AN_B_FLOW"/>
-	<IO Name="Metal3.WHClamp" IOName="c_METAL3_WS_CLAMP_ON"/>
-	<IO Name="Metal3.WHUnclamp" IOName="c_METAL3_WS_CLAMP_OFF"/>
-	<IO Name="Metal3.CellFlowValve" IOName="c_CELL3_FLOW"/>
+	<IO Name="Metal3.CellFlow" IOName="r_PUMP3_FLOW"/>
+	<IO Name="Metal3.CellPump" IOName="c_METAL3_PUMP_ON"/>
+	<IO Name="Metal3.Circulation" IOName="c_METAL3_CIRCULATION"/>
+	<IO Name="Metal3.WaferHolderClamp" IOName="c_METAL3_WH_CLAMP"/>
 	</Module>
 	<Module Name="Metal4">
 	<IO Name="Metal4.CellFlow" IOName="r_PUMP4_FLOW"/>
@@ -517,34 +461,4 @@
 	<IO Name="Metal4.Circulation" IOName="c_METAL4_CIRCULATION"/>
 	<IO Name="Metal4.WaferHolderClamp" IOName="c_METAL4_WH_CLAMP"/>
 	</Module>
-	<Module Name="Metal5">
-	<IO Name="Metal5.CellFlow" IOName="r_PUMP5_FLOW"/>
-	<IO Name="Metal5.CellPump" IOName="c_METAL5_PUMP_ON"/>
-	<IO Name="Metal5.Circulation" IOName="c_METAL5_CIRCULATION"/>
-	<IO Name="Metal5.WaferHolderClamp" IOName="c_METAL5_WS_CLAMP"/>
-	</Module>
-	<Module Name="Metal6">
-	<IO Name="Metal6.ANAPinEnable" IOName="c_CELL6_AN_A_PIN_ENABLE"/>	
-	<IO Name="Metal6.ANBPinEnable" IOName="c_CELL6_AN_B_PIN_ENABLE"/>
-	<IO Name="Metal6.ANAPoutEnable" IOName="c_CELL6_AN_A_POUT_ENABLE"/>	
-	<IO Name="Metal6.ANBPoutEnable" IOName="c_CELL6_AN_B_POUT_ENABLE"/>  
-	<IO Name="Metal6.CellFlow" IOName="r_CELL6_FLOW"/>		
-	<IO Name="Metal6.ANACellFlow" IOName="r_CELL6_AN_A_FLOW"/>
-	<IO Name="Metal6.ANBCellFlow" IOName="r_CELL6_AN_B_FLOW"/>
-	<IO Name="Metal6.WHClamp" IOName="c_METAL6_WS_CLAMP_ON"/>
-	<IO Name="Metal6.WHUnclamp" IOName="c_METAL6_WS_CLAMP_OFF"/>
-	<IO Name="Metal6.CellFlowValve" IOName="c_CELL6_FLOW"/>
-	</Module>
-	<Module Name="Metal7">
-	<IO Name="Metal7.ANAPinEnable" IOName="c_CELL7_AN_A_PIN_ENABLE"/>	
-	<IO Name="Metal7.ANBPinEnable" IOName="c_CELL7_AN_B_PIN_ENABLE"/>
-	<IO Name="Metal7.ANAPoutEnable" IOName="c_CELL7_AN_A_POUT_ENABLE"/>	
-	<IO Name="Metal7.ANBPoutEnable" IOName="c_CELL7_AN_B_POUT_ENABLE"/>
-	<IO Name="Metal7.ANACellFlow" IOName="r_CELL7_AN_A_FLOW"/>
-	<IO Name="Metal7.ANBCellFlow" IOName="r_CELL7_AN_B_FLOW"/>
-	<IO Name="Metal7.CellFlow" IOName="r_CELL7_FLOW"/> 
-	<IO Name="Metal7.WHClamp" IOName="c_METAL7_WS_CLAMP_ON"/>
-	<IO Name="Metal7.WHUnclamp" IOName="c_METAL7_WS_CLAMP_OFF"/>
-	<IO Name="Metal7.CellFlowValve" IOName="c_CELL7_FLOW"/>
-	</Module>
 </BeckhoffModuleIOCfg>

+ 1 - 0
CyberX8_RT/Config/Devices/SMCCfg.xml

@@ -5,6 +5,7 @@
     <Device Name="TC1-1" Address="1"/>
     <Device Name="TC1-2" Address="2"/>
     <Device Name="TC1-3" Address="3"/>
+    <Device Name="TC1-4" Address="4"/>
   </SMCDeviceConfig>
   <SMCDeviceConfig Name ="TC2" Port="com13" BaudRate="2400" Parity="N" Data="8" StopBit="1">
     <Device Name="TC2-1" Address="1"/>

+ 8 - 8
CyberX8_RT/Config/Devices/WagoControllerCfg-Simulator.xml

@@ -195,7 +195,7 @@
 				<DI Name="DI29"  Address="31" Invert="false"/>
 			</DIGroup>
 			<DIGroup Name="22">
-				<DI Name="r_RES1_HI_LEVEL"  Address="32" Invert="false"/>
+				<DI Name="r_RES1_HIGH_LEVEL"  Address="32" Invert="false"/>
 				<DI Name="r_RES1_LOW_LEVEL"  Address="33" Invert="true"/>
 				<DI Name="r_RES2_HIGH_LEVEL"  Address="34" Invert="false"/>
 				<DI Name="r_RES2_LOW_LEVEL"  Address="35" Invert="true"/>
@@ -272,7 +272,7 @@
 			</DOGroup>
 			<DOGroup Name="29">
 				<DO Name="c_RES3_POWER_ON"  Address="552" Invert="false"/>
-				<DO Name="DO41"  Address="553" Invert="false"/>
+				<DO Name="c_METAL4_PUMP_ON"  Address="553" Invert="false"/>
 			</DOGroup>
 		</Dig_Out>
 		<Ano_In>
@@ -331,16 +331,16 @@
 				<AI Name="AI35"  Address="35" Scaling="13=0,150=32767" DataType="short"/>
 			</AIGroup>
 			<AIGroup Name="10">
-				<AI Name="r_RES_LEVEL_1_raw"  Address="36" Scaling="0=3276.7,100=32767" DataType="short"/>
-				<AI Name="r_RES_LEVEL_2_raw"  Address="37" Scaling="0=3276.7,100=32767" DataType="short"/>
-				<AI Name="r_RES_LEVEL_3_raw"  Address="38" Scaling="0=3276.7,100=32767" DataType="short"/>
-				<AI Name="r_RES_LEVEL_4_raw"  Address="39" Scaling="0=3276.7,100=32767" DataType="short"/>
+				<AI Name="r_RES1_LEVEL_raw"  Address="36" Scaling="0=0,100=32767" DataType="short"/>
+				<AI Name="r_RES2_LEVEL_raw"  Address="37" Scaling="0=0,100=32767" DataType="short"/>
+				<AI Name="r_RES3_LEVEL_raw"  Address="38" Scaling="0=0,100=32767" DataType="short"/>
+				<AI Name="r_RES4_LEVEL_raw"  Address="39" Scaling="0=0,100=32767" DataType="short"/>
 			</AIGroup>
 			<AIGroup Name="11">
 				<AI Name="AI40"  Address="40" Scaling="0=3276.7,-757.5=16383.5" DataType="short"/>
 				<AI Name="AI41"  Address="41" Scaling="0=3276.7,-757.5=16383.5" DataType="short"/>
 				<AI Name="AI42"  Address="42" Scaling="13=0,150=32767" DataType="short"/>
-				<AI Name="r_HCW_FLOW"  Address="43" Scaling="0=3276.7,40=32767" DataType="short"/>
+				<AI Name="r_HCW_FLOW"  Address="43" Scaling="0=0,40=32767" DataType="short"/>
 			</AIGroup>
 			<AIGroup Name="12">
 				<AI Name="r_CDA_EXTERNAL_PRESSURE"  Address="44" Scaling="0=3276.7,145=16383.5" DataType="short"/>
@@ -357,7 +357,7 @@
 			<AIGroup Name="14">
 				<AI Name="r_N2_2A_PRESSURE"  Address="52" Scaling="0=3276.7,145=16383.5" DataType="short"/>
 				<AI Name="r_N2_BLANKET_PRESSURE"  Address="53" Scaling="0=3276.7,14.5=16383.5" DataType="short"/>
-				<AI Name="r_SYSTEM_VACUUM"  Address="54" Scaling="0=3276.7,-757.5=16383.5" DataType="short"/>
+				<AI Name="r_SYSTEM_VACUUM"  Address="54" Scaling="-750=3276.7, 750=16383.5" DataType="short"/>
 				<AI Name="AI55"  Address="55" Scaling="13=0,150=32767" DataType="short"/>
 			</AIGroup>
 		</Ano_In>

+ 5 - 5
CyberX8_RT/Config/Layout/ToolLayoutConfiguration.xml

@@ -389,7 +389,7 @@
 				<Item i:type="Metal">
 					<Installed>true</Installed>
 					<PermittedWaferSizeInMM>300</PermittedWaferSizeInMM>
-					<CellID>7</CellID>
+					<CellID>2</CellID>
 					<NominalGantryPositionInMilliMeters>2219</NominalGantryPositionInMilliMeters>
 					<MetalID>1</MetalID>
 					<PlatingPowerSupplyAID>Power1-1</PlatingPowerSupplyAID>
@@ -436,7 +436,7 @@
 				<Item i:type="Metal">
 					<Installed>true</Installed>
 					<PermittedWaferSizeInMM>300</PermittedWaferSizeInMM>
-					<CellID>8</CellID>
+					<CellID>7</CellID>
 					<NominalGantryPositionInMilliMeters>2219</NominalGantryPositionInMilliMeters>
 					<MetalID>2</MetalID>
 					<PlatingPowerSupplyAID>Power3-1</PlatingPowerSupplyAID>
@@ -473,7 +473,7 @@
 
 		<Item i:type="Rinse">
 			<Installed>true</Installed>
-			<CellID>10</CellID>
+			<CellID>12</CellID>
 			<NominalGantryPositionInMilliMeters>2390</NominalGantryPositionInMilliMeters>
 			<RinseID>4</RinseID>
 			<SubType>QDR</SubType>
@@ -492,7 +492,7 @@
 				<Item i:type="Metal">
 					<Installed>true</Installed>
 					<PermittedWaferSizeInMM>300</PermittedWaferSizeInMM>
-					<CellID>9</CellID>
+					<CellID>10</CellID>
 					<NominalGantryPositionInMilliMeters>2219</NominalGantryPositionInMilliMeters>
 					<MetalID>3</MetalID>
 					<PlatingPowerSupplyAID>Power5-1</PlatingPowerSupplyAID>
@@ -530,7 +530,7 @@
 				<Item i:type="Metal">
 					<Installed>true</Installed>
 					<PermittedWaferSizeInMM>300</PermittedWaferSizeInMM>
-					<CellID>10</CellID>
+					<CellID>14</CellID>
 					<NominalGantryPositionInMilliMeters>2219</NominalGantryPositionInMilliMeters>
 					<MetalID>4</MetalID>
 					<PlatingPowerSupplyAID>Power7-1</PlatingPowerSupplyAID>

+ 183 - 44
CyberX8_RT/Config/System.sccfg

@@ -223,24 +223,97 @@
 		<config default="2.5" name="AnodeFillVolume" nameView="AnodeFillVolume" description="Time delay after placing wafer holder down to cell" max="5" min="0" paramter="" tag="" unit="" type="Double"/>
 		<config default="240" name="AnodeDrainTime" nameView="AnodeDrainTime" description="Time for AN Drain" max="600" min="0" paramter="" tag="" unit="s" type="Double"/>
 		<config default="3.0" name="CellFlowStartLowLimit" nameView="CellFlowStartLowLimit" description="cell flow start low limit" max="30" min="0" paramter="" tag="" unit="" type="Double"/>
-		<config default="0.125" name="ShortTestThreshold" nameView="ShortTestThreshold" description="short test threshold" max="1" min="0" paramter="" tag="" unit="A" type="Double"/>
-		<config default="50" name="MetalTotalAmpHoursWarningLimit" nameView="MetalTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
-		<config default="100" name="MetalTotalAmpHoursFaultLimit" nameView="MetalTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="AnodeATotalAmpHoursWarningLimit" nameView="AnodeATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="AnodeATotalAmpHoursFaultLimit" nameView="AnodeATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="AnodeBTotalAmpHoursWarningLimit" nameView="AnodeBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="AnodeBTotalAmpHoursFaultLimit" nameView="AnodeBTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="MembraneATotalAmpHoursWarningLimit" nameView="MembraneATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="MembraneATotalAmpHoursFaultLimit" nameView="MembraneATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="MembraneBTotalAmpHoursWarningLimit" nameView="MembraneBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="MembraneBTotalAmpHoursFaultLimit" nameView="MembraneBTotalAmpHoursFaultLimit"  type="Double" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="MetalTotalWafersWarningLimit" nameView="MetalTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="MetalTotalWafersFaultLimit" nameView="MetalTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
-		<config default="50" name="AnodeATotalWafersWarningLimit" nameView="AnodeATotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="AnodeATotalWafersFaultLimit" nameView="AnodeATotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="AnodeBTotalWafersWarningLimit" nameView="AnodeBTotalWafersWarningLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="AnodeBTotalWafersFaultLimit" nameView="AnodeBTotalWafersFaultLimit" type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description=""/>
-		<config default="100" name="WaferShuttleSoakMaxTime" nameView="Max Time Length of Wafer Shuttle Soak in metal" type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="minute" description=""/>
+		<config default="0.125" name="ShortTestThreshold" nameView="ShortTestThreshold" description="short test threshold" max="1" min="0" paramter="" tag="" unit="A" type="Double"/>		
+		<config default="100" name="WaferShuttleSoakMaxTime" nameView="WaferShuttleSoakMaxTime" description="Max Time Length of Wafer Shuttle Soak in metal" type="Integer" min="0" max="100000" paramter="" tag="" unit="minute"/>
+		<config default="10" name="CurrentCheckDelay" nameView="CurrentCheckDelay" description="After delay second to check current"  type="Integer" min="0" max="60" paramter="" tag="" unit="s" />
+			<configs name="Metal1" nameView="Metal1">
+					<config default="50" name="MetalTotalAmpHoursWarningLimit" nameView="MetalTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+					<config default="100" name="MetalTotalAmpHoursFaultLimit" nameView="MetalTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeATotalAmpHoursWarningLimit" nameView="AnodeATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeATotalAmpHoursFaultLimit" nameView="AnodeATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBTotalAmpHoursWarningLimit" nameView="AnodeBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBTotalAmpHoursFaultLimit" nameView="AnodeBTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MembraneATotalAmpHoursWarningLimit" nameView="MembraneATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MembraneATotalAmpHoursFaultLimit" nameView="MembraneATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MembraneBTotalAmpHoursWarningLimit" nameView="MembraneBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MembraneBTotalAmpHoursFaultLimit" nameView="MembraneBTotalAmpHoursFaultLimit"  type="Double" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MetalTotalWafersWarningLimit" nameView="MetalTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MetalTotalWafersFaultLimit" nameView="MetalTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+					<config default="50" name="AnodeATotalWafersWarningLimit" nameView="AnodeATotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeATotalWafersFaultLimit" nameView="AnodeATotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBTotalWafersWarningLimit" nameView="AnodeBTotalWafersWarningLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBTotalWafersFaultLimit" nameView="AnodeBTotalWafersFaultLimit" type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description=""/>
+					<config default="50" name="AnodeABathTotalUsageDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeABathTotalUsageDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBBathTotalUsageDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBBathTotalUsageDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+		  </configs>
+	      <configs name="Metal2" nameView="Metal2">
+					<config default="50" name="MetalTotalAmpHoursWarningLimit" nameView="MetalTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+					<config default="100" name="MetalTotalAmpHoursFaultLimit" nameView="MetalTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeATotalAmpHoursWarningLimit" nameView="AnodeATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeATotalAmpHoursFaultLimit" nameView="AnodeATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBTotalAmpHoursWarningLimit" nameView="AnodeBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBTotalAmpHoursFaultLimit" nameView="AnodeBTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MembraneATotalAmpHoursWarningLimit" nameView="MembraneATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MembraneATotalAmpHoursFaultLimit" nameView="MembraneATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MembraneBTotalAmpHoursWarningLimit" nameView="MembraneBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MembraneBTotalAmpHoursFaultLimit" nameView="MembraneBTotalAmpHoursFaultLimit"  type="Double" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MetalTotalWafersWarningLimit" nameView="MetalTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MetalTotalWafersFaultLimit" nameView="MetalTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+					<config default="50" name="AnodeATotalWafersWarningLimit" nameView="AnodeATotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeATotalWafersFaultLimit" nameView="AnodeATotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBTotalWafersWarningLimit" nameView="AnodeBTotalWafersWarningLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBTotalWafersFaultLimit" nameView="AnodeBTotalWafersFaultLimit" type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description=""/>
+					<config default="50" name="AnodeABathTotalUsageDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeABathTotalUsageDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBBathTotalUsageDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBBathTotalUsageDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+		  </configs>
+	      <configs name="Metal3" nameView="Metal3">
+					<config default="50" name="MetalTotalAmpHoursWarningLimit" nameView="MetalTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+					<config default="100" name="MetalTotalAmpHoursFaultLimit" nameView="MetalTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeATotalAmpHoursWarningLimit" nameView="AnodeATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeATotalAmpHoursFaultLimit" nameView="AnodeATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBTotalAmpHoursWarningLimit" nameView="AnodeBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBTotalAmpHoursFaultLimit" nameView="AnodeBTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MembraneATotalAmpHoursWarningLimit" nameView="MembraneATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MembraneATotalAmpHoursFaultLimit" nameView="MembraneATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MembraneBTotalAmpHoursWarningLimit" nameView="MembraneBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MembraneBTotalAmpHoursFaultLimit" nameView="MembraneBTotalAmpHoursFaultLimit"  type="Double" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MetalTotalWafersWarningLimit" nameView="MetalTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MetalTotalWafersFaultLimit" nameView="MetalTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+					<config default="50" name="AnodeATotalWafersWarningLimit" nameView="AnodeATotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeATotalWafersFaultLimit" nameView="AnodeATotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBTotalWafersWarningLimit" nameView="AnodeBTotalWafersWarningLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBTotalWafersFaultLimit" nameView="AnodeBTotalWafersFaultLimit" type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description=""/>
+					<config default="50" name="AnodeABathTotalUsageDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeABathTotalUsageDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBBathTotalUsageDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBBathTotalUsageDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+		  </configs>
+		  <configs name="Metal4" nameView="Metal4">
+					<config default="50" name="MetalTotalAmpHoursWarningLimit" nameView="MetalTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+					<config default="100" name="MetalTotalAmpHoursFaultLimit" nameView="MetalTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeATotalAmpHoursWarningLimit" nameView="AnodeATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeATotalAmpHoursFaultLimit" nameView="AnodeATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBTotalAmpHoursWarningLimit" nameView="AnodeBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBTotalAmpHoursFaultLimit" nameView="AnodeBTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MembraneATotalAmpHoursWarningLimit" nameView="MembraneATotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MembraneATotalAmpHoursFaultLimit" nameView="MembraneATotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MembraneBTotalAmpHoursWarningLimit" nameView="MembraneBTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MembraneBTotalAmpHoursFaultLimit" nameView="MembraneBTotalAmpHoursFaultLimit"  type="Double" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="MetalTotalWafersWarningLimit" nameView="MetalTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="MetalTotalWafersFaultLimit" nameView="MetalTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+					<config default="50" name="AnodeATotalWafersWarningLimit" nameView="AnodeATotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeATotalWafersFaultLimit" nameView="AnodeATotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBTotalWafersWarningLimit" nameView="AnodeBTotalWafersWarningLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBTotalWafersFaultLimit" nameView="AnodeBTotalWafersFaultLimit" type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description=""/>
+					<config default="50" name="AnodeABathTotalUsageDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeABathTotalUsageDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="50" name="AnodeBBathTotalUsageDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+					<config default="100" name="AnodeBBathTotalUsageDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+		  </configs>
 	</configs>
 	<configs name="Buffer" nameView="Buffer">
 		<config default="10" name="PickTimeSeconds" nameView="PickTimeSeconds" description="Time taken to pick up from cell" max="100000" min="0" paramter="" tag="" unit="s" type="Integer"/>
@@ -399,32 +472,6 @@
 		<config default="3" name="DrainSpeed" nameView="DrainSpeed" description="AN drain pump default speed" max="5" min="0" paramter="" tag="" unit="" type="Double"></config>
 		<config default="30" name="CellFlowUpdatePeriod" nameView="CellFlowUpdatePeriod" description="Cell Flow Update Period" max="60" min="0" paramter="" tag="" unit="s" type="Integer"/>
 		
-		<config default="50" name="ReservoirTotalAmpHoursWarningLimit" nameView="ReservoirTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="ReservoirTotalAmpHoursFaultLimit" nameView="ReservoirTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="BathTotalAmpHoursWarningLimit" nameView="BathTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="BathTotalAmpHoursFaultLimit" nameView="BathTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="ANBathTotalAmpHoursWarningLimit" nameView="ANBathTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="ANBathTotalAmpHoursFaultLimit" nameView="ANBathTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="BathTotalDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="BathTotalDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="50" name="MembraneTotalAmpHoursWarningLimit" nameView="MembraneTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="MembraneTotalAmpHoursFaultLimit" nameView="MembraneTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
-		<config default="50" name="ReservoirTotalWafersWarningLimit" nameView="ReservoirTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		<config default="100" name="ReservoirTotalWafersFaultLimit" nameView="ReservoirTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
-		
-		<configs name="CMM" nameView="CMM">
-			<config default="20" name="CMMFlowHighFault" nameView="CMMFlowHighFault" description="CMM Flow Over HighFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
-			<config default="20" name="CMMFlowHighWarning" nameView="CMMFlowHighWarning" description="CMM Flow Over HighWarninb,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
-			<config default="0" name="CMMFlowLowFault" nameView="CMMFlowLowFault" description="CMM Flow Less LowFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
-			<config default="0" name="CMMFlowLowWarning" nameView="CMMFlowLowWarning" description="CMM Flow less HighFault,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
-			<config default="1000" name="CMMAnodeLifeTimeAHrs" nameView="CMMAnodeLifeTimeAHrs" description="CMM Anode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
-			<config default="1000" name="CMMCathodeLifeTimeAHrs" nameView="CMMCathodeLifeTimeAHrs" description="CMM Cathode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
-			<config default="6" name="CMMFlowCheckDelaySeconds" nameView="CMMFlowCheckDelaySeconds" description="CMM Flow Check Delay Seconds" max="30" min="0" paramter="" tag="" unit="s" type="Integer" />
-			<config default="50" name="CMMAnodeTotalAmpHoursWarningLimit" nameView="CMMAnodeTotalAmpHoursWarningLimit" description="CMM Anode Total Amp Hours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
-			<config default="100" name="CMMAnodeTotalAmpHoursFaultLimit" nameView="CMMAnodeTotalAmpHoursFaultLimit" description="CMM Anode Total Amp Hours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
-			<config default="50" name="CMMCathodeTotalAmpHoursWarningLimit" nameView="CMMCathodeTotalAmpHoursWarningLimit" description="CMM Cathode Total AmpHours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
-			<config default="100" name="CMMCathodeTotalAmpHoursFaultLimit" nameView="CMMCathodeTotalAmpHoursFaultLimit" description="CMM Cathode Total AmpHours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
-		</configs>
 		<configs name="Reservoir1" nameView="Reservoir1">
 			<config default="16" name="DIValveMaxOnTime" nameView="DIValveMaxOnTime" description="DI Valve Max Time in period " max="50" min="0" paramter="" tag="" unit="minute" type="Double" />
 			<config default="5" name="DIValveMaxOnTimePerFill" nameView="DIValveMaxOnTimePerFill" description="DI Valve Max Time per fill " max="50" min="0" paramter="" tag="" unit="minute" type="Double" />
@@ -439,6 +486,29 @@
 			<config default="1" name="BottleReserveVolume1" nameView="BottleReserveVolume1" description="Bottle Reserve Volume of Replen1" max="5000" min="0" paramter="" tag="" unit="mL" type="Double" />
 			<config default="1" name="BottleReserveVolume2" nameView="BottleReserveVolume2" description="Bottle Reserve Volume of Replen2" max="5000" min="0" paramter="" tag="" unit="mL" type="Double" />
 			<config default="60" name="DosingOutTime" nameView="DosingOutTime" description="Dosing Out Time" max="600" min="1" paramter="" tag="" unit="s" type="Double" />
+
+			<config default="20" name="CMMFlowHighFault" nameView="CMMFlowHighFault" description="CMM Flow Over HighFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="20" name="CMMFlowHighWarning" nameView="CMMFlowHighWarning" description="CMM Flow Over HighWarninb,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="0" name="CMMFlowLowFault" nameView="CMMFlowLowFault" description="CMM Flow Less LowFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="0" name="CMMFlowLowWarning" nameView="CMMFlowLowWarning" description="CMM Flow less HighFault,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="1000" name="CMMAnodeLifeTimeAHrs" nameView="CMMAnodeLifeTimeAHrs" description="CMM Anode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="1000" name="CMMCathodeLifeTimeAHrs" nameView="CMMCathodeLifeTimeAHrs" description="CMM Cathode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="6" name="CMMFlowCheckDelaySeconds" nameView="CMMFlowCheckDelaySeconds" description="CMM Flow Check Delay Seconds" max="30" min="0" paramter="" tag="" unit="s" type="Integer" />
+			<config default="50" name="CMMAnodeTotalAmpHoursWarningLimit" nameView="CMMAnodeTotalAmpHoursWarningLimit" description="CMM Anode Total Amp Hours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="100" name="CMMAnodeTotalAmpHoursFaultLimit" nameView="CMMAnodeTotalAmpHoursFaultLimit" description="CMM Anode Total Amp Hours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="50" name="CMMCathodeTotalAmpHoursWarningLimit" nameView="CMMCathodeTotalAmpHoursWarningLimit" description="CMM Cathode Total AmpHours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="100" name="CMMCathodeTotalAmpHoursFaultLimit" nameView="CMMCathodeTotalAmpHoursFaultLimit" description="CMM Cathode Total AmpHours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+
+			<config default="52" name="ReservoirTotalAmpHoursWarningLimit" nameView="ReservoirTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="ReservoirTotalAmpHoursFaultLimit" nameView="ReservoirTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="BathTotalAmpHoursWarningLimit" nameView="BathTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="BathTotalAmpHoursFaultLimit" nameView="BathTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="BathTotalDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="BathTotalDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="MembraneTotalAmpHoursWarningLimit" nameView="MembraneTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="MembraneTotalAmpHoursFaultLimit" nameView="MembraneTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+			<config default="52" name="ReservoirTotalWafersWarningLimit" nameView="ReservoirTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="ReservoirTotalWafersFaultLimit" nameView="ReservoirTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
 		</configs>
 		<configs name="Reservoir2" nameView="Reservoir2">
 			<config default="16" name="DIValveMaxOnTime" nameView="DIValveMaxOnTime" description="DI Valve Max Time in period " max="50" min="0" paramter="" tag="" unit="minute" type="Double" />
@@ -454,6 +524,29 @@
 			<config default="1" name="BottleReserveVolume1" nameView="BottleReserveVolume1" description="Bottle Reserve Volume of Replen1" max="5000" min="0" paramter="" tag="" unit="mL" type="Double" />
 			<config default="1" name="BottleReserveVolume2" nameView="BottleReserveVolume2" description="Bottle Reserve Volume of Replen2" max="5000" min="0" paramter="" tag="" unit="mL" type="Double" />
 			<config default="60" name="DosingOutTime" nameView="DosingOutTime" description="Dosing Out Time" max="600" min="1" paramter="" tag="" unit="s" type="Double" />
+
+			<config default="20" name="CMMFlowHighFault" nameView="CMMFlowHighFault" description="CMM Flow Over HighFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="20" name="CMMFlowHighWarning" nameView="CMMFlowHighWarning" description="CMM Flow Over HighWarninb,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="0" name="CMMFlowLowFault" nameView="CMMFlowLowFault" description="CMM Flow Less LowFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="0" name="CMMFlowLowWarning" nameView="CMMFlowLowWarning" description="CMM Flow less HighFault,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="1000" name="CMMAnodeLifeTimeAHrs" nameView="CMMAnodeLifeTimeAHrs" description="CMM Anode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="1000" name="CMMCathodeLifeTimeAHrs" nameView="CMMCathodeLifeTimeAHrs" description="CMM Cathode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="6" name="CMMFlowCheckDelaySeconds" nameView="CMMFlowCheckDelaySeconds" description="CMM Flow Check Delay Seconds" max="30" min="0" paramter="" tag="" unit="s" type="Integer" />
+			<config default="50" name="CMMAnodeTotalAmpHoursWarningLimit" nameView="CMMAnodeTotalAmpHoursWarningLimit" description="CMM Anode Total Amp Hours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="100" name="CMMAnodeTotalAmpHoursFaultLimit" nameView="CMMAnodeTotalAmpHoursFaultLimit" description="CMM Anode Total Amp Hours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="50" name="CMMCathodeTotalAmpHoursWarningLimit" nameView="CMMCathodeTotalAmpHoursWarningLimit" description="CMM Cathode Total AmpHours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="100" name="CMMCathodeTotalAmpHoursFaultLimit" nameView="CMMCathodeTotalAmpHoursFaultLimit" description="CMM Cathode Total AmpHours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+
+			<config default="52" name="ReservoirTotalAmpHoursWarningLimit" nameView="ReservoirTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="ReservoirTotalAmpHoursFaultLimit" nameView="ReservoirTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="BathTotalAmpHoursWarningLimit" nameView="BathTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="BathTotalAmpHoursFaultLimit" nameView="BathTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="BathTotalDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="BathTotalDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="MembraneTotalAmpHoursWarningLimit" nameView="MembraneTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="MembraneTotalAmpHoursFaultLimit" nameView="MembraneTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+			<config default="52" name="ReservoirTotalWafersWarningLimit" nameView="ReservoirTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="ReservoirTotalWafersFaultLimit" nameView="ReservoirTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
 		</configs>
 		<configs name="Reservoir3" nameView="Reservoir3">
 			<config default="16" name="DIValveMaxOnTime" nameView="DIValveMaxOnTime" description="DI Valve Max Time in period " max="50" min="0" paramter="" tag="" unit="minute" type="Double" />
@@ -469,6 +562,29 @@
 			<config default="1" name="BottleReserveVolume1" nameView="BottleReserveVolume1" description="Bottle Reserve Volume of Replen1" max="5000" min="0" paramter="" tag="" unit="mL" type="Double" />
 			<config default="1" name="BottleReserveVolume2" nameView="BottleReserveVolume2" description="Bottle Reserve Volume of Replen2" max="5000" min="0" paramter="" tag="" unit="mL" type="Double" />
 			<config default="60" name="DosingOutTime" nameView="DosingOutTime" description="Dosing Out Time" max="600" min="1" paramter="" tag="" unit="s" type="Double" />
+
+			<config default="20" name="CMMFlowHighFault" nameView="CMMFlowHighFault" description="CMM Flow Over HighFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="20" name="CMMFlowHighWarning" nameView="CMMFlowHighWarning" description="CMM Flow Over HighWarninb,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="0" name="CMMFlowLowFault" nameView="CMMFlowLowFault" description="CMM Flow Less LowFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="0" name="CMMFlowLowWarning" nameView="CMMFlowLowWarning" description="CMM Flow less HighFault,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="1000" name="CMMAnodeLifeTimeAHrs" nameView="CMMAnodeLifeTimeAHrs" description="CMM Anode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="1000" name="CMMCathodeLifeTimeAHrs" nameView="CMMCathodeLifeTimeAHrs" description="CMM Cathode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="6" name="CMMFlowCheckDelaySeconds" nameView="CMMFlowCheckDelaySeconds" description="CMM Flow Check Delay Seconds" max="30" min="0" paramter="" tag="" unit="s" type="Integer" />
+			<config default="50" name="CMMAnodeTotalAmpHoursWarningLimit" nameView="CMMAnodeTotalAmpHoursWarningLimit" description="CMM Anode Total Amp Hours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="100" name="CMMAnodeTotalAmpHoursFaultLimit" nameView="CMMAnodeTotalAmpHoursFaultLimit" description="CMM Anode Total Amp Hours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="50" name="CMMCathodeTotalAmpHoursWarningLimit" nameView="CMMCathodeTotalAmpHoursWarningLimit" description="CMM Cathode Total AmpHours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="100" name="CMMCathodeTotalAmpHoursFaultLimit" nameView="CMMCathodeTotalAmpHoursFaultLimit" description="CMM Cathode Total AmpHours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+
+			<config default="52" name="ReservoirTotalAmpHoursWarningLimit" nameView="ReservoirTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="ReservoirTotalAmpHoursFaultLimit" nameView="ReservoirTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="BathTotalAmpHoursWarningLimit" nameView="BathTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="BathTotalAmpHoursFaultLimit" nameView="BathTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="BathTotalDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="BathTotalDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="MembraneTotalAmpHoursWarningLimit" nameView="MembraneTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="MembraneTotalAmpHoursFaultLimit" nameView="MembraneTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+			<config default="52" name="ReservoirTotalWafersWarningLimit" nameView="ReservoirTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="ReservoirTotalWafersFaultLimit" nameView="ReservoirTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
 		</configs>
 		<configs name="Reservoir4" nameView="Reservoir4">
 			<config default="16" name="DIValveMaxOnTime" nameView="DIValveMaxOnTime" description="DI Valve Max Time in period " max="50" min="0" paramter="" tag="" unit="minute" type="Double" />
@@ -484,6 +600,29 @@
 			<config default="1" name="BottleReserveVolume1" nameView="BottleReserveVolume1" description="Bottle Reserve Volume of Replen1" max="5000" min="0" paramter="" tag="" unit="mL" type="Double" />
 			<config default="1" name="BottleReserveVolume2" nameView="BottleReserveVolume2" description="Bottle Reserve Volume of Replen2" max="5000" min="0" paramter="" tag="" unit="mL" type="Double" />
 			<config default="60" name="DosingOutTime" nameView="DosingOutTime" description="Dosing Out Time" max="600" min="1" paramter="" tag="" unit="s" type="Double" />
+
+			<config default="20" name="CMMFlowHighFault" nameView="CMMFlowHighFault" description="CMM Flow Over HighFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="20" name="CMMFlowHighWarning" nameView="CMMFlowHighWarning" description="CMM Flow Over HighWarninb,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="0" name="CMMFlowLowFault" nameView="CMMFlowLowFault" description="CMM Flow Less LowFault,system occurs error " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="0" name="CMMFlowLowWarning" nameView="CMMFlowLowWarning" description="CMM Flow less HighFault,system occurs warning " max="20" min="0" paramter="" tag="" unit="L/min" type="Double" />
+			<config default="1000" name="CMMAnodeLifeTimeAHrs" nameView="CMMAnodeLifeTimeAHrs" description="CMM Anode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="1000" name="CMMCathodeLifeTimeAHrs" nameView="CMMCathodeLifeTimeAHrs" description="CMM Cathode LifeTimeAHrs" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="6" name="CMMFlowCheckDelaySeconds" nameView="CMMFlowCheckDelaySeconds" description="CMM Flow Check Delay Seconds" max="30" min="0" paramter="" tag="" unit="s" type="Integer" />
+			<config default="50" name="CMMAnodeTotalAmpHoursWarningLimit" nameView="CMMAnodeTotalAmpHoursWarningLimit" description="CMM Anode Total Amp Hours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="100" name="CMMAnodeTotalAmpHoursFaultLimit" nameView="CMMAnodeTotalAmpHoursFaultLimit" description="CMM Anode Total Amp Hours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="50" name="CMMCathodeTotalAmpHoursWarningLimit" nameView="CMMCathodeTotalAmpHoursWarningLimit" description="CMM Cathode Total AmpHours Warning Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+			<config default="100" name="CMMCathodeTotalAmpHoursFaultLimit" nameView="CMMCathodeTotalAmpHoursFaultLimit" description="CMM Cathode Total AmpHours Fault Limit" max="100000" min="0" paramter="" tag="" unit="Ah" type="Double" />
+
+			<config default="52" name="ReservoirTotalAmpHoursWarningLimit" nameView="ReservoirTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="ReservoirTotalAmpHoursFaultLimit" nameView="ReservoirTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="BathTotalAmpHoursWarningLimit" nameView="BathTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="BathTotalAmpHoursFaultLimit" nameView="BathTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="BathTotalDaysWarningLimit" nameView="BathTotalDaysWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="BathTotalDaysFaultLimit" nameView="BathTotalDaysFaultLimit"  type="Integer" value="0" min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="52" name="MembraneTotalAmpHoursWarningLimit" nameView="MembraneTotalAmpHoursWarningLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="MembraneTotalAmpHoursFaultLimit" nameView="MembraneTotalAmpHoursFaultLimit"  type="Double" value="0"  min="0" max="100000" paramter="" tag="" unit=""/>
+			<config default="52" name="ReservoirTotalWafersWarningLimit" nameView="ReservoirTotalWafersWarningLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
+			<config default="102" name="ReservoirTotalWafersFaultLimit" nameView="ReservoirTotalWafersFaultLimit"  type="Integer" value="0"  min="0" max="100000" paramter="" tag="" unit="" description="" />
 		</configs>
 	</configs>
 	<configs name="Linmot" nameView="Linmot">

+ 58 - 54
CyberX8_RT/Devices/Facilities/SystemFacilities.cs

@@ -42,7 +42,7 @@ namespace CyberX8_RT.Devices.Facilities
         private const string DI_REPLEN_ENABLE = "DiReplenEnable";
         private const string DI_FILL_ENABLE = "DiFillEnable";
         private const string LOADER_DI_ENABLE = "LoaderDiEnable";
-        private const string FILTER_PURGE_ENABLE="FilterPurgeEnable";
+        private const string FILTER_PURGE_ENABLE = "FilterPurgeEnable";
         private const string N2_1A_PRESSURE_VALUE = "Nitrogen1APressure";
         private const string N2_1B_PRESSURE_VALUE = "Nitrogen1BPressure";
         private const string N2_2A_PRESSURE_VALUE = "Nitrogen2APressure";
@@ -51,7 +51,7 @@ namespace CyberX8_RT.Devices.Facilities
         private const string CDA_2_PRESSURE_VALUE = "CDA2Pressure";
         private const string CDA_EXTERNAL_PRESSURE_VALUE = "ExternalCDAPressure";
         private const string DI_WATER_PRESSURE_VALUE = "DiWaterPressure";
-        private const string HOUSE_CHILLED_WATER_PRESSURE_VALUE="HouseChilledWaterPressure";
+        private const string HOUSE_CHILLED_WATER_PRESSURE_VALUE = "HouseChilledWaterPressure";
         private const string EXHAUST_PRESSURE_VALUE = "ExhaustPressure";
         private const string VACUUM_PRESSURE_VALUE = "VacuumPressure";
         private const string N2_BLANKET_PRESSURE_VALUE = "N2BlanketPressure";
@@ -93,7 +93,7 @@ namespace CyberX8_RT.Devices.Facilities
         /// <summary>
         /// External CDA可用性
         /// </summary>
-        private bool _externalCDAEnable=false;
+        private bool _externalCDAEnable = false;
         /// <summary>
         /// DI Water 可用性
         /// </summary>
@@ -231,13 +231,17 @@ namespace CyberX8_RT.Devices.Facilities
         /// SampleFluidDetect
         /// </summary>
         public bool SampleFluidDetect { get { return _sampleFluidDetect; } }
+        /// <summary>
+        /// Di Fill Enable
+        /// </summary>
+        public bool DIFillEnable { get { return _diFillEnable; } }
         #endregion
 
         /// <summary>
         /// 构造函数
         /// </summary>
-        public SystemFacilities():base("System",FACILITIES,FACILITIES,FACILITIES)
-        {            
+        public SystemFacilities() : base("System", FACILITIES, FACILITIES, FACILITIES)
+        {
         }
         /// <summary>
         /// 定时器
@@ -245,14 +249,14 @@ namespace CyberX8_RT.Devices.Facilities
         /// <returns></returns>
         private bool OnTimer()
         {
-            if (_isSammpleing)
-            {
-                int sampleAutoDisableTime = SC.GetValue<int>("Facilities.SampleAutoDisableTime");
-                if ((DateTime.Now - _sampleStartime).TotalSeconds >= sampleAutoDisableTime)
-                {
-                    SampleDisableOperation("", null);
-                }
-            }                      
+            //if (_isSammpleing)
+            //{
+            //    int sampleAutoDisableTime = SC.GetValue<int>("Facilities.SampleAutoDisableTime");
+            //    if ((DateTime.Now - _sampleStartime).TotalSeconds >= sampleAutoDisableTime)
+            //    {
+            //        SampleDisableOperation("", null);
+            //    }
+            //}                      
             return true;
         }
         /// <summary>
@@ -264,7 +268,7 @@ namespace CyberX8_RT.Devices.Facilities
             InitialData();
             SubscribeValueAction();
             InitializeOperation();
-            _periodicJob = new PeriodicJob(200, OnTimer, $"{Module}.OnTimer", true);
+            //_periodicJob = new PeriodicJob(200, OnTimer, $"{Module}.OnTimer", true);
             return true;
         }
         /// <summary>
@@ -318,7 +322,7 @@ namespace CyberX8_RT.Devices.Facilities
             DATA.Subscribe($"{Module}.{Name}.{ARS_FLUID_DETECT}", () => _arsFluidDetect, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.{Name}.{PROCESS_FLUID_DETECT}", () => _processFluidDetect, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.{Name}.{SAMPLE_FLUID_DETECT}", () => _sampleFluidDetect, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.{Name}.{CDA_1_PRESSURE_VALUE}", ()=> _facilitiesDataDic[CDA_1_PRESSURE_VALUE].Value, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.{Name}.{CDA_1_PRESSURE_VALUE}", () => _facilitiesDataDic[CDA_1_PRESSURE_VALUE].Value, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.{Name}.{CDA_2_PRESSURE_VALUE}", () => _facilitiesDataDic[CDA_2_PRESSURE_VALUE].Value, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.{Name}.{N2_1A_PRESSURE_VALUE}", () => _facilitiesDataDic[N2_1A_PRESSURE_VALUE].Value, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.{Name}.{N2_1B_PRESSURE_VALUE}", () => _facilitiesDataDic[N2_1B_PRESSURE_VALUE].Value, SubscriptionAttribute.FLAG.IgnoreSaveDB);
@@ -401,7 +405,7 @@ namespace CyberX8_RT.Devices.Facilities
             OP.Subscribe($"{Module}.{Name}.N2Enable", N2EnableOperation);
             OP.Subscribe($"{Module}.{Name}.N2Disable", N2DisableOperation);
             OP.Subscribe($"{Module}.{Name}.CDAEnable", CDAEnableOperation);
-            OP.Subscribe($"{Module}.{Name}.CDADisable",CDADisableOperation);
+            OP.Subscribe($"{Module}.{Name}.CDADisable", CDADisableOperation);
             OP.Subscribe($"{Module}.{Name}.ExternalCDAEnable", ExternalCDAEnableOperation);
             OP.Subscribe($"{Module}.{Name}.ExternalCDADisable", ExternalCDADisableOperation);
             OP.Subscribe($"{Module}.{Name}.DiWaterEnable", DiWaterEnableOperation);
@@ -429,7 +433,7 @@ namespace CyberX8_RT.Devices.Facilities
             {
                 _variableInitializeDic[variable] = true;
             }
-            switch(variable)
+            switch (variable)
             {
                 case N2_ENABLE:
                     _n2Enabled = (bool)value;
@@ -438,7 +442,7 @@ namespace CyberX8_RT.Devices.Facilities
                     _cdaEnable = (bool)value;
                     break;
                 case EXTERNAL_CDA_ENABLE:
-                    _externalCDAEnable  = (bool)value;
+                    _externalCDAEnable = (bool)value;
                     break;
                 case DI_WATER_ENABLE:
                     _diWaterEnable = (bool)value;
@@ -456,7 +460,7 @@ namespace CyberX8_RT.Devices.Facilities
                     _loaderDiEnable = (bool)value;
                     break;
                 case FILTER_PURGE_ENABLE:
-                    _filterPurgeEnable= (bool)value;
+                    _filterPurgeEnable = (bool)value;
                     break;
                 case N2_1A_PRESSURE_VALUE:
                 case N2_2A_PRESSURE_VALUE:
@@ -472,40 +476,40 @@ namespace CyberX8_RT.Devices.Facilities
                     _facilitiesDataDic[variable].Value = (double)value;
                     break;
                 case N2_BLANKET_PRESSURE_VALUE:
-                    _n2BlaketPressure=(double)value;
+                    _n2BlaketPressure = (double)value;
                     break;
                 case SAMPLE_ENABLE:
-                    _sampleEnable= (bool)value;
+                    _sampleEnable = (bool)value;
                     break;
                 case SAMPLE_FLOW_1_ENABLE:
-                    _sampleFlow1Enable=(bool)value;
+                    _sampleFlow1Enable = (bool)value;
                     break;
                 case SAMPLE_FLOW_2_ENABLE:
-                    _sampleFlow2Enable=(bool)value;
+                    _sampleFlow2Enable = (bool)value;
                     break;
                 case SAMPLE_FLOW_3_ENABLE:
-                    _sampleFlow3Enable=(bool)value;
+                    _sampleFlow3Enable = (bool)value;
                     break;
                 case SAMPLE_FLOW_4_ENABLE:
-                    _sampleFlow4Enable=(bool)value;
+                    _sampleFlow4Enable = (bool)value;
                     break;
                 case FFU_LOADER_ERROR:
-                    _ffuLoaderError= (bool)value; 
+                    _ffuLoaderError = (bool)value;
                     break;
                 case FFU_PROCESS_ERROR:
-                    _ffuProcessError= (bool)value;
+                    _ffuProcessError = (bool)value;
                     break;
                 case FFU_LOADER_PRESSURE:
                     _ffuLoaderPressure = (double)value;
                     break;
                 case FFU_PROCESS_PRESSURE:
-                    _ffuProcessPressure= (double)value;
+                    _ffuProcessPressure = (double)value;
                     break;
                 case ARS_FLUID_DETECT:
-                    _arsFluidDetect=(bool)value;
+                    _arsFluidDetect = (bool)value;
                     break;
                 case SAMPLE_FLUID_DETECT:
-                    _sampleFluidDetect= (bool)value;
+                    _sampleFluidDetect = (bool)value;
                     if (!_sampleFluidDetect)
                     {
                         LOG.WriteLog(eEvent.WARN_Sensor, Module, "SampleFluidDetect is Activate");
@@ -514,8 +518,8 @@ namespace CyberX8_RT.Devices.Facilities
                     }
                     break;
                 case PROCESS_FLUID_DETECT:
-                    _processFluidDetect= (bool)value;
-                    if(!_processFluidDetect)
+                    _processFluidDetect = (bool)value;
+                    if (!_processFluidDetect)
                     {
                         LOG.WriteLog(eEvent.WARN_Sensor, Module, "ProcessFluidDetect is Activate");
                         AlarmListManager.Instance.AddWarn(Module, "ProcessFluidDetect", $"ProcessFluidDetect is Activate");
@@ -549,7 +553,7 @@ namespace CyberX8_RT.Devices.Facilities
         /// <param name="cmd"></param>
         /// <param name="param"></param>
         /// <returns></returns>
-        public bool N2EnableOperation(string cmd,object param)
+        public bool N2EnableOperation(string cmd, object param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Name}.{N2_ENABLE}");
             if (!string.IsNullOrEmpty(ioName))
@@ -876,7 +880,7 @@ namespace CyberX8_RT.Devices.Facilities
         /// 检验Exhaust
         /// </summary>
         /// <returns></returns>
-        public (bool result,string reason) CheckExhaustResult()
+        public (bool result, string reason) CheckExhaustResult()
         {
             return CheckPressureData(EXHAUST_PRESSURE_VALUE);
         }
@@ -892,7 +896,7 @@ namespace CyberX8_RT.Devices.Facilities
         /// 检验CDA
         /// </summary>
         /// <returns></returns>
-        public (bool result,string reason) CheckCDA()
+        public (bool result, string reason) CheckCDA()
         {
             if (!CDAEnable)
             {
@@ -918,7 +922,7 @@ namespace CyberX8_RT.Devices.Facilities
         /// 检验CDA和N2
         /// </summary>
         /// <returns></returns>
-        public (bool result,string reason) CheckCDAN2()
+        public (bool result, string reason) CheckCDAN2()
         {
             if (!CDAEnable)
             {
@@ -971,54 +975,54 @@ namespace CyberX8_RT.Devices.Facilities
         /// 检验CDA N2以及Vacuum状态
         /// </summary>
         /// <returns></returns>
-        public (bool result,string reason) CheckCDAN2AndVacuum()
+        public (bool result, string reason) CheckCDAN2AndVacuum()
         {
-            if(!CDAEnable)
+            if (!CDAEnable)
             {
-                return (false,"CDA is disable");
+                return (false, "CDA is disable");
             }
             else
             {
                 var cda1Result = CheckPressureData(CDA_1_PRESSURE_VALUE);
-                if(!cda1Result.result)
+                if (!cda1Result.result)
                 {
                     return cda1Result;
                 }
-                var cda2Result=CheckPressureData(CDA_2_PRESSURE_VALUE);
-                if(!cda2Result.result)
+                var cda2Result = CheckPressureData(CDA_2_PRESSURE_VALUE);
+                if (!cda2Result.result)
                 {
                     return cda2Result;
                 }
             }
 
-            if(!N2Enable)
+            if (!N2Enable)
             {
                 return (false, "N2 is disable");
             }
             else
             {
                 var n21AResult = CheckPressureData(N2_1A_PRESSURE_VALUE);
-                if(!n21AResult.result)
+                if (!n21AResult.result)
                 {
                     return n21AResult;
                 }
                 var n21BResult = CheckPressureData(N2_1B_PRESSURE_VALUE);
-                if(!n21BResult.result)
+                if (!n21BResult.result)
                 {
                     return n21BResult;
                 }
                 var n22AResult = CheckPressureData(N2_2A_PRESSURE_VALUE);
-                if(!n22AResult.result)
+                if (!n22AResult.result)
                 {
                     return n22AResult;
                 }
-                var n22BResult=CheckPressureData(N2_2B_PRESSURE_VALUE);
-                if(!n22BResult.result)
+                var n22BResult = CheckPressureData(N2_2B_PRESSURE_VALUE);
+                if (!n22BResult.result)
                 {
                     return n22BResult;
                 }
                 var vacuumResult = CheckPressureData(VACUUM_PRESSURE_VALUE);
-                if(!vacuumResult.result)
+                if (!vacuumResult.result)
                 {
                     return vacuumResult;
                 }
@@ -1031,16 +1035,16 @@ namespace CyberX8_RT.Devices.Facilities
         /// </summary>
         /// <param name="pressureName"></param>
         /// <returns></returns>
-        private (bool result,string reason) CheckPressureData(string pressureName)
+        private (bool result, string reason) CheckPressureData(string pressureName)
         {
             if (_facilitiesDataDic.ContainsKey(pressureName))
             {
-                CommonLimitData facilitiesData = _facilitiesDataDic[(pressureName)];    
-                if(facilitiesData.IsError)
+                CommonLimitData facilitiesData = _facilitiesDataDic[(pressureName)];
+                if (facilitiesData.IsError)
                 {
                     return (false, $"{pressureName} data {facilitiesData.Value} is error value");
                 }
-                else if(facilitiesData.IsWarning)
+                else if (facilitiesData.IsWarning)
                 {
                     return (true, $"{pressureName} data {facilitiesData.Value} is warning");
                 }
@@ -1061,7 +1065,7 @@ namespace CyberX8_RT.Devices.Facilities
         /// <returns></returns>
         public CommonLimitData GetCommonLimitDataByName(string name)
         {
-            return _facilitiesDataDic.ContainsKey(name)?_facilitiesDataDic[name]:null;
+            return _facilitiesDataDic.ContainsKey(name) ? _facilitiesDataDic[name] : null;
         }
 
         #region IDevice接口

+ 101 - 69
CyberX8_RT/Devices/Metal/CompactMembranMetalDevice.cs

@@ -11,8 +11,6 @@ using MECF.Framework.Common.CommonData;
 using MECF.Framework.Common.CommonData.Metal;
 using MECF.Framework.Common.Persistent.Reservoirs;
 using MECF.Framework.Common.TwinCat;
-using CyberX8_Core;
-using CyberX8_RT.Devices.Prewet;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -21,10 +19,12 @@ using System.Reflection;
 using System.Text;
 using System.Threading.Tasks;
 using MECF.Framework.Common.ToolLayout;
-using CyberX8_RT.Devices.Reservoir;
 using MECF.Framework.Common.Layout;
 using Aitex.Core.RT.SCCore;
 using System.Diagnostics;
+using CyberX8_Core;
+using CyberX8_RT.Devices.Metal;
+using CyberX8_RT.Devices.Reservoir;
 using MECF.Framework.Common.IOCore;
 
 namespace CyberX8_RT.Devices.Metal
@@ -49,7 +49,7 @@ namespace CyberX8_RT.Devices.Metal
         #region 常量 
         private const string SIDE_A = "SideA";
         private const string SIDE_B = "SideB";
-        private const string AN_A_PINENABLE="ANAPinEnable";
+        private const string AN_A_PINENABLE = "ANAPinEnable";
         private const string AN_B_PINENABLE = "ANBPinEnable";
         private const string AN_A_POUTENABLE = "ANAPoutEnable";
         private const string AN_B_POUTENABLE = "ANBPoutEnable";
@@ -72,7 +72,7 @@ namespace CyberX8_RT.Devices.Metal
         /// <summary>
         /// 设备数据
         /// </summary>
-        private CompactMembranMetalDeviceData _metalDeviceData =new CompactMembranMetalDeviceData();
+        private CompactMembranMetalDeviceData _metalDeviceData = new CompactMembranMetalDeviceData();
         /// <summary>
         /// 变量是否初始化字典
         /// </summary>
@@ -125,6 +125,14 @@ namespace CyberX8_RT.Devices.Metal
         /// Flow Valve计时
         /// </summary>
         private Stopwatch _flowValveStopWatch = new Stopwatch();
+        /// <summary>
+        /// ANA Flow Valve计时
+        /// </summary>
+        private Stopwatch _anaFlowValveStopWatch = new Stopwatch();
+        /// <summary>
+        /// ANB Flow Valve计时
+        /// </summary>
+        private Stopwatch _anbFlowValveStopWatch = new Stopwatch();
         #endregion
 
         #region 属性
@@ -144,6 +152,14 @@ namespace CyberX8_RT.Devices.Metal
         /// Flow Valve稳定状态
         /// </summary>
         public bool FlowValveStable { get { return _metalDeviceData.CellFlowValve && _flowValveStopWatch.ElapsedMilliseconds >= 3000; } }
+        /// <summary>
+        /// ANA Flow 稳定状态
+        /// </summary>
+        public bool ANAFlowValveStable { get { return _metalDeviceData.ANAPinEnable && _anaFlowValveStopWatch.ElapsedMilliseconds >= 3000; } }
+        /// <summary>
+        /// ANB Flow 稳定状态
+        /// </summary>
+        public bool ANBFlowValveStable { get { return _metalDeviceData.ANBPinEnable && _anbFlowValveStopWatch.ElapsedMilliseconds >= 3000; } }
         #endregion
 
         /// <summary>
@@ -153,7 +169,7 @@ namespace CyberX8_RT.Devices.Metal
         public CompactMembranMetalDevice(string moduleName) : base(moduleName)
         {
         }
-        
+
         /// <summary>
         /// 初始化
         /// </summary>
@@ -171,8 +187,8 @@ namespace CyberX8_RT.Devices.Metal
         /// </summary>
         private void InitializeRoutine()
         {
-            _anANACellFillRoutine = new CompactMembranFillRoutine(Module,"A");
-            _anANBCellFillRoutine = new CompactMembranFillRoutine(Module,"B");
+            _anANACellFillRoutine = new CompactMembranFillRoutine(Module, "A");
+            _anANBCellFillRoutine = new CompactMembranFillRoutine(Module, "B");
         }
         /// <summary>
         /// 订阅数据
@@ -180,12 +196,12 @@ namespace CyberX8_RT.Devices.Metal
         private void SubscribeData()
         {
             DATA.Subscribe($"{Module}.MetalData", () => _metalDeviceData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.SideAFlow",()=>ANACellFlow.CounterValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.SideAFlow", () => ANACellFlow.CounterValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.SideAFlowStatus", () => ANACellFlow.Status, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.SideBFlow", () => ANBCellFlow.CounterValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.SideBFlowStatus",()=>ANBCellFlow.Status, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.CellFlow",()=>MetalDeviceData.CellFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ANBPinEnable",()=>_metalDeviceData.ANBPinEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.SideBFlowStatus", () => ANBCellFlow.Status, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.CellFlow", () => MetalDeviceData.CellFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.ANBPinEnable", () => _metalDeviceData.ANBPinEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.ANAPinEnable", () => _metalDeviceData.ANAPinEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.ANAPoutEnable", () => _metalDeviceData.ANAPoutEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.ANBPoutEnable", () => _metalDeviceData.ANBPoutEnable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
@@ -207,13 +223,13 @@ namespace CyberX8_RT.Devices.Metal
             BeckhoffIoSubscribeUpdateVariable(WH_UNCLAMP);
             BeckhoffIoSubscribeUpdateVariable(CELL_FLOW_VALVE);
 
-            BeckhoffCounterSubscribeUpdateVariable(AN_A_CELL_FLOW,ANACellFlow);
+            BeckhoffCounterSubscribeUpdateVariable(AN_A_CELL_FLOW, ANACellFlow);
             BeckhoffCounter anACellFlowCounter = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_A_CELL_FLOW}");
-            if(anACellFlowCounter!=null)
+            if (anACellFlowCounter != null)
             {
                 ANACellFlow.Period = anACellFlowCounter.Period;
             }
-            BeckhoffCounterSubscribeUpdateVariable(AN_B_CELL_FLOW,ANBCellFlow);
+            BeckhoffCounterSubscribeUpdateVariable(AN_B_CELL_FLOW, ANBCellFlow);
             BeckhoffCounter anBCellFlowCounter = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_B_CELL_FLOW}");
             if (anACellFlowCounter != null)
             {
@@ -226,7 +242,7 @@ namespace CyberX8_RT.Devices.Metal
         protected override void InitializeOperation()
         {
             base.InitializeOperation();
-            OP.Subscribe($"{Module}.ANAFillOn",AnSideAFillOn);
+            OP.Subscribe($"{Module}.ANAFillOn", AnSideAFillOn);
             OP.Subscribe($"{Module}.ANAFillOff", AnSideAFillOff);
             OP.Subscribe($"{Module}.ANBFillOn", AnSideBFillOn);
             OP.Subscribe($"{Module}.ANBFillOff", AnSideBFillOff);
@@ -294,13 +310,29 @@ namespace CyberX8_RT.Devices.Metal
                     _flowValveStopWatch.Restart();
                 }
             }
+            else if (variable == AN_A_PINENABLE)
+            {
+                bool bValue = (bool)value;
+                if (bValue)
+                {
+                    _anaFlowValveStopWatch.Restart();
+                }
+            }
+            else if (variable == AN_B_PINENABLE)
+            {
+                bool bValue = (bool)value;
+                if (bValue)
+                {
+                    _anbFlowValveStopWatch.Restart();
+                }
+            }
         }
 
         /// <summary>
         /// 订阅Counter变量
         /// </summary>
         /// <param name="variable"></param>
-        private void BeckhoffCounterSubscribeUpdateVariable(string variable,CounterFlowData counterFlowData)
+        private void BeckhoffCounterSubscribeUpdateVariable(string variable, CounterFlowData counterFlowData)
         {
             _nameCounterFlowData[$"{Module}.{variable}"] = counterFlowData;
             BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_VALUE, UpdateCounterVariableValue);
@@ -320,7 +352,7 @@ namespace CyberX8_RT.Devices.Metal
             string lastVariable = strAry[strAry.Length - 1];
             PropertyInfo property = null;
             string key = variable.Replace($".{lastVariable}", "");
-            if(_nameCounterFlowData.ContainsKey(key))
+            if (_nameCounterFlowData.ContainsKey(key))
             {
                 CounterFlowData counterFlowData = _nameCounterFlowData[key];
                 if (counterFlowData != null)
@@ -343,12 +375,12 @@ namespace CyberX8_RT.Devices.Metal
         /// <returns></returns>
         public bool AnSideAFillOn(string cmd, object[] param)
         {
-            string ioName= BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_PINENABLE}");
-            string countName= BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_CELL_FLOW}");
-            bool result= BeckhoffCounterManager.Instance.StartCounter(countName);
+            string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_PINENABLE}");
+            string countName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_CELL_FLOW}");
+            bool result = BeckhoffCounterManager.Instance.StartCounter(countName);
             if (result)
             {
-                return IOModuleManager.Instance.WriteIoValue(ioName, true);
+                return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
             }
             else
             {
@@ -366,12 +398,12 @@ namespace CyberX8_RT.Devices.Metal
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_PINENABLE}");
             string countName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_CELL_FLOW}");
             bool result = BeckhoffCounterManager.Instance.StopCounter(countName);
-            if(result)
+            if (result)
             {
-                result= BeckhoffCounterManager.Instance.ResetCounter(countName,0);
-                if(result)
+                result = BeckhoffCounterManager.Instance.ResetCounter(countName, 0);
+                if (result)
                 {
-                    return IOModuleManager.Instance.WriteIoValue(ioName, false);
+                    return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
                 }
             }
             return false;
@@ -390,7 +422,7 @@ namespace CyberX8_RT.Devices.Metal
             bool result = BeckhoffCounterManager.Instance.StartCounter(countName);
             if (result)
             {
-                return IOModuleManager.Instance.WriteIoValue(ioName, true);
+                return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
             }
             else
             {
@@ -413,7 +445,7 @@ namespace CyberX8_RT.Devices.Metal
                 result = BeckhoffCounterManager.Instance.ResetCounter(countName, 0);
                 if (result)
                 {
-                    return IOModuleManager.Instance.WriteIoValue(ioName, false);
+                    return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
                 }
             }
             return false;
@@ -430,7 +462,7 @@ namespace CyberX8_RT.Devices.Metal
         private bool AnSideADrainOn(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_POUTENABLE}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, true);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
         }
         /// <summary>
         /// AN A面Drain Off
@@ -441,7 +473,7 @@ namespace CyberX8_RT.Devices.Metal
         public bool AnSideADrainOff(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_POUTENABLE}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, false);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
         }
 
         /// <summary>
@@ -453,7 +485,7 @@ namespace CyberX8_RT.Devices.Metal
         private bool AnSideBDrainOn(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_POUTENABLE}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, true);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
         }
         /// <summary>
         /// AN A面Drain Off
@@ -464,7 +496,7 @@ namespace CyberX8_RT.Devices.Metal
         public bool AnSideBDrainOff(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_POUTENABLE}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, false);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
         }
         #endregion
 
@@ -478,7 +510,7 @@ namespace CyberX8_RT.Devices.Metal
         private bool WHClampOn(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, true);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
         }
 
         /// <summary>
@@ -490,7 +522,7 @@ namespace CyberX8_RT.Devices.Metal
         private bool WHClampOff(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, false);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
         }
         /// <summary>
         /// WH UnClamp On
@@ -501,7 +533,7 @@ namespace CyberX8_RT.Devices.Metal
         private bool WHUnClampOn(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, true);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
         }
 
         /// <summary>
@@ -513,7 +545,7 @@ namespace CyberX8_RT.Devices.Metal
         private bool WHUnClampOff(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, false);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
         }
         /// <summary>
         /// Wafer Holder Clamp On
@@ -524,11 +556,11 @@ namespace CyberX8_RT.Devices.Metal
         public bool WaferHolderClampOn(string cmd, object[] param)
         {
             string unclampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
-            bool result = IOModuleManager.Instance.WriteIoValue(unclampIOName, false);
-            if(result)
+            bool result = BeckhoffIOManager.Instance.WriteIoValue(unclampIOName, false);
+            if (result)
             {
-                string clampIOName= BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
-                return IOModuleManager.Instance.WriteIoValue(clampIOName, true);
+                string clampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
+                return BeckhoffIOManager.Instance.WriteIoValue(clampIOName, true);
             }
             return false;
         }
@@ -541,11 +573,11 @@ namespace CyberX8_RT.Devices.Metal
         public bool WaferHolderUnclampOn(string cmd, object[] param)
         {
             string clampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
-            bool result = IOModuleManager.Instance.WriteIoValue(clampIOName, false);
+            bool result = BeckhoffIOManager.Instance.WriteIoValue(clampIOName, false);
             if (result)
             {
                 string unclampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
-                return IOModuleManager.Instance.WriteIoValue(unclampIOName, true);
+                return BeckhoffIOManager.Instance.WriteIoValue(unclampIOName, true);
             }
             return false;
         }
@@ -558,11 +590,11 @@ namespace CyberX8_RT.Devices.Metal
         public bool WaferHolderDisConnect(string cmd, object[] param)
         {
             string clampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
-            bool result = IOModuleManager.Instance.WriteIoValue(clampIOName, false);
+            bool result = BeckhoffIOManager.Instance.WriteIoValue(clampIOName, false);
             if (result)
             {
                 string unclampIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_UNCLAMP}");
-                return IOModuleManager.Instance.WriteIoValue(unclampIOName, false);
+                return BeckhoffIOManager.Instance.WriteIoValue(unclampIOName, false);
             }
             return false;
         }
@@ -578,7 +610,7 @@ namespace CyberX8_RT.Devices.Metal
         public bool CellFlowValveOn(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CELL_FLOW_VALVE}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, true);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
         }
         /// <summary>
         /// Cell Flow Off
@@ -589,7 +621,7 @@ namespace CyberX8_RT.Devices.Metal
         public bool CellFlowValveOff(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CELL_FLOW_VALVE}");
-            return IOModuleManager.Instance.WriteIoValue(ioName, false);
+            return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
         }
         #endregion
 
@@ -602,7 +634,7 @@ namespace CyberX8_RT.Devices.Metal
         /// <returns></returns>
         private bool ANSideAFillOperation(string cmd, object[] objects)
         {
-            if(_currentANACellOperation!=ANCellOperation.None)
+            if (_currentANACellOperation != ANCellOperation.None)
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} current is {_currentANACellOperation},cannot execute AN Side A Fill");
                 return false;
@@ -653,7 +685,7 @@ namespace CyberX8_RT.Devices.Metal
 
             bool result = true;
             CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice();
-            if(CheckOtherMetalDeviceDrainStatus(reservoirDevice,"A"))
+            if (CheckOtherMetalDeviceDrainStatus(reservoirDevice, "A"))
             {
                 return false;
             }
@@ -668,7 +700,7 @@ namespace CyberX8_RT.Devices.Metal
                 {
                     ANACellFlow.Status = ANCellStatus.Emptying.ToString();
                     _anATotalFillFlow = 0;
-                    _anADrainTime=DateTime.Now;
+                    _anADrainTime = DateTime.Now;
                 }
                 else
                 {
@@ -683,23 +715,23 @@ namespace CyberX8_RT.Devices.Metal
         /// <param name="reservoirDevice"></param>
         /// <param name="side"></param>
         /// <returns></returns>
-        private bool CheckOtherMetalDeviceDrainStatus(CompactMembranReservoirDevice reservoirDevice,string side)
+        private bool CheckOtherMetalDeviceDrainStatus(CompactMembranReservoirDevice reservoirDevice, string side)
         {
-            if(reservoirDevice==null)
+            if (reservoirDevice == null)
             {
                 return false;
             }
             ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(reservoirDevice.Module);
-            if(reservoirItem!=null)
+            if (reservoirItem != null)
             {
-                foreach(var item in reservoirItem.MetalCells)
+                foreach (var item in reservoirItem.MetalCells)
                 {
-                    if(item.ModuleName!=Module)
+                    if (item.ModuleName != Module)
                     {
                         CompactMembranMetalDevice metalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(item.ModuleName);
-                        if(metalDevice!=null)
+                        if (metalDevice != null)
                         {
-                            if(side=="A"&&metalDevice.MetalDeviceData.ANAPoutEnable)
+                            if (side == "A" && metalDevice.MetalDeviceData.ANAPoutEnable)
                             {
                                 LOG.WriteLog(eEvent.ERR_METAL, Module, $"{item.ModuleName} A Drain is on");
                                 return true;
@@ -735,9 +767,9 @@ namespace CyberX8_RT.Devices.Metal
             {
                 return false;
             }
-            if(reservoirDevice!=null&&reservoirDevice.ReservoirData.ANBDrainPump==0)
+            if (reservoirDevice != null && reservoirDevice.ReservoirData.ANBDrainPump == 0)
             {
-                result= reservoirDevice.AnBDrainPumpOn("", null);
+                result = reservoirDevice.AnBDrainPumpOn("", null);
             }
             if (result)
             {
@@ -746,7 +778,7 @@ namespace CyberX8_RT.Devices.Metal
                 {
                     ANBCellFlow.Status = ANCellStatus.Emptying.ToString();
                     _anBTotalFillFlow = 0;
-                    _anBDrainTime=DateTime.Now;
+                    _anBDrainTime = DateTime.Now;
                 }
                 else
                 {
@@ -785,7 +817,7 @@ namespace CyberX8_RT.Devices.Metal
             if (MetalDeviceData.ANAPoutEnable)
             {
                 AnSideADrainOff("", null);
-            }            
+            }
             ANACellFlow.Status = ANCellStatus.Unknow.ToString();
             _anATotalFillFlow = 0;
             return true;
@@ -805,16 +837,16 @@ namespace CyberX8_RT.Devices.Metal
                 {
                     reservoirDevice.AnPump(0);
                 }
-                if(reservoirDevice.ReservoirData.ANBDrainPump!=0)
+                if (reservoirDevice.ReservoirData.ANBDrainPump != 0)
                 {
                     reservoirDevice.AnBDrainPump(0);
                 }
             }
-            if(MetalDeviceData.ANBPinEnable)
+            if (MetalDeviceData.ANBPinEnable)
             {
                 AnSideBFillOff("", null);
             }
-            if(MetalDeviceData.ANBPoutEnable)
+            if (MetalDeviceData.ANBPoutEnable)
             {
                 AnSideBDrainOff("", null);
             }
@@ -842,11 +874,11 @@ namespace CyberX8_RT.Devices.Metal
             //正在Filing
             if (ANACellFlow.Status == ANCellStatus.Filling.ToString())
             {
-                JudgeFillFull(ANACellFlow,interval,ref _anATotalFillFlow);
+                JudgeFillFull(ANACellFlow, interval, ref _anATotalFillFlow);
             }
             if (ANBCellFlow.Status == ANCellStatus.Filling.ToString())
             {
-                JudgeFillFull(ANBCellFlow,interval,ref _anBTotalFillFlow);
+                JudgeFillFull(ANBCellFlow, interval, ref _anBTotalFillFlow);
             }
 
             if (ANACellFlow.Status == ANCellStatus.Emptying.ToString())
@@ -865,7 +897,7 @@ namespace CyberX8_RT.Devices.Metal
         /// <param name="routine"></param>
         /// <param name="side"></param>
         /// <param name="operation"></param>
-        private void SideFillRoutineMonitor(IRoutine routine, string side,CounterFlowData counterFlowData, ref ANCellOperation operation)
+        private void SideFillRoutineMonitor(IRoutine routine, string side, CounterFlowData counterFlowData, ref ANCellOperation operation)
         {
             RState state = routine.Monitor();
             if (state == RState.Failed || state == RState.Timeout)
@@ -882,7 +914,7 @@ namespace CyberX8_RT.Devices.Metal
         /// <summary>
         /// 判定是否fill Full
         /// </summary>
-        private void JudgeFillFull(CounterFlowData counterFlowData,int interval,ref double totalFillFlow)
+        private void JudgeFillFull(CounterFlowData counterFlowData, int interval, ref double totalFillFlow)
         {
             double anodeFillVolume = SC.GetValue<double>($"Metal.AnodeFillVolume");
             totalFillFlow += counterFlowData.CounterValue / 60 * ((double)interval / 1000);
@@ -900,7 +932,7 @@ namespace CyberX8_RT.Devices.Metal
             if (side == "A")
             {
                 JudgeSideADrain(ANACellFlow, _anADrainTime);
-                if(ANACellFlow.Status==ANCellStatus.Empty.ToString())
+                if (ANACellFlow.Status == ANCellStatus.Empty.ToString())
                 {
                     CompactMembranReservoirDevice reservoirDevice = GetReservoirDevice();
                     if (reservoirDevice != null)
@@ -979,7 +1011,7 @@ namespace CyberX8_RT.Devices.Metal
             if (_metalDeviceData.CellFlowValve)
             {
                 CellFlowValveOff("", null);
-            }            
+            }
         }
         #region 设备接口
         public override void Monitor()

+ 49 - 24
CyberX8_RT/Devices/Metal/MetalCellDevice.cs

@@ -8,11 +8,8 @@ using CyberX8_Core;
 using CyberX8_RT.Devices.LinMot;
 using CyberX8_RT.Devices.PowerSupplier;
 using Aitex.Core.RT.OperationCenter;
-using CyberX8_RT.Modules.Reservoir;
 using CyberX8_RT.Modules;
 using CyberX8_RT.Modules.Metal;
-using CyberX8_RT.Modules.Dryer;
-using MECF.Framework.Common.Persistent.Dryer;
 
 namespace CyberX8_RT.Devices.Metal
 {
@@ -146,8 +143,8 @@ namespace CyberX8_RT.Devices.Metal
             {
                 LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Persistent Value Object is not exist");
             }
-            _metalItem=MetalItemManager.Instance.GetMetalItem(Module);
-            if(_metalItem!=null)
+            _metalItem = MetalItemManager.Instance.GetMetalItem(Module);
+            if (_metalItem != null)
             {
                 _sideAPowerSupplier = DEVICE.GetDevice<CellPowerSupplier>(_metalItem.PlatingPowerSupplyAID);
                 _sideBPowerSupplier = DEVICE.GetDevice<CellPowerSupplier>(_metalItem.PlatingPowerSupplyBID);
@@ -162,9 +159,9 @@ namespace CyberX8_RT.Devices.Metal
         {
             DATA.Subscribe($"{Module}.{PERSISTENT_VALUE}", () => _persistentValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.SideAPowerSupplierData", () => _sideAPowerSupplier.PowerSupplierData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.SideBPowerSupplierData", () => _sideBPowerSupplier.PowerSupplierData, SubscriptionAttribute.FLAG.IgnoreSaveDB); 
+            DATA.Subscribe($"{Module}.SideBPowerSupplierData", () => _sideBPowerSupplier.PowerSupplierData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.SideAPowerSupplier.ID", () => _sideAPowerSupplier.Module, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.SideAPowerSupplier.IsConnected", ()=>_sideAPowerSupplier.IsConnected, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.SideAPowerSupplier.IsConnected", () => _sideAPowerSupplier.IsConnected, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.SideAPowerSupplier.Voltage", () => _sideAPowerSupplier.PowerSupplierData.Voltage, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.SideAPowerSupplier.Current", () => _sideAPowerSupplier.PowerSupplierData.Current, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.SideAPowerSupplier.SetPoint", () => _sideAPowerSupplier.PowerSupplierData.SetPoint, SubscriptionAttribute.FLAG.IgnoreSaveDB);
@@ -183,7 +180,7 @@ namespace CyberX8_RT.Devices.Metal
             DATA.Subscribe($"{Module}.SideBPowerSupplier.Enable", () => _sideBPowerSupplier.PowerSupplierData.Enabled, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.Linmot.ID", () => _linmotAxis.Module, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.Linmot.IsMotorOn", () => _linmotAxis.IsMotorOn, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.Linmot.IsError", ()=>_linmotAxis.IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.Linmot.IsError", () => _linmotAxis.IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.Linmot.IsSwitchOn", () => _linmotAxis.IsSwitchOn, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.Linmot.CurveSpeed", () => _linmotAxis.CurveSpeed, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.Linmot.ErrorCode", () => _linmotAxis.ErrorCode, SubscriptionAttribute.FLAG.IgnoreSaveDB);
@@ -244,7 +241,7 @@ namespace CyberX8_RT.Devices.Metal
         {
             if (_linmotAxis != null)
             {
-                return _linmotAxis.ResetOperation("",false);
+                return _linmotAxis.ResetOperation("", false);
             }
             else
             {
@@ -260,7 +257,7 @@ namespace CyberX8_RT.Devices.Metal
         {
             if (_linmotAxis != null)
             {
-                return _linmotAxis.Status==RState.End;
+                return _linmotAxis.Status == RState.End;
             }
             else
             {
@@ -276,7 +273,7 @@ namespace CyberX8_RT.Devices.Metal
         {
             if (_linmotAxis != null)
             {
-                return _linmotAxis.Status == RState.Failed||_linmotAxis.Status==RState.Timeout;
+                return _linmotAxis.Status == RState.Failed || _linmotAxis.Status == RState.Timeout;
             }
             else
             {
@@ -289,7 +286,7 @@ namespace CyberX8_RT.Devices.Metal
         /// <returns></returns>
         public bool StopLinmot()
         {
-            if(_linmotAxis != null)
+            if (_linmotAxis != null)
             {
                 return _linmotAxis.StopOperation("", null);
             }
@@ -311,9 +308,20 @@ namespace CyberX8_RT.Devices.Metal
         {
             string currentOperation = "Disabled";
             MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(Module);
-            if (metalEntity == null || _persistentValue == null) return false;
-            if (_persistentValue.OperatingMode != "Disabled") metalEntity.EnterInit();
-            _persistentValue.OperatingMode = currentOperation;           
+            if (metalEntity != null && _persistentValue != null && _persistentValue.OperatingMode != currentOperation)
+            {
+                string preOperation = _persistentValue.OperatingMode;
+                if (metalEntity.IsBusy)
+                {
+                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} is Busy, can't switch to Disabled mode");
+                    return false;
+                }
+                metalEntity.EnterInit();
+                _persistentValue.OperatingMode = currentOperation;
+
+                LOG.WriteLog(eEvent.INFO_METAL, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
+            }
+
             MetalPersistentManager.Instance.UpdatePersistentValue(Module);
             return true;
         }
@@ -327,14 +335,20 @@ namespace CyberX8_RT.Devices.Metal
         {
             string currentOperation = "Manual";
             MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(Module);
-            if (metalEntity == null || _persistentValue == null) return false;
-            if (_persistentValue.OperatingMode == "Auto" && metalEntity.IsBusy)
+            if (metalEntity != null && _persistentValue != null && _persistentValue.OperatingMode != currentOperation)
             {
-                LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} is Busy, can't change to manual mode");
-                return false;
+                string preOperation = _persistentValue.OperatingMode;
+                if (metalEntity.IsBusy)
+                {
+                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} is Busy, can't switch to Manual mode");
+                    return false;
+                }
+                metalEntity.EnterInit();
+                _persistentValue.OperatingMode = currentOperation;
+
+                LOG.WriteLog(eEvent.INFO_METAL, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
             }
-            if (_persistentValue.OperatingMode != "Manual") metalEntity.EnterInit();
-            _persistentValue.OperatingMode = currentOperation;         
+
             MetalPersistentManager.Instance.UpdatePersistentValue(Module);
             return true;
         }
@@ -348,9 +362,20 @@ namespace CyberX8_RT.Devices.Metal
         {
             string currentOperation = "Auto";
             MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(Module);
-            if(metalEntity == null || _persistentValue == null) return false;
-            if (_persistentValue.OperatingMode != "Auto") metalEntity.EnterInit();          
-            _persistentValue.OperatingMode = currentOperation;
+            if (metalEntity != null && _persistentValue != null && _persistentValue.OperatingMode != currentOperation)
+            {
+                string preOperation = _persistentValue.OperatingMode;
+                if (metalEntity.IsBusy)
+                {
+                    LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} is Busy, can't switch to Auto mode");
+                    return false;
+                }
+                metalEntity.EnterInit();
+                _persistentValue.OperatingMode = currentOperation;
+
+                LOG.WriteLog(eEvent.INFO_METAL, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
+            }
+
             MetalPersistentManager.Instance.UpdatePersistentValue(Module);
             return true;
         }

+ 8 - 9
CyberX8_RT/Devices/Metal/StandardHotMetalDevice.cs

@@ -16,11 +16,10 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
 using System.Diagnostics;
 using MECF.Framework.Common.IOCore;
 
+
 namespace CyberX8_RT.Devices.Metal
 {
     public class StandardHotMetalDevice : MetalCellDevice
@@ -32,7 +31,7 @@ namespace CyberX8_RT.Devices.Metal
         }
         #region 常量 
         private const string PERSISTENT_VALUE = "PersistentValue";
-        private const string CELL_PUMP="CellPump";
+        private const string CELL_PUMP = "CellPump";
         private const string CELL_FLOW = "CellFlow";
         private const string WH_CLAMP = "WaferHolderClamp";
         private const string CIRCULATION = "Circulation";
@@ -41,7 +40,7 @@ namespace CyberX8_RT.Devices.Metal
         /// <summary>
         /// 设备数据
         /// </summary>
-        private StandardHotMetalDeviceData _metalDeviceData=new StandardHotMetalDeviceData();
+        private StandardHotMetalDeviceData _metalDeviceData = new StandardHotMetalDeviceData();
         /// <summary>
         /// 变量是否初始化字典
         /// </summary>
@@ -116,10 +115,10 @@ namespace CyberX8_RT.Devices.Metal
         private void SubscribeData()
         {
             DATA.Subscribe($"{Module}.MetalData", () => _metalDeviceData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.CellPumpEnable",()=>_metalDeviceData.CellPump, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.CellPumpEnable", () => _metalDeviceData.CellPump, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.WaferShuttleClamped", () => _metalDeviceData.WaferHolderClamp, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.CellFlow",()=>_metalDeviceData.CellFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.Circulation",()=>_metalDeviceData.Circulation, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.CellFlow", () => _metalDeviceData.CellFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.Circulation", () => _metalDeviceData.Circulation, SubscriptionAttribute.FLAG.IgnoreSaveDB);
         }
         /// <summary>
         /// 订阅变量数值发生变化
@@ -221,7 +220,7 @@ namespace CyberX8_RT.Devices.Metal
         /// <returns></returns>
         public bool PumpOff()
         {
-            if (_status == RState.Running&&_currentOperation==MetalOperation.CellPumpOn)
+            if (_status == RState.Running && _currentOperation == MetalOperation.CellPumpOn)
             {
                 IRoutine routine = GetCurrentRoutine();
                 if (routine != null)
@@ -241,7 +240,7 @@ namespace CyberX8_RT.Devices.Metal
         /// <param name="cmd"></param>
         /// <param name="param"></param>
         /// <returns></returns>
-        public bool WaferHolderClampOn(string cmd,object[] param)
+        public bool WaferHolderClampOn(string cmd, object[] param)
         {
             string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{WH_CLAMP}");
             return IOModuleManager.Instance.WriteIoValue(ioName, true);

File diff suppressed because it is too large
+ 631 - 264
CyberX8_RT/Devices/Reservoir/CompactMembranReservoirDevice.cs


+ 14 - 13
CyberX8_RT/Devices/Reservoir/ReservoirDiReplenHelper.cs

@@ -33,7 +33,7 @@ namespace CyberX8_RT.Devices.Reservoir
         /// <param name="module"></param>
         /// <param name="persistentValue"></param>
         /// <param name="resRecipe"></param>
-        public ReservoirDiReplenHelper(string module,ReservoirsPersistentValue persistentValue)
+        public ReservoirDiReplenHelper(string module, ReservoirsPersistentValue persistentValue)
         {
             _module = module;
             _persistentValue = persistentValue;
@@ -61,16 +61,16 @@ namespace CyberX8_RT.Devices.Reservoir
         /// <summary>
         /// 监控手动注水
         /// </summary>
-        public bool MonitorManualDiReplenComplete(int replenSecond, Func<string, object[],bool> direplenOffAction)
+        public bool MonitorManualDiReplenComplete(int replenSecond, Func<string, object[], bool> direplenOffAction)
         {
             lock (_locker)
             {
                 _persistentValue.TotalReplen = _persistentValue.LastTotalReplen + (int)DateTime.Now.Subtract(_persistentValue.DiReplenTime).TotalSeconds;
             }
-            if(DateTime.Now.Subtract(_persistentValue.DiReplenTime).TotalSeconds >= replenSecond)
+            if (DateTime.Now.Subtract(_persistentValue.DiReplenTime).TotalSeconds >= replenSecond)
             {
-                bool result = direplenOffAction("",null);
-                if(result)
+                bool result = direplenOffAction("", null);
+                if (result)
                 {
                     _persistentValue.LastTotalReplen = _persistentValue.TotalReplen;
                     _persistentValue.IsDiReplenOn = false;
@@ -89,15 +89,15 @@ namespace CyberX8_RT.Devices.Reservoir
         {
             lock (_locker)
             {
-                _persistentValue.TotalReplen = _persistentValue.LastTotalReplen+(int)DateTime.Now.Subtract(_persistentValue.DiReplenTime).TotalSeconds;
+                _persistentValue.TotalReplen = _persistentValue.LastTotalReplen + (int)DateTime.Now.Subtract(_persistentValue.DiReplenTime).TotalSeconds;
             }
             double diValveMaxOnTimePerFill = SC.GetValue<double>($"Reservoir.{_module}.DIValveMaxOnTimePerFill");
-            if(DateTime.Now.Subtract(_persistentValue.DiReplenTime).TotalSeconds >= diValveMaxOnTimePerFill * 60)
+            if (DateTime.Now.Subtract(_persistentValue.DiReplenTime).TotalSeconds >= diValveMaxOnTimePerFill * 60)
             {
                 bool result = direplenOffAction("", null);
-                if(result)
+                if (result)
                 {
-                    LOG.WriteLog(eEvent.WARN_RESERVOIR, _module, $"Direplen time over {diValveMaxOnTimePerFill}");                    
+                    LOG.WriteLog(eEvent.WARN_RESERVOIR, _module, $"Direplen time over {diValveMaxOnTimePerFill} min");
                     _persistentValue.LastTotalReplen = _persistentValue.TotalReplen;
                     _persistentValue.IsDiReplenOn = false;
                     ReservoirsPersistentManager.Instance.UpdatePersistentValue(_module);
@@ -113,16 +113,17 @@ namespace CyberX8_RT.Devices.Reservoir
         /// <param name="recipeLevel"></param>
         /// <param name="direplenOffAction"></param>
         /// <returns></returns>
-        public bool AutoDiReplenMonitorComplete(double level,double recipeLevel,ResRecipe _recipe,Func<string, object[], bool> direplenOffAction)
+        public bool AutoDiReplenMonitorComplete(double level, double recipeLevel, bool replenEnable,
+            int direplenTimeRate, int direplenCurrentRate, Func<string, object[], bool> direplenOffAction)
         {
             double levelHysteresis = SC.GetValue<double>("Reservoir.LevelHysteresis");
             //按液位补水
-            if (_recipe.DIReplenEnable && _recipe.DIReplenTimeRate == 0 && _recipe.DIReplenCurrentRate == 0 &&
+            if (replenEnable && direplenTimeRate == 0 && direplenCurrentRate == 0 &&
                 level >= recipeLevel)
             {
                 LOG.WriteLog(eEvent.INFO_RESERVOIR, _module, "Auto replen complete");
-                bool result= direplenOffAction("",null);
-                if(result)
+                bool result = direplenOffAction("", null);
+                if (result)
                 {
                     _persistentValue.LastTotalReplen = _persistentValue.TotalReplen;
                     _persistentValue.IsDiReplenOn = false;

File diff suppressed because it is too large
+ 585 - 218
CyberX8_RT/Devices/Reservoir/StandardHotReservoirDevice.cs


+ 13 - 12
CyberX8_RT/Devices/Reservoir/TotalReservoirDevice.cs

@@ -18,6 +18,7 @@ using System.Threading.Tasks;
 using MECF.Framework.Common.ToolLayout;
 using CyberX8_RT.Modules.Reservoir;
 using CyberX8_RT.Modules;
+using CyberX8_RT.Devices.Reservoir;
 using MECF.Framework.Common.IOCore;
 
 namespace CyberX8_RT.Devices.Reservoir
@@ -33,7 +34,7 @@ namespace CyberX8_RT.Devices.Reservoir
         private const string COUNTER_RESET = "Reset";
 
         private const string EVAPORATOR_LEVEL = "EvaporatorLevel";
-        private const string HIGH_LEVEL="HighLevel";
+        private const string HIGH_LEVEL = "HighLevel";
         private const string STRATUS = "Stratus";
         #endregion
         #region 内部变量
@@ -110,7 +111,7 @@ namespace CyberX8_RT.Devices.Reservoir
         /// </summary>
         private void SubscribeValueAction()
         {
-            BeckhoffCounterSubscribeUpdateVariable(DIREPLEN_FLOW,DiReplenFlow);
+            BeckhoffCounterSubscribeUpdateVariable(DIREPLEN_FLOW, DiReplenFlow);
             BeckhoffIoSubscribeUpdateVariable(EVAPORATOR_LEVEL);
             BeckhoffIoSubscribeUpdateVariable(HIGH_LEVEL);
         }
@@ -145,13 +146,13 @@ namespace CyberX8_RT.Devices.Reservoir
         /// <param name="value"></param>
         private void UpdateIOVariableValue(string variable, object value)
         {
-            if(variable==HIGH_LEVEL)
+            if (variable == HIGH_LEVEL)
             {
-                _highLevel=(bool)value;
+                _highLevel = (bool)value;
             }
-            else if(variable==EVAPORATOR_LEVEL)
+            else if (variable == EVAPORATOR_LEVEL)
             {
-                _evaporatorLevel=(bool)value;
+                _evaporatorLevel = (bool)value;
             }
         }
         /// <summary>
@@ -184,18 +185,18 @@ namespace CyberX8_RT.Devices.Reservoir
             List<string> reservoirs = ReservoirItemManager.Instance.InstalledModules;
             foreach (string module in reservoirs)
             {
-                ReservoirItem reservoirItem=ReservoirItemManager.Instance.GetReservoirItem(module);
+                ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(module);
                 ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(module);
                 if (reservoirEntity != null)
                 {
-                    if(reservoirItem.SubType==STRATUS)
+                    if (reservoirItem.SubType == STRATUS)
                     {
                         StandardHotReservoirDevice reservoirDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(module);
-                        if(reservoirDevice.IsDireplenOn)
+                        if (reservoirDevice.IsDireplenOn)
                         {
                             break;
                         }
-                        if (reservoirDevice.NeedAutoDireplen&&!reservoirDevice.IsDireplenOn)
+                        if (reservoirDevice.NeedAutoDireplen && !reservoirDevice.IsDireplenOn)
                         {
                             reservoirDevice.AutoDireplen();
                         }
@@ -207,11 +208,11 @@ namespace CyberX8_RT.Devices.Reservoir
                         {
                             break;
                         }
-                        if(reservoirDevice.AnNeedDireplen&&!reservoirDevice.IsDireplenOn)
+                        if (reservoirDevice.AnNeedDireplen && !reservoirDevice.IsDireplenOn)
                         {
                             reservoirDevice.AutoANDiReplen();
                         }
-                        else if(reservoirDevice.CANeedDiReplen && !reservoirDevice.IsDireplenOn)
+                        else if (reservoirDevice.CANeedDiReplen && !reservoirDevice.IsDireplenOn)
                         {
                             reservoirDevice.AutoCADiReplen();
                         }

+ 7 - 21
CyberX8_RT/Devices/Temperature/TemperatureController.cs

@@ -509,28 +509,14 @@ namespace CyberX8_RT.Devices.Temperature
                     LOG.WriteLog(eEvent.ERR_TEMPERATURE, Module, $"{Module} reservoir is null");
                     return false;
                 }
-                bool result= reservoirDevice.ReservoirData.HedFlow > 0;
-                if (!result)
-                {
-                    LOG.WriteLog(eEvent.ERR_TEMPERATURE, Module, $"{Module} reservoir HED flow is 0");
-                }
-                return result;
-            }
-            else
-            {
-                CompactMembranReservoirDevice reservoirDevice = DEVICE.GetDevice<CompactMembranReservoirDevice>(reservoir);
-                if (reservoirDevice == null)
-                {
-                    LOG.WriteLog(eEvent.ERR_TEMPERATURE, Module, $"{Module} reservoir is null");
-                    return false;
-                }
-                bool result = reservoirDevice.ReservoirData.CAHedFlow > 0;
-                if (!result)
-                {
-                    LOG.WriteLog(eEvent.ERR_TEMPERATURE, Module, $"{Module} reservoir CA HED flow is 0");
-                }
-                return result;
+                //bool result= reservoirDevice.ReservoirData.Flow > 0;
+                //if (!result)
+                //{
+                //    LOG.WriteLog(eEvent.ERR_TEMPERATURE, Module, $"{Module} reservoir cell flow is 0");
+                //}
+                //return result;
             }
+            return true;
         }
         /// <summary>
         /// 设置Enable并设置温度

+ 334 - 78
CyberX8_RT/Modules/Metal/MetalEntity.cs

@@ -5,21 +5,28 @@ using Aitex.Core.Util;
 using Aitex.Core.Utilities;
 using MECF.Framework.Common.Equipment;
 using MECF.Framework.Common.WaferHolder;
-using CyberX8_Core;
+
 using System;
 using MECF.Framework.Common.ToolLayout;
 using MECF.Framework.Common.Persistent.Reservoirs;
-using CyberX8_RT.Modules.Reservoir;
+
 using Aitex.Core.RT.OperationCenter;
 using MECF.Framework.Common.RecipeCenter;
 using Aitex.Core.RT.RecipeCenter;
 using MECF.Framework.Common.SubstrateTrackings;
-using CyberX8_RT.Devices.Metal;
+
 using Aitex.Core.RT.Device;
-using CyberX8_RT.Devices.Reservoir;
+
 using MECF.Framework.Common.Routine;
 using MECF.Framework.Common.ProcessCell;
 using Aitex.Core.RT.SCCore;
+using MECF.Framework.Common.Alarm;
+using CyberX8_Core;
+using CyberX8_RT.Devices.Metal;
+using CyberX8_RT.Devices.Reservoir;
+using CyberX8_RT.Modules.Metal;
+using CyberX8_RT.Modules.Reservoir;
+using CyberX8_RT.Modules;
 
 namespace CyberX8_RT.Modules.Metal
 {
@@ -29,7 +36,7 @@ namespace CyberX8_RT.Modules.Metal
         private const string STRATUS = "Stratus";
         private const string AUTO = "Auto";
         private const string MANUAL = "Manual";
-        private const string DISABLED= "Disabled";
+        private const string DISABLED = "Disabled";
         private const string ENGINEERING = "Engineering";
         private const string PRODUCTION = "Production";
         #endregion
@@ -109,11 +116,11 @@ namespace CyberX8_RT.Modules.Metal
         /// <summary>
         /// 初始化状态
         /// </summary>
-        public bool IsInit {  get { return fsm.State == (int)MetalState.Init; } }
+        public bool IsInit { get { return fsm.State == (int)MetalState.Init; } }
         /// <summary>
         /// 空闲状态
         /// </summary>
-        public bool IsIdle { get {  return fsm.State == (int)MetalState.Idle; } }
+        public bool IsIdle { get { return fsm.State == (int)MetalState.Idle; } }
         /// <summary>
         /// 是否发生错误
         /// </summary>
@@ -121,7 +128,7 @@ namespace CyberX8_RT.Modules.Metal
         /// <summary>
         /// 是否正在作业
         /// </summary>
-        public bool IsBusy {  get { return fsm.State > (int)MetalState.Idle; } }
+        public bool IsBusy { get { return fsm.State > (int)MetalState.Idle; } }
         /// <summary>
         /// 是否初始化完成
         /// </summary>
@@ -133,7 +140,7 @@ namespace CyberX8_RT.Modules.Metal
         /// <summary>
         /// 自动模式
         /// </summary>
-        public bool IsAuto { get { return _persistentValue!=null&&_persistentValue.OperatingMode == AUTO; } }
+        public bool IsAuto { get { return _persistentValue != null && _persistentValue.OperatingMode == AUTO; } }
         /// <summary>
         /// 自动模式
         /// </summary>
@@ -177,12 +184,12 @@ namespace CyberX8_RT.Modules.Metal
                 {
                     return 0;
                 }
-                switch(fsm.State)
+                switch (fsm.State)
                 {
-                    case (int)MetalState.RunReciping:                        
-                        return Math.Max(_recipeTime - fsm.ElapsedTime/1000, 0);
+                    case (int)MetalState.RunReciping:
+                        return Math.Max(_recipeTime - fsm.ElapsedTime / 1000, 0);
                     default:
-                        return 0 ;
+                        return 0;
                 }
             }
         }
@@ -226,7 +233,7 @@ namespace CyberX8_RT.Modules.Metal
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Persistent Value Object is not exist");
             }
-            _metalItem=MetalItemManager.Instance.GetMetalItem(Module.ToString());
+            _metalItem = MetalItemManager.Instance.GetMetalItem(Module.ToString());
         }
         /// <summary>
         /// 初始化Routine
@@ -234,10 +241,10 @@ namespace CyberX8_RT.Modules.Metal
         private void InitializeRoutine()
         {
             _compactEmbranceInitializeRoutine = new CompactEmbranceInitializeRoutine(Module.ToString());
-            _standardHotInitializeRoutine=new StandardHotInitializeRoutine(Module.ToString());
-            _compactEmbranceRunRecipeRoutine=new CompactEmbranceRunRecipeRoutine(Module.ToString());
-            _standardHotRunRecipeRoutine=new StandardHotRunRecipeRoutine(Module.ToString());
-            _currentShortTestRoutine=new CurrentShortTestRoutine(Module.ToString());
+            _standardHotInitializeRoutine = new StandardHotInitializeRoutine(Module.ToString());
+            _compactEmbranceRunRecipeRoutine = new CompactEmbranceRunRecipeRoutine(Module.ToString());
+            _standardHotRunRecipeRoutine = new StandardHotRunRecipeRoutine(Module.ToString());
+            _currentShortTestRoutine = new CurrentShortTestRoutine(Module.ToString());
         }
         /// <summary>
         /// 初始化操作
@@ -245,7 +252,7 @@ namespace CyberX8_RT.Modules.Metal
         private void InitializeOperation()
         {
             OP.Subscribe($"{Module}.InitializeAll", (cmd, args) => { return CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Initialize); });
-            OP.Subscribe($"{Module}.CycleManualProcessRecipe", (cmd, args) => 
+            OP.Subscribe($"{Module}.CycleManualProcessRecipe", (cmd, args) =>
             {
                 DepRecipe recipe = RecipeFileManager.Instance.LoadGenericityRecipe<DepRecipe>(args[0].ToString());
                 if (recipe == null)
@@ -255,11 +262,11 @@ namespace CyberX8_RT.Modules.Metal
                 }
                 object[] objects = new object[args.Length];
                 objects[0] = recipe;
-                for(int i = 1; i < args.Length; i++)
+                for (int i = 1; i < args.Length; i++)
                 {
                     objects[i] = args[i];
                 }
-                return CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.RunRecipe,objects); 
+                return CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.RunRecipe, objects);
             });
             OP.Subscribe($"{Module}.CurrentShortTest", (cmd, args) => { return CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.CurrentShortTest); });
             OP.Subscribe($"{Module}.UpdateMetalUsage", UpdateMetalUsageAction);
@@ -286,7 +293,7 @@ namespace CyberX8_RT.Modules.Metal
             AnyStateTransition(MetalMsg.Error, EnterError, MetalState.Error);
             //Initialize
             AnyStateTransition(MetalMsg.Initialize, InitializeAll, MetalState.Initializing);
-            Transition(MetalState.Initializing,FSM_MSG.TIMER,InitializeAllMonitor, MetalState.Initialized);
+            Transition(MetalState.Initializing, FSM_MSG.TIMER, InitializeAllMonitor, MetalState.Initialized);
 
             //直接进入Idle
             Transition(MetalState.Initialized, FSM_MSG.TIMER, NullFunc, MetalState.Idle);
@@ -319,7 +326,7 @@ namespace CyberX8_RT.Modules.Metal
             DATA.Subscribe($"{Module}.FsmState", () => ((MetalState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.WaferHolder", () => WaferHolderInfo, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.AchievedCycle", () => AchievedCycle, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.IsInit", () => IsInit, SubscriptionAttribute.FLAG.IgnoreSaveDB); 
+            DATA.Subscribe($"{Module}.IsInit", () => IsInit, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.IsIdle", () => IsIdle, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.IsError", () => IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.IsBusy", () => IsBusy, SubscriptionAttribute.FLAG.IgnoreSaveDB);
@@ -344,31 +351,31 @@ namespace CyberX8_RT.Modules.Metal
             DATA.Subscribe($"{Module}.TotalTime", () => _recipeTime, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.TimeRemain", () => _recipeTime != 0 && _currentRunRecipeRoutine != null ? (_recipeTime - Math.Round((double)_currentRunRecipeRoutine.ElapsedMilliseconds / 1000, 0)) : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.Task", () => WaferHolderInfo != null ? WaferHolderInfo.CurrentControlJobId : "", SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.OperatingMode", () => _persistentValue != null ? _persistentValue.OperatingMode : "None", SubscriptionAttribute.FLAG.IgnoreSaveDB); 
+            DATA.Subscribe($"{Module}.OperatingMode", () => _persistentValue != null ? _persistentValue.OperatingMode : "None", SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.TotalUsage", () => MetalUsage != null ? MetalUsage.TotalUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.TotalUsage.WarningLimit", () => SC.GetValue<double>("Metal.MetalTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.TotalUsage.FaultLimit", () => SC.GetValue<double>("Metal.MetalTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeAUsage",()=> MetalUsage!=null?MetalUsage.AnodeAUsage:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeAUsage.WarningLimit", () => SC.GetValue<double>("Metal.AnodeATotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeAUsage.FaultLimit", () => SC.GetValue<double>("Metal.AnodeATotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeBUsage", () => MetalUsage != null ? MetalUsage.AnodeBUsage:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeBUsage.WarningLimit", () => SC.GetValue<double>("Metal.AnodeBTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeBUsage.FaultLimit", () => SC.GetValue<double>("Metal.AnodeBTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.MembranceAUsage",()=> MetalUsage != null ? MetalUsage.MembranceAUsage:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.MembranceAUsage.WarningLimit", () => SC.GetValue<double>("Metal.MembraneATotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.MembranceAUsage.FaultLimit", () => SC.GetValue<double>("Metal.MembraneATotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.MembranceBUsage", () => MetalUsage != null ? MetalUsage.MembranceBUsage:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.MembranceBUsage.WarningLimit", () => SC.GetValue<double>("Metal.MembraneBTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.MembranceBUsage.FaultLimit", () => SC.GetValue<double>("Metal.MembraneBTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.TotalWafers", () => MetalUsage != null ? MetalUsage.TotalWafers:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.TotalWafers.WarningLimit", () => SC.GetValue<int>("Metal.MetalTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.TotalWafers.FaultLimit", () => SC.GetValue<int>("Metal.MetalTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeAWafers",()=> MetalUsage != null ? MetalUsage.AnodeAWafers:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeAWafers.WarningLimit", () => SC.GetValue<int>("Metal.AnodeATotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeAWafers.FaultLimit", () => SC.GetValue<int>("Metal.AnodeATotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeBWafers", () => MetalUsage != null ? MetalUsage.AnodeBWafers:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeBWafers.WarningLimit", () => SC.GetValue<int>("Metal.AnodeBTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.AnodeBWafers.FaultLimit", () => SC.GetValue<int>("Metal.AnodeBTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.TotalUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.TotalUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeAUsage", () => MetalUsage != null ? MetalUsage.AnodeAUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeAUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeAUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeBUsage", () => MetalUsage != null ? MetalUsage.AnodeBUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeBUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeBUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.MembranceAUsage", () => MetalUsage != null ? MetalUsage.MembranceAUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.MembranceAUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.MembranceAUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.MembranceBUsage", () => MetalUsage != null ? MetalUsage.MembranceBUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.MembranceBUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.MembranceBUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.TotalWafers", () => MetalUsage != null ? MetalUsage.TotalWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.TotalWafers.WarningLimit", () => SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.TotalWafers.FaultLimit", () => SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeAWafers", () => MetalUsage != null ? MetalUsage.AnodeAWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeAWafers.WarningLimit", () => SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeAWafers.FaultLimit", () => SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeBWafers", () => MetalUsage != null ? MetalUsage.AnodeBWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeBWafers.WarningLimit", () => SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.AnodeBWafers.FaultLimit", () => SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
         }
         /// <summary>
         /// 进入错误状态
@@ -414,12 +421,12 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         private bool InitializeAll(object[] param)
         {
-            if (fsm.State ==(int)MetalState.Initializing)
+            if (fsm.State == (int)MetalState.Initializing)
             {
                 LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), "state is Initializing,cannot do initialize");
                 return false;
             }
-            if(!CheckReservoirInitialized())
+            if (!CheckReservoirInitialized())
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not initialized");
                 return false;
@@ -432,7 +439,7 @@ namespace CyberX8_RT.Modules.Metal
                     return false;
                 }
             }
-            if (_metalItem.SubType==STRATUS)
+            if (_metalItem.SubType == STRATUS)
             {
                 return _standardHotInitializeRoutine.Start(_persistentValue) == RState.Running;
             }
@@ -476,25 +483,25 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         private bool InitializeAllMonitor(object[] param)
         {
-            RState rsstate= RState.Running;
+            RState rsstate = RState.Running;
             if (_metalItem.SubType == STRATUS)
             {
                 rsstate = _standardHotInitializeRoutine.Monitor();
             }
             else
             {
-                rsstate = _compactEmbranceInitializeRoutine.Monitor() ;
+                rsstate = _compactEmbranceInitializeRoutine.Monitor();
             }
-            if(rsstate==RState.End)
+            if (rsstate == RState.End)
             {
                 return true;
             }
-            else if(rsstate==RState.Failed||rsstate==RState.Timeout)
+            else if (rsstate == RState.Failed || rsstate == RState.Timeout)
             {
                 PostMsg(MetalMsg.Error);
                 return false;
             }
-            return false; 
+            return false;
         }
         #endregion
 
@@ -506,6 +513,13 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         private bool RunRecipe(object[] param)
         {
+            MetalUsageMointor(); //Metal run recipe前检查PMCounter消耗
+            string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
+            if (_metalItem.SubType == STRATUS)
+            {
+                StandardHotReservoirDevice resDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
+                resDevice.ReservoirUsageMonitor();
+            }
             DepRecipe recipe = param[0] as DepRecipe;
             _recipeSide = param[1].ToString();
             _cycle = (int)param[2];
@@ -514,14 +528,14 @@ namespace CyberX8_RT.Modules.Metal
             if (_metalItem.SubType == STRATUS)
             {
                 _currentRunRecipeRoutine = _standardHotRunRecipeRoutine;
-                result= _standardHotRunRecipeRoutine.Start(recipe,_recipeSide) == RState.Running;
+                result = _standardHotRunRecipeRoutine.Start(recipe, _recipeSide) == RState.Running;
             }
             else
             {
                 _currentRunRecipeRoutine = _compactEmbranceRunRecipeRoutine;
-                result= _compactEmbranceRunRecipeRoutine.Start(recipe,_recipeSide) == RState.Running;
+                result = _compactEmbranceRunRecipeRoutine.Start(recipe, _recipeSide) == RState.Running;
             }
-            if(result)
+            if (result)
             {
                 if (WaferHolderInfo != null)
                 {
@@ -529,7 +543,7 @@ namespace CyberX8_RT.Modules.Metal
                 }
                 _recipeTime = recipe.CalculateRecipeTotalTime();
                 _currentRecipe = recipe;
-                if (WaferHolderInfo != null)
+                if (WaferHolderInfo != null && WaferHolderInfo.SchedulerModules != null && WaferHolderInfo.SchedulerModules.Count != 0)
                 {
                     LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"{WaferHolderInfo?.Id} {string.Join(",", WaferHolderInfo.SchedulerModules)}");
                 }
@@ -552,15 +566,43 @@ namespace CyberX8_RT.Modules.Metal
             if (_metalItem.SubType == STRATUS)
             {
                 rsstate = _standardHotRunRecipeRoutine.Monitor();
+                if (rsstate == RState.Running)
+                {
+                    StandardHotMetalDevice _standardHotMetalDevice = DEVICE.GetDevice<StandardHotMetalDevice>(Module.ToString());
+                    if (_standardHotMetalDevice.MetalDeviceData.CellFlow <= 0)
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir metal cell flow is 0");
+                        rsstate = RState.Failed;
+                    }
+                }
             }
             else
             {
                 rsstate = _compactEmbranceRunRecipeRoutine.Monitor();
+                if (rsstate == RState.Running)
+                {
+                    CompactMembranMetalDevice _compactMembranMetalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(Module.ToString());
+                    if (_compactMembranMetalDevice.MetalDeviceData.CellFlow <= 0)
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir metal cell flow is 0");
+                        rsstate = RState.Failed;
+                    }
+                    if (_compactMembranMetalDevice.ANACellFlow.CounterValue <= 0) //检查hold flow
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir AnodeA flow is 0");
+                        rsstate = RState.Failed;
+                    }
+                    if (_compactMembranMetalDevice.ANBCellFlow.CounterValue <= 0)
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir AnodeB flow is 0");
+                        rsstate = RState.Failed;
+                    }
+                }
             }
-            if (Singleton<RouteManager>.Instance.IsAutoRunning&&_runrecipeElapsedTime!=TimeToReady)
+            if (Singleton<RouteManager>.Instance.IsAutoRunning && _runrecipeElapsedTime != TimeToReady)
             {
                 _runrecipeElapsedTime = TimeToReady;
-                LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"{WaferHolderInfo?.Id} {Module} RunRecipe TimeToReady {TimeToReady}s.");                
+                LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"{WaferHolderInfo?.Id} {Module} RunRecipe TimeToReady {TimeToReady}s.");
             }
             if (rsstate == RState.End)
             {
@@ -570,17 +612,19 @@ namespace CyberX8_RT.Modules.Metal
                     double anodeAUsage = GetAnodeAUsage();
                     double anodeBUsage = GetAnodeBUsage();
                     MetalUsageManager.Instance.UpdateMetalUsage(Module.ToString(), _recipeSide, anodeAUsage, anodeBUsage);
+                    MetalUsageMointor(); //检查PMCounter消耗
                     //CMM Usage
-                    if(_metalItem.SubType == STRATUS)
+                    string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
+                    if (_metalItem.SubType == STRATUS)
                     {
-                        string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
                         StandardHotReservoirDevice resDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
+                        resDevice.ReservoirUsageMonitor();
                         resDevice.SetExportCMMUsage();
-                    }                    
+                    }
                     WaferHolderInfo.LastMetalRecipeCompleteTime = DateTime.Now;
                 }
                 _runrecipeElapsedTime = 0;
-                
+
                 //记录LotTrack
                 _runRecipeCompleteTime = DateTime.Now;
                 int timeLength = (int)(_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds;
@@ -600,7 +644,7 @@ namespace CyberX8_RT.Modules.Metal
                 {
                     FaModuleNotifier.Instance.NotifyWaferShuttleRecipeEnd(WaferHolderInfo, _currentRecipe.Ppid, timeLength);
                 }
-                    
+
                 return true;
             }
             else if (rsstate == RState.Failed || rsstate == RState.Timeout)
@@ -611,11 +655,13 @@ namespace CyberX8_RT.Modules.Metal
                     double anodeAUsage = GetAnodeAUsage();
                     double anodeBUsage = GetAnodeBUsage();
                     MetalUsageManager.Instance.UpdateMetalUsage(Module.ToString(), _recipeSide, anodeAUsage, anodeBUsage);
+                    MetalUsageMointor(); //失败了也要检查PMCounter消耗
                     //CMMUsage
+                    string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
                     if (_metalItem.SubType == STRATUS)
                     {
-                        string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
                         StandardHotReservoirDevice resDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
+                        resDevice.ReservoirUsageMonitor();
                         resDevice.SetExportCMMUsage();
                     }
                 }
@@ -649,18 +695,228 @@ namespace CyberX8_RT.Modules.Metal
             return false;
         }
         /// <summary>
+        /// 监控 PM Counter Metal用量
+        /// </summary>
+        private void MetalUsageMointor()
+        {
+            MetalUsage metalUsage = MetalUsageManager.Instance.GetMetalUsage(Module.ToString());
+            if (metalUsage != null)
+            {
+                //TotalAUsage
+                if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit") != 0)
+                {
+                    if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.TotalUsage",
+                            $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.TotalUsage",
+                            $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}");
+                    }
+                }
+
+                //AnodeAUsage
+                if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit") != 0)
+                {
+                    if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeAUsage",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeAUsage",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}");
+                    }
+                }
+
+                //AnodeBUsage
+                if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit") != 0)
+                {
+                    if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeBUsage",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeBUsage",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}");
+                    }
+                }
+
+                //MembraneAUsage
+                if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit") != 0)
+                {
+                    if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.MembraneAUsage",
+                            $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.MembraneAUsage",
+                            $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}");
+                    }
+                }
+
+                //MembraneBUsage
+                if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit") != 0)
+                {
+                    if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.MembraneBUsage",
+                            $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.MembraneBUsage",
+                            $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}");
+                    }
+                }
+
+                //TotalWafer
+                if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit") != 0)
+                {
+                    if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.TotalWafers",
+                            $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.TotalWafers",
+                            $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit")}");
+                    }
+                }
+
+                //AnodeAWafer
+                if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit") != 0)
+                {
+                    if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeAWafers",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeAWafers",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit")}");
+                    }
+                }
+
+                //AnodeBWafer
+                if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit") != 0)
+                {
+                    if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeBWafers",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeBWafers",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}");
+                    }
+                }
+
+                //AnodeAbathUsage
+                if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit") != 0)
+                {
+                    if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeABathUsage",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeABathUsage",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}");
+                    }
+                }
+
+                //AnodeBbathUsage
+                if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit") != 0)
+                {
+                    if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit"))
+                    {
+                        LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}");
+                        PostMsg(MetalMsg.Error);
+                        AlarmListManager.Instance.AddDataError(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeBBathUsage",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}");
+                    }
+                    else
+                    {
+                        LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}");
+                        AlarmListManager.Instance.AddWarn(Module.ToString(),
+                            $"{Module.ToString()}.metalUsage.AnodeBBathUsage",
+                            $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}");
+                    }
+                }
+
+            }
+        }
+        /// <summary>
         /// 获取A面使用的电量
         /// </summary>
         /// <returns></returns>
         private double GetAnodeAUsage()
         {
-            if(_metalItem.SubType == STRATUS)
+            if (_metalItem.SubType == STRATUS)
             {
-                return Math.Round(_standardHotRunRecipeRoutine.AnodeAUsage,3);
+                return Math.Round(_standardHotRunRecipeRoutine.AnodeAUsage, 3);
             }
             else
             {
-                return Math.Round(_compactEmbranceRunRecipeRoutine.AnodeAUsage,3);
+                return Math.Round(_compactEmbranceRunRecipeRoutine.AnodeAUsage, 3);
             }
         }
         /// <summary>
@@ -700,7 +956,7 @@ namespace CyberX8_RT.Modules.Metal
                 MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas,
                     _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
             }
-            
+
             return true;
         }
         #endregion
@@ -744,10 +1000,10 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         private bool CloseFlowValve(object[] param)
         {
-            if(_metalItem.SubType==STRATUS)
+            if (_metalItem.SubType == STRATUS)
             {
                 StandardHotMetalDevice device = DEVICE.GetDevice<StandardHotMetalDevice>(Module.ToString());
-                if (device!=null)
+                if (device != null)
                 {
                     return device.SwitchToBypass("", null);
                 }
@@ -755,15 +1011,15 @@ namespace CyberX8_RT.Modules.Metal
             }
             else
             {
-                CompactMembranMetalDevice device=DEVICE.GetDevice<CompactMembranMetalDevice>(Module.ToString());
-                if(device!=null)
+                CompactMembranMetalDevice device = DEVICE.GetDevice<CompactMembranMetalDevice>(Module.ToString());
+                if (device != null)
                 {
-                    string reservoir= ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
+                    string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
                     CompactMembranReservoirDevice reservoirDevice = DEVICE.GetDevice<CompactMembranReservoirDevice>(reservoir);
                     if (reservoirDevice != null)
                     {
                         bool result = reservoirDevice.CAByPassOn("", null);
-                        if(result)
+                        if (result)
                         {
                             return device.CellFlowValveOff("", null);
                         }
@@ -790,7 +1046,7 @@ namespace CyberX8_RT.Modules.Metal
                     bool result = device.SwitchToFlow("", null);
                     if (result)
                     {
-                        return device.PumpOnOperation("",null);
+                        return device.PumpOnOperation("", null);
                     }
                 }
                 return false;

+ 14 - 14
CyberX8_RT/Modules/Metal/StandardHotInitializeRoutine.cs

@@ -79,13 +79,13 @@ namespace CyberX8_RT.Modules.Metal
         public RState Monitor()
         {
             Runner.Run(InitializeStep.CheckPowerSupplierConnected, CheckPowerSupplierStatus, _delay_1ms)
-                .Run(InitializeStep.LinmotReset,_metalDevice.ResetLinmot,_delay_1ms)
+                .Run(InitializeStep.LinmotReset, _metalDevice.ResetLinmot, _delay_1ms)
                 .WaitWithStopCondition(InitializeStep.LinmotResetWait, _metalDevice.CheckLinmotRoutineEnd, _metalDevice.CheckLinmotRoutineError)
-                .Run(InitializeStep.WHUnclampOn,WaferHolderUnclampOn,_delay_1ms)
-                .Run(InitializeStep.FlowValveOn,()=>_metalDevice.SwitchToFlow("",null),_delay_1ms)
-                .Delay(InitializeStep.Delay,_cellFlowFaultHoldOffTime)
-                .RunIf(InitializeStep.ManualFlowCheck,_metalDevice.IsManual,ManualFlowCheck,_delay_1ms)
-                .RunIf(InitializeStep.AutoFlowCheck,_metalDevice.IsAuto,AutoFlowCheck,_delay_1ms)
+                .Run(InitializeStep.WHUnclampOn, WaferHolderUnclampOn, _delay_1ms)
+                .Run(InitializeStep.FlowValveOn, () => _metalDevice.SwitchToFlow("", null), _delay_1ms)
+                .Delay(InitializeStep.Delay, _cellFlowFaultHoldOffTime)
+                .RunIf(InitializeStep.ManualFlowCheck, _metalDevice.IsManual, ManualFlowCheck, _delay_1ms)
+                .RunIf(InitializeStep.AutoFlowCheck, _metalDevice.IsAuto, AutoFlowCheck, _delay_1ms)
                 .End(InitializeStep.End, NullFun, _delay_1ms);
             return Runner.Status;
         }
@@ -95,12 +95,12 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         private bool CheckPowerSupplierStatus()
         {
-            if(!_metalDevice.SideAPowerSupplier.IsConnected)
+            if (!_metalDevice.SideAPowerSupplier.IsConnected)
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module, "side A power is not connected");
                 return false;
             }
-            if(!_metalDevice.SideBPowerSupplier.IsConnected)
+            if (!_metalDevice.SideBPowerSupplier.IsConnected)
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module, "side B power is not connected");
                 return false;
@@ -121,9 +121,9 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         private bool ManualFlowCheck()
         {
-            if(_metalDevice.MetalDeviceData.CellFlow<_cellFlowStartLowLimit)
+            if (_metalDevice.MetalDeviceData.CellFlow < _cellFlowStartLowLimit)
             {
-                LOG.WriteLog(eEvent.ERR_METAL,Module,$"Flow {_metalDevice.MetalDeviceData.CellFlow} is less than {_cellFlowStartLowLimit}");
+                LOG.WriteLog(eEvent.ERR_METAL, Module, $"Flow {_metalDevice.MetalDeviceData.CellFlow} is less than {_cellFlowStartLowLimit}");
                 _metalDevice.SwitchToBypass("", null);
                 _metalDevice.PumpOff();
                 return false;
@@ -150,24 +150,24 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         public RState Start(params object[] objs)
         {
-            _persistentValue= (MetalPersistentValue)objs[0];
+            _persistentValue = (MetalPersistentValue)objs[0];
             _metalDevice = DEVICE.GetDevice<StandardHotMetalDevice>(Module);
             _cellFlowFaultHoldOffTime = SC.GetValue<int>("Metal.CellFlowFaultHoldOffTime");
             _cellFlowStartLowLimit = SC.GetValue<double>("Metal.CellFlowStartLowLimit");
             string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
             StandardHotReservoirDevice reservoirDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoir);
-            if(reservoirDevice==null)
+            if (reservoirDevice == null)
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module, $"{reservoir} device is null");
                 return RState.Failed;
             }
-            if(reservoirDevice.Recipe==null)
+            if (reservoirDevice.Recipe == null)
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module, $"{reservoir} current recipe is null");
                 return RState.Failed;
             }
             _resRecipe = reservoirDevice.Recipe;
             return Runner.Start(Module, "Start S&H Initialize");
-        }        
+        }
     }
 }

+ 16 - 10
CyberX8_RT/Modules/Metal/StandardHotRunRecipeRoutine.cs

@@ -3,7 +3,7 @@ using Aitex.Core.RT.Log;
 using Aitex.Core.RT.Routine;
 using CyberX8_Core;
 using CyberX8_RT.Devices.Metal;
-using CyberX8_RT.Devices.PowerSupplier;
+using CyberX8_RT.Modules.Metal;
 using MECF.Framework.Common.CommonData;
 using MECF.Framework.Common.CommonData.Metal;
 using MECF.Framework.Common.CommonData.PowerSupplier;
@@ -30,6 +30,12 @@ namespace CyberX8_RT.Modules.Metal
             WaferHolderUnclampOn,
             End
         }
+
+
+        #region 常量 
+        private const int ALL_DAY_MILLOSECONDS = 24 * 60 * 60 * 1000;
+        #endregion
+
         #region 内部变量
         /// <summary>
         /// recipe
@@ -73,7 +79,7 @@ namespace CyberX8_RT.Modules.Metal
         /// <param name="module"></param>
         public StandardHotRunRecipeRoutine(string module) : base(module)
         {
-            _runRecipeRoutine=new ReservoirRunRecipeRoutine(module);
+            _runRecipeRoutine = new ReservoirRunRecipeRoutine(module);
         }
 
         /// <summary>
@@ -90,10 +96,10 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         public RState Monitor()
         {
-            Runner.Run(RecipeStep.WaferHolderClampOn, () => _device.WaferHolderClampOn("", null), () => _device.MetalDeviceData.WaferHolderClamp,_delay_1s)
+            Runner.Run(RecipeStep.WaferHolderClampOn, () => _device.WaferHolderClampOn("", null), () => _device.MetalDeviceData.WaferHolderClamp, _delay_1s)
                 .Run(RecipeStep.RunRecipe, () => _runRecipeRoutine.Start(new object[] { _recipe, _side }) == RState.Running, _delay_1ms)
-                .WaitWithStopCondition(RecipeStep.RunRecipeWait, () => CommonFunction.CheckRoutineEndState(_runRecipeRoutine), CheckRunRecipeStopStatus)
-                .Run(RecipeStep.WaferHolderUnclampOn, () => _device.WaferHolderClampOff("", null), () => !_device.MetalDeviceData.WaferHolderClamp,_delay_1s)
+                .WaitWithStopCondition(RecipeStep.RunRecipeWait, () => CommonFunction.CheckRoutineEndState(_runRecipeRoutine), CheckRunRecipeStopStatus, ALL_DAY_MILLOSECONDS)
+                .Run(RecipeStep.WaferHolderUnclampOn, () => _device.WaferHolderClampOff("", null), () => !_device.MetalDeviceData.WaferHolderClamp, _delay_1s)
                 .End(RecipeStep.End, NullFun, _delay_1ms);
 
             return Runner.Status;
@@ -105,13 +111,13 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         public RState Start(params object[] objs)
         {
-            _recipe=(DepRecipe)objs[0];
-            if(objs.Length>1)
+            _recipe = (DepRecipe)objs[0];
+            if (objs.Length > 1)
             {
                 _side = objs[1].ToString();
             }
             _device = DEVICE.GetDevice<StandardHotMetalDevice>(Module);
-            if(!CheckPreCondition())
+            if (!CheckPreCondition())
             {
                 return RState.Failed;
             }
@@ -123,13 +129,13 @@ namespace CyberX8_RT.Modules.Metal
         /// <returns></returns>
         private bool CheckPreCondition()
         {
-            if(_recipe==null)
+            if (_recipe == null)
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module, "Recipe is null");
                 return false;
             }
 
-            if(_recipe.CurrentRampProfileSteps.Count==0)
+            if (_recipe.CurrentRampProfileSteps.Count == 0)
             {
                 LOG.WriteLog(eEvent.ERR_METAL, Module, "Recipe RampProfileSteps count is 0");
                 return false;

+ 47 - 43
CyberX8_RT/Modules/Reservoir/ReservoirEntity.cs

@@ -9,11 +9,6 @@ using MECF.Framework.Common.Equipment;
 using MECF.Framework.Common.Persistent.Reservoirs;
 using MECF.Framework.Common.RecipeCenter;
 using MECF.Framework.Common.ToolLayout;
-using CyberX8_Core;
-using CyberX8_RT.Devices.Metal;
-using CyberX8_RT.Devices.PowerSupplier;
-using CyberX8_RT.Devices.Temperature;
-using CyberX8_RT.Modules.Prewet;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -21,11 +16,16 @@ using System.Text;
 using System.Threading.Tasks;
 using Aitex.Core.Utilities;
 using MECF.Framework.Common.ProcessCell;
-using CyberX8_RT.Modules.Metal;
-using CyberX8_RT.Modules.SRD;
 using System.Windows;
 using Aitex.Core.RT.SCCore;
 using SecsGem.Core.ItemModel;
+using CyberX8_Core;
+using CyberX8_RT.Devices.Metal;
+using CyberX8_RT.Devices.PowerSupplier;
+using CyberX8_RT.Devices.Temperature;
+using CyberX8_RT.Modules.Metal;
+using CyberX8_RT.Modules.Reservoir;
+using CyberX8_RT.Modules;
 
 namespace CyberX8_RT.Modules.Reservoir
 {
@@ -159,9 +159,10 @@ namespace CyberX8_RT.Modules.Reservoir
         /// </summary>
         public bool IsMetalBusy
         {
-            get {
-                if(_metalDevices == null) return false;
-                foreach(var item in _metalDevices)
+            get
+            {
+                if (_metalDevices == null) return false;
+                foreach (var item in _metalDevices)
                 {
                     MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(item.Module.ToString());
                     if (metalEntity != null && metalEntity.IsBusy) return true;
@@ -211,7 +212,7 @@ namespace CyberX8_RT.Modules.Reservoir
         /// <returns></returns>
         private ResRecipe LoadCurrentRecipe()
         {
-            if(_persistentValue!=null&&!string.IsNullOrEmpty(_persistentValue.Recipe))
+            if (_persistentValue != null && !string.IsNullOrEmpty(_persistentValue.Recipe))
             {
                 return RecipeFileManager.Instance.LoadGenericityRecipe<ResRecipe>(_persistentValue.Recipe);
             }
@@ -240,7 +241,7 @@ namespace CyberX8_RT.Modules.Reservoir
 
                 if (!string.IsNullOrEmpty(_reservoirItem.CMMSupplyID))
                 {
-                    _powerSupplier = DEVICE.GetDevice<CellPowerSupplier>(_reservoirItem.CMMSupplyID);                                 
+                    _powerSupplier = DEVICE.GetDevice<CellPowerSupplier>(_reservoirItem.CMMSupplyID);
                 }
 
                 if (!string.IsNullOrEmpty(_reservoirItem.TCID))
@@ -279,16 +280,16 @@ namespace CyberX8_RT.Modules.Reservoir
         {
             InitializeSVID();
             DATA.Subscribe($"{Module}.FsmState", () => ((ReservoirState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.IsIdle", () => IsIdle,SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.IsIdle", () => IsIdle, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.IsInit", () => IsInit, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.IsDisable", () => IsDisable,SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.IsBusy", () => IsBusy, SubscriptionAttribute.FLAG.IgnoreSaveDB);            
+            DATA.Subscribe($"{Module}.IsDisable", () => IsDisable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.IsBusy", () => IsBusy, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.IsError", () => IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.Metals",()=>_metalDevices.Select(O=>O.Name).ToList(),SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.Metals", () => _metalDevices.Select(O => O.Name).ToList(), SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.TemperatureControllerData", () => _temperatureController == null ? null : _temperatureController.TemperatureData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.CmmPowerSupplierData", () => _powerSupplier == null ? null : _powerSupplier.PowerSupplierData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.ReservoirUsage", () => ReservoirUsage, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.IsCMMInstalled", () => ReservoirItemManager.Instance.GetReservoirItem(Module.ToString()).CMMType == "Standard"? true : false, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.IsCMMInstalled", () => ReservoirItemManager.Instance.GetReservoirItem(Module.ToString()).CMMType == "Standard" ? true : false, SubscriptionAttribute.FLAG.IgnoreSaveDB);
         }
         /// <summary>
         /// 初始化SVID
@@ -297,25 +298,28 @@ namespace CyberX8_RT.Modules.Reservoir
         {
             DATA.Subscribe($"{Module}.State", () => ((ReservoirState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.OperatingMode", () => _persistentValue != null ? _persistentValue.OperatingMode : "None", SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ReservoirTotalAmpHours",()=> ReservoirUsage!=null?ReservoirUsage.TotalUsage:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ReservoirTotalAmpHours.WarningLimit", () => SC.GetValue<double>("Reservoir.ReservoirTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ReservoirTotalAmpHours.FaultLimit", () => SC.GetValue<double>("Reservoir.ReservoirTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.BathTotalAmpHours",()=> ReservoirUsage != null ? ReservoirUsage.BathUsage:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.BathTotalAmpHours.WarningLimit", () => SC.GetValue<double>("Reservoir.BathTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.BathTotalAmpHours.FaultLimit", () => SC.GetValue<double>("Reservoir.BathTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ANBathTotalAmpHours",()=> ReservoirUsage != null ? ReservoirUsage.AnodeUsage:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ANBathTotalAmpHours.WarningLimit", () => SC.GetValue<double>("Reservoir.ANBathTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ANBathTotalAmpHours.FaultLimit", () => SC.GetValue<double>("Reservoir.ANBathTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.MembraneTotalAmpHours",()=> ReservoirUsage != null ? ReservoirUsage.MembranceUsage:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.MembraneTotalAmpHours.WarningLimit", () => SC.GetValue<double>("Reservoir.MembraneTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.MembraneTotalAmpHours.FaultLimit", () => SC.GetValue<double>("Reservoir.MembraneTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.BathTotalDays", () => ReservoirUsage != null ? ReservoirUsage.BathUsageDays:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.BathTotalDays.WarningLimit", () => SC.GetValue<int>("Reservoir.BathTotalDaysWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.BathTotalDays.FaultLimit", () => SC.GetValue<int>("Reservoir.BathTotalDaysFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ReservoirTotalWafers",()=> ReservoirUsage != null ? ReservoirUsage.TotalWafers:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ReservoirTotalWafers.WarningLimit", () => SC.GetValue<int>("Reservoir.ReservoirTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.ReservoirTotalWafers.FaultLimit", () => SC.GetValue<int>("Reservoir.ReservoirTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
-            DATA.Subscribe($"{Module}.Temperature", () => _temperatureController!=null? _temperatureController.TemperatureData.ReserviorTemperature:0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.ReservoirTotalAmpHours", () => ReservoirUsage != null ? ReservoirUsage.TotalUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.ReservoirTotalAmpHours.WarningLimit", () => SC.GetValue<double>($"Reservoir.{Module}.ReservoirTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.ReservoirTotalAmpHours.FaultLimit", () => SC.GetValue<double>($"Reservoir.{Module}.ReservoirTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.BathTotalAmpHours", () => ReservoirUsage != null ? ReservoirUsage.BathUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.BathTotalAmpHours.WarningLimit", () => SC.GetValue<double>($"Reservoir.{Module}.BathTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.BathTotalAmpHours.FaultLimit", () => SC.GetValue<double>($"Reservoir.{Module}.BathTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.ANBathTotalAmpHours", () => ReservoirUsage != null ? ReservoirUsage.AnodeUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            if (ReservoirItemManager.Instance.GetReservoirItem(Module.ToString()).CMMType != "Standard")
+            {
+                DATA.Subscribe($"{Module}.ANBathTotalAmpHours.WarningLimit", () => SC.GetValue<double>($"Reservoir.{Module}.ANBathTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+                DATA.Subscribe($"{Module}.ANBathTotalAmpHours.FaultLimit", () => SC.GetValue<double>($"Reservoir.{Module}.ANBathTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            }
+            DATA.Subscribe($"{Module}.MembraneTotalAmpHours", () => ReservoirUsage != null ? ReservoirUsage.MembranceUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            //DATA.Subscribe($"{Module}.MembraneTotalAmpHours.WarningLimit", () => SC.GetValue<double>($"Reservoir.{Module}.MembraneTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            //DATA.Subscribe($"{Module}.MembraneTotalAmpHours.FaultLimit", () => SC.GetValue<double>($"Reservoir.{Module}.MembraneTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.BathTotalDays", () => ReservoirUsage != null ? ReservoirUsage.BathUsageDays : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            //DATA.Subscribe($"{Module}.BathTotalDays.WarningLimit", () => SC.GetValue<int>($"Reservoir.{Module}.BathTotalDaysWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            //DATA.Subscribe($"{Module}.BathTotalDays.FaultLimit", () => SC.GetValue<int>($"Reservoir.{Module}.BathTotalDaysFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.ReservoirTotalWafers", () => ReservoirUsage != null ? ReservoirUsage.TotalWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            //DATA.Subscribe($"{Module}.ReservoirTotalWafers.WarningLimit", () => SC.GetValue<int>($"Reservoir.{Module}.ReservoirTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            //DATA.Subscribe($"{Module}.ReservoirTotalWafers.FaultLimit", () => SC.GetValue<int>($"Reservoir.{Module}.ReservoirTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
+            DATA.Subscribe($"{Module}.Temperature", () => _temperatureController != null ? _temperatureController.TemperatureData.ReserviorTemperature : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.Temperature.ID", () => _temperatureController != null ? _temperatureController.Module : "", SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.Temperature.Status", () => _temperatureController != null ? _temperatureController.TemperatureData.Status : "", SubscriptionAttribute.FLAG.IgnoreSaveDB);
             DATA.Subscribe($"{Module}.Temperature.TargetTemperature", () => _temperatureController != null ? _temperatureController.TemperatureData.TargetTemperature : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
@@ -328,7 +332,7 @@ namespace CyberX8_RT.Modules.Reservoir
         private void InitializeRoutine()
         {
             _shInitializeRoutine = new StandardHotReservoirInitializeRoutine(Module.ToString());
-            _cmInitializeRoutine=new CompactEmbranceInitializeRoutine(Module.ToString()); 
+            _cmInitializeRoutine = new CompactEmbranceInitializeRoutine(Module.ToString());
             _dosingSystemInitializeRoutine = new DosingSystemInitializeRoutine(Module.ToString());
         }
         /// <summary>
@@ -376,12 +380,12 @@ namespace CyberX8_RT.Modules.Reservoir
         /// <returns></returns>
         private bool InitializeAll(object[] param)
         {
-            if (_metalDevices==null||_metalDevices.Count==0)
+            if (_metalDevices == null || _metalDevices.Count == 0)
             {
                 LOG.WriteLog(eEvent.ERR_RESERVOIR, Module.ToString(), "metal device is empty");
                 return false;
             }
-            if(_persistentValue==null)
+            if (_persistentValue == null)
             {
                 LOG.WriteLog(eEvent.ERR_RESERVOIR, Module.ToString(), "persistent is null");
                 return false;
@@ -392,7 +396,7 @@ namespace CyberX8_RT.Modules.Reservoir
             }
             else
             {
-                return _cmInitializeRoutine.Start(_metalDevices, _temperatureController) ==RState.Running;
+                return _cmInitializeRoutine.Start(_metalDevices, _temperatureController) == RState.Running;
             }
         }
         /// <summary>
@@ -405,7 +409,7 @@ namespace CyberX8_RT.Modules.Reservoir
             RState ret = RState.Init;
             if (_reservoirItem.SubType == STRATUS)
             {
-                ret= _shInitializeRoutine.Monitor();
+                ret = _shInitializeRoutine.Monitor();
             }
             else
             {
@@ -420,7 +424,7 @@ namespace CyberX8_RT.Modules.Reservoir
             return ret == RState.End;
         }
         #endregion
-               
+
         public bool Check(int msg, out string reason, params object[] args)
         {
             reason = "";
@@ -452,6 +456,6 @@ namespace CyberX8_RT.Modules.Reservoir
             }
             return (int)FSM_MSG.NONE;
         }
-        
+
     }
 }

+ 59 - 57
CyberX8_RT/Modules/Reservoir/StandardHotReservoirInitializeRoutine.cs

@@ -5,14 +5,15 @@ using Aitex.Core.RT.SCCore;
 using MECF.Framework.Common.Persistent.Reservoirs;
 using MECF.Framework.Common.RecipeCenter;
 using MECF.Framework.Common.Routine;
+using System;
+using System.Collections.Generic;
+using MECF.Framework.Common.Alarm;
 using CyberX8_Core;
 using CyberX8_RT.Devices.Facilities;
 using CyberX8_RT.Devices.Metal;
 using CyberX8_RT.Devices.PowerSupplier;
 using CyberX8_RT.Devices.Reservoir;
 using CyberX8_RT.Devices.Temperature;
-using System;
-using System.Collections.Generic;
 
 namespace CyberX8_RT.Modules.Reservoir
 {
@@ -23,7 +24,7 @@ namespace CyberX8_RT.Modules.Reservoir
             AutoDiReplen,
             CellPump,
             WaitCellPump,
-            CheckHedFlow,
+            CheckCellFlow,
             ManualCellByPass,
             AutoCellManual,
             AutoEnableCMM,
@@ -104,11 +105,11 @@ namespace CyberX8_RT.Modules.Reservoir
         /// <returns></returns>
         public RState Monitor()
         {
-                //Cell Pump
+            //Cell Pump
             Runner.RunIf(InitializeStep.AutoDiReplen, _recipe.DIReplenEnable, CheckFacilitiesDiReplenStatus, _delay_1ms)
                 .Run(InitializeStep.CellPump, CellsPumpOn, _delay_1ms)
                 .WaitWithStopCondition(InitializeStep.WaitCellPump, CheckPumpOnEndStatus, CheckPumpOnStopStatus)
-                .Run(InitializeStep.CheckHedFlow, CheckHedFlow, _delay_1ms)
+                .Run(InitializeStep.CheckCellFlow, CheckCellFlow, _delay_1ms)
                 //Manual cell Bypass同时disable HED
                 .RunIf(InitializeStep.ManualCellByPass, _reservoirDevice.OperationMode == MANUAL, CellsByPassEnableHed, _delay_1ms)
                 //Auto 所有metal 处于Manual, cell Bypass,Enable HED,设置温度
@@ -120,23 +121,23 @@ namespace CyberX8_RT.Modules.Reservoir
                 .DelayIf(InitializeStep.AutoCMMFlowDelay, CheckAutoEnableCMM(), _cmmFlowCheckDelay * 1000)
                 .RunIf(InitializeStep.AutoCMMFlowCheck, CheckAutoEnableCMM(), CheckCMMTargetFlow, _delay_1ms)
                 //Auto 启动PH检测
-                .RunIf(InitializeStep.AutoPHDetect,_reservoirDevice.OperationMode==AUTO,StartAutoPHDetect,_delay_1ms)
+                .RunIf(InitializeStep.AutoPHDetect, _reservoirDevice.OperationMode == AUTO, StartAutoPHDetect, _delay_1ms)
                 //Auto Cell Flow
-                .Run(InitializeStep.AutoCellAutoFlow,AllMetalSwitchFlow,_delay_1ms)
+                .Run(InitializeStep.AutoCellAutoFlow, AllMetalSwitchFlow, _delay_1ms)
                 .Delay(InitializeStep.AutoCellAutoFlowDelay, 500)
-                .Run(InitializeStep.AutoCellAutoFlowCheck, AllMetalCheckFlow,_delay_1ms)
+                .Run(InitializeStep.AutoCellAutoFlowCheck, AllMetalCheckFlow, _delay_1ms)
                 //Auto HED
                 .Run(InitializeStep.AutoCellAutoEnableHED, AutoHedOn, _delay_1ms)
-                .Delay(InitializeStep.AutoCellAutoEnableHEDDelay,_autoHedDelay)
+                .Delay(InitializeStep.AutoCellAutoEnableHEDDelay, _autoHedDelay)
                 .Run(InitializeStep.AutoCellAutoEnableHEDCheck, AutoHedSuccess, _delay_1ms)
                 //检验PowerSupplier通信
                 .Run(InitializeStep.AutoCellAutoCheckPowerSupplier, AutoMetalsPowerSupplierCommuncationStatus, _delay_1ms)
                 //Cell Linmot Reset
-                .RunIf(InitializeStep.AutoCellAutoLinmotReset,_reservoirDevice.OperationMode==AUTO,AutoMetalResetLinmot,_delay_1ms)
+                .RunIf(InitializeStep.AutoCellAutoLinmotReset, _reservoirDevice.OperationMode == AUTO, AutoMetalResetLinmot, _delay_1ms)
                 .WaitWithStopCondition(InitializeStep.AutoCellAutoLinmotResetCheck, CheckAutoMetalResetStatus, CheckAutoMetalResetStopStatus)
                 //Cell Unclamp
-                .Run(InitializeStep.CellWSUnclamp,MetalsWHUnclampOn,_delay_1ms)
-                .End(InitializeStep.End, NullFun, _delay_1ms);
+                .Run(InitializeStep.CellWSUnclamp, MetalsWHUnclampOn, _delay_1ms)
+                .End(InitializeStep.End, ClearAlarmDataError, _delay_1ms);
             return Runner.Status;
         }
         /// <summary>
@@ -241,16 +242,9 @@ namespace CyberX8_RT.Modules.Reservoir
         /// 检验HED Flow
         /// </summary>
         /// <returns></returns>
-        private bool CheckHedFlow()
+        private bool CheckCellFlow()
         {
-            double hedFlow = _reservoirDevice.ReservoirData.HedFlow;
-            bool result = hedFlow > _hedFlowLowLimit;
-            if (!result)
-            {
-                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"HED Flow {hedFlow} is less than {_hedFlowLowLimit}");
-                PumpOffMetals();
-            }
-            return result;
+            return true;
         }
         /// <summary>
         /// 检验所有Metal处于Manual
@@ -293,24 +287,24 @@ namespace CyberX8_RT.Modules.Reservoir
         /// <returns></returns>
         private bool CheckCellManualByPassAndTemperature()
         {
-            for (int i = 0; i<_metalDevices.Count; i++)
+            for (int i = 0; i < _metalDevices.Count; i++)
             {
                 StandardHotMetalDevice hotMetalDevice = _metalDevices[i];
-                if(hotMetalDevice.MetalDeviceData.Circulation)
+                if (hotMetalDevice.MetalDeviceData.Circulation)
                 {
                     return false;
                 }
             }
-            
-            if(_temperatureController.TemperatureData.ControlOperationModel==0)
+
+            if (_temperatureController.TemperatureData.ControlOperationModel == 0)
             {
                 return false;
             }
-            if(Math.Abs(_recipe.TemperatureSetPoint-_temperatureController.TemperatureData.TargetTemperature)>=0.1*_recipe.TemperatureSetPoint)
+            if (Math.Abs(_recipe.TemperatureSetPoint - _temperatureController.TemperatureData.TargetTemperature) >= 0.1 * _recipe.TemperatureSetPoint)
             {
                 return false;
             }
-           return true;
+            return true;
         }
         /// <summary>
         /// 检验 Auto ,同时Enable CMM
@@ -318,7 +312,7 @@ namespace CyberX8_RT.Modules.Reservoir
         /// <returns></returns>
         private bool CheckAutoEnableCMM()
         {
-            if(_reservoirDevice.OperationMode!=AUTO)
+            if (_reservoirDevice.OperationMode != AUTO)
             {
                 return false;
             }
@@ -340,20 +334,20 @@ namespace CyberX8_RT.Modules.Reservoir
         {
             double flow = _reservoirDevice.ReservoirData.Flow;
 
-            if(flow < _cmmFlowLowFault)
+            if (flow < _cmmFlowLowFault)
             {
                 LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} CMM flow:{flow} is less than config item CMMFlowLowFault:{_cmmFlowLowFault}");
-                if (_cellPowerSupplier.PowerSupplierData.Enabled)  _cellPowerSupplier.DisableOperation("", null);
+                if (_cellPowerSupplier.PowerSupplierData.Enabled) _cellPowerSupplier.DisableOperation("", null);
                 return false;
-            } 
+            }
             else if (flow < _cmmFlowLowWarning)
             {
                 LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} CMM flow:{flow} is less than config item CMMFlowLowWarning:{_cmmFlowLowWarning}");
-            } 
+            }
             else if (flow > _cmmFlowHighFault)
             {
                 LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} CMM flow:{flow} is over config item CMMFlowHighFault:{_cmmFlowLowFault}");
-                if(_cellPowerSupplier.PowerSupplierData.Enabled) _cellPowerSupplier.DisableOperation("", null);
+                if (_cellPowerSupplier.PowerSupplierData.Enabled) _cellPowerSupplier.DisableOperation("", null);
                 return false;
             }
             else if (flow > _cmmFlowHighWarning)
@@ -399,7 +393,7 @@ namespace CyberX8_RT.Modules.Reservoir
             for (int i = 0; i < _metalDevices.Count; i++)
             {
                 StandardHotMetalDevice hotMetalDevice = _metalDevices[i];
-                if (hotMetalDevice != null && !hotMetalDevice.IsDisable&&hotMetalDevice.IsAuto)
+                if (hotMetalDevice != null && !hotMetalDevice.IsDisable && hotMetalDevice.IsAuto)
                 {
                     bool result = hotMetalDevice.SwitchToFlow("", null);
                     if (!result)
@@ -441,13 +435,13 @@ namespace CyberX8_RT.Modules.Reservoir
         /// <returns></returns>
         private bool AutoHedOn()
         {
-            double hedFlow = _reservoirDevice.ReservoirData.HedFlow;
-            bool result = hedFlow > _hedFlowLowLimit;
-            if (!result)
-            {
-                LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"HED Flow {hedFlow} is less than {_hedFlowLowLimit}");
-                return false;
-            }
+            //double hedFlow = _reservoirDevice.ReservoirData.HedFlow;
+            //bool result = hedFlow > _hedFlowLowLimit;
+            //if (!result)
+            //{
+            //    LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"HED Flow {hedFlow} is less than {_hedFlowLowLimit}");
+            //    return false;
+            //}
             _autoHedDelay = _delay_2s;
             _temperatureController.EnableOperation("", null);
             _temperatureController.SetTargetTemperatureOperation("", new object[] { _recipe.TemperatureSetPoint });
@@ -516,10 +510,10 @@ namespace CyberX8_RT.Modules.Reservoir
             {
                 StandardHotMetalDevice hotMetalDevice = _metalDevices[i];
 
-                if(hotMetalDevice.OperationMode==AUTO)
+                if (hotMetalDevice.OperationMode == AUTO)
                 {
-                    bool result= hotMetalDevice.ResetLinmot();
-                    if(!result)
+                    bool result = hotMetalDevice.ResetLinmot();
+                    if (!result)
                     {
                         LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Reset linmot error");
                         return false;
@@ -535,7 +529,7 @@ namespace CyberX8_RT.Modules.Reservoir
         /// <returns></returns>
         private bool CheckAutoMetalResetStatus()
         {
-            if(_reservoirDevice.OperationMode == MANUAL)
+            if (_reservoirDevice.OperationMode == MANUAL)
             {
                 return true;
             }
@@ -597,7 +591,15 @@ namespace CyberX8_RT.Modules.Reservoir
             }
             return true;
         }
-
+        /// <summary>
+        /// 清除alarm界面相关的dataerror
+        /// </summary>
+        private bool ClearAlarmDataError()
+        {
+            AlarmListManager.Instance.RemoveDataError(Module);
+            _reservoirDevice.ClearErrorLogSet(Module); //清除device里面的ErrorLogSet
+            return true;
+        }
         /// <summary>
         /// 启动
         /// </summary>
@@ -607,31 +609,31 @@ namespace CyberX8_RT.Modules.Reservoir
         {
             List<MetalCellDevice> lstDevice = (List<MetalCellDevice>)objs[0];
             _metalDevices.Clear();
-            for(int i=0;i<lstDevice.Count; i++)
+            for (int i = 0; i < lstDevice.Count; i++)
             {
                 _metalDevices.Add((StandardHotMetalDevice)lstDevice[i]);
             }
             _reservoirDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(Module.ToString());
-            _recipe=_reservoirDevice.Recipe;
+            _recipe = _reservoirDevice.Recipe;
             if (!(objs[1] is null))
             {
                 _cellPowerSupplier = (CellPowerSupplier)objs[1];
             }
-            _temperatureController=(TemperatureController)objs[2];
+            _temperatureController = (TemperatureController)objs[2];
             _hedFlowLowLimit = SC.GetValue<double>($"Reservoir.{Module}.HEDFlowLowLimit");
             if (!CheckPreCondition())
             {
                 return RState.Failed;
             }
-            _cmmFlowHighFault = SC.GetValue<double>($"Reservoir.CMM.CMMFlowHighFault");
-            _cmmFlowHighWarning = SC.GetValue<double>($"Reservoir.CMM.CMMFlowHighWarning");
-            _cmmFlowLowFault = SC.GetValue<double>($"Reservoir.CMM.CMMFlowLowFault");
-            _cmmFlowLowWarning = SC.GetValue<double>($"Reservoir.CMM.CMMFlowLowWarning");
-            _cmmFlowCheckDelay = SC.GetValue<int>($"Reservoir.CMM.CMMFlowCheckDelaySeconds");
+            _cmmFlowHighFault = SC.GetValue<double>($"Reservoir.{Module}.CMMFlowHighFault");
+            _cmmFlowHighWarning = SC.GetValue<double>($"Reservoir.{Module}.CMMFlowHighWarning");
+            _cmmFlowLowFault = SC.GetValue<double>($"Reservoir.{Module}.CMMFlowLowFault");
+            _cmmFlowLowWarning = SC.GetValue<double>($"Reservoir.{Module}.CMMFlowLowWarning");
+            _cmmFlowCheckDelay = SC.GetValue<int>($"Reservoir.{Module}.CMMFlowCheckDelaySeconds");
             if (_recipe.CMMEnable)
             {
                 _persistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(Module);
-            }         
+            }
             return Runner.Start(Module, "Start Initialize");
         }
 
@@ -641,12 +643,12 @@ namespace CyberX8_RT.Modules.Reservoir
         /// <returns></returns>
         private bool CheckPreCondition()
         {
-            if(_recipe==null)
+            if (_recipe == null)
             {
                 LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "recipe is null");
                 return false;
             }
-            if(_recipe.CMMEnable&&!_cellPowerSupplier.IsConnected)
+            if (_recipe.CMMEnable && !_cellPowerSupplier.IsConnected)
             {
                 LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "PowerSupplier is not connected");
                 return false;

+ 1 - 0
CyberX8_Simulator/Config/SimulatorIOMapCfg.xml

@@ -21,4 +21,5 @@
 	<SimulatorIOMapItem SourceIOName="c_QDRD3_DUMP" TargetIONameA="r_QDRD3_WATER_LEVEL"/>
 	<SimulatorIOMapItem SourceIOName="c_QDRD4_DI_FILL" TargetIONameA="r_QDRD4_WATER_LEVEL"/>
 	<SimulatorIOMapItem SourceIOName="c_QDRD4_DUMP" TargetIONameA="r_QDRD4_WATER_LEVEL"/>
+	<SimulatorIOMapItem SourceIOName="c_QDRD4_DUMP" TargetIONameA="r_QDRD4_WATER_LEVEL"/>
 </SimulatorIOMapConfig>

+ 45 - 7
CyberX8_Simulator/Devices/WagoSocketSimulator.cs

@@ -29,7 +29,6 @@ namespace CyberX8_Simulator.Devices
         public Dictionary<string, int> AONameIndexDic;
 
         private IByteTransform byteTransform = new BigEndianByteTransformBase();
-
         //存储模拟器数据的数组
         public byte[] DOBytes = new byte[200];
 
@@ -388,10 +387,10 @@ namespace CyberX8_Simulator.Devices
             if (DONameIndexDic.ContainsKey("c_HVD_1_ENABLE")) DOBytes[DONameIndexDic["c_HVD_1_ENABLE"]] = 1;
             if (DONameIndexDic.ContainsKey("c_HVD_2_ENABLE")) DOBytes[DONameIndexDic["c_HVD_2_ENABLE"]] = 1;
             //QDR
-            if (AINameIndexDic.ContainsKey("r_QDRD1_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD1_WATER_LEVEL"]] = 4000;
-            if (AINameIndexDic.ContainsKey("r_QDRD2_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD2_WATER_LEVEL"]] = 4000;
-            if (AINameIndexDic.ContainsKey("r_QDRD3_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD3_WATER_LEVEL"]] = 4000;
-            if (AINameIndexDic.ContainsKey("r_QDRD4_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] = 4000;
+            if (AINameIndexDic.ContainsKey("r_QDRD1_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD1_WATER_LEVEL"]] = 0;
+            if (AINameIndexDic.ContainsKey("r_QDRD2_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD2_WATER_LEVEL"]] = 0;
+            if (AINameIndexDic.ContainsKey("r_QDRD3_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD3_WATER_LEVEL"]] = 0;
+            if (AINameIndexDic.ContainsKey("r_QDRD4_WATER_LEVEL")) AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] = 0;
             //SRD
             if (AINameIndexDic.ContainsKey("r_SRD1_CHUCK_VACUUM_anlg")) AIShorts[AINameIndexDic["r_SRD1_CHUCK_VACUUM_anlg"]] = 15000;
             if (AINameIndexDic.ContainsKey("r_SRD2_CHUCK_VACUUM_anlg")) AIShorts[AINameIndexDic["r_SRD2_CHUCK_VACUUM_anlg"]] = 15000;
@@ -424,9 +423,21 @@ namespace CyberX8_Simulator.Devices
             if (DINameIndexDic.ContainsKey("r_SRD2_WAFER_PRESENT")) DIBytes[DINameIndexDic["r_SRD2_WAFER_PRESENT"]] = 1;
             //Metal
             if (AINameIndexDic.ContainsKey("r_PUMP4_FLOW")) AIShorts[AINameIndexDic["r_PUMP4_FLOW"]] = 3277;
+            if (AINameIndexDic.ContainsKey("r_PUMP3_FLOW")) AIShorts[AINameIndexDic["r_PUMP3_FLOW"]] = 3277;
+            if (AINameIndexDic.ContainsKey("r_PUMP2_FLOW")) AIShorts[AINameIndexDic["r_PUMP2_FLOW"]] = 3277;
+            if (AINameIndexDic.ContainsKey("r_PUMP1_FLOW")) AIShorts[AINameIndexDic["r_PUMP1_FLOW"]] = 3277;
 
             //Facility
             if (AINameIndexDic.ContainsKey("r_DI_WATER_PRESSURE")) AIShorts[AINameIndexDic["r_DI_WATER_PRESSURE"]] = 16000;
+            if (AINameIndexDic.ContainsKey("r_HCW_FLOW")) AIShorts[AINameIndexDic["r_HCW_FLOW"]] = 16300;
+            if (AINameIndexDic.ContainsKey("r_N2_1B_PRESSURE")) AIShorts[AINameIndexDic["r_N2_1B_PRESSURE"]] = 5400;
+            if (AINameIndexDic.ContainsKey("r_N2_1A_PRESSURE")) AIShorts[AINameIndexDic["r_N2_1A_PRESSURE"]] = 8900;
+            if (AINameIndexDic.ContainsKey("r_N2_2B_PRESSURE")) AIShorts[AINameIndexDic["r_N2_2B_PRESSURE"]] = 5400;
+            if (AINameIndexDic.ContainsKey("r_N2_2A_PRESSURE")) AIShorts[AINameIndexDic["r_N2_2A_PRESSURE"]] = 8900;
+            if (AINameIndexDic.ContainsKey("r_SYSTEM_VACUUM")) AIShorts[AINameIndexDic["r_SYSTEM_VACUUM"]] = 3276;
+            if (AINameIndexDic.ContainsKey("r_CDA_HIGH_PRESSURE")) AIShorts[AINameIndexDic["r_CDA_HIGH_PRESSURE"]] = 10000;
+            if (AINameIndexDic.ContainsKey("r_CDA_LOW_PRESSURE")) AIShorts[AINameIndexDic["r_CDA_LOW_PRESSURE"]] = 10000;
+            if (AINameIndexDic.ContainsKey("r_CDA_EXTERNAL_PRESSURE")) AIShorts[AINameIndexDic["r_CDA_EXTERNAL_PRESSURE"]] = 10000;
 
         }
         #region 公共方法
@@ -835,7 +846,7 @@ namespace CyberX8_Simulator.Devices
             {
                 AIShorts[AINameIndexDic["r_QDRD4_WATER_LEVEL"]] -= 2;
             }
-        }
+        }
         /// <summary>
         /// metal pump流量模拟
         /// </summary>
@@ -847,7 +858,34 @@ namespace CyberX8_Simulator.Devices
             }
             else
             {
-                AIShorts[AINameIndexDic["r_PUMP4_FLOW"]] = 3277;
+                AIShorts[AINameIndexDic["r_PUMP3_FLOW"]] = 3277;
+            }
+
+            if (DOBytes[DONameIndexDic["c_METAL3_PUMP_ON"]] == 1)
+            {
+                AIShorts[AINameIndexDic["r_PUMP3_FLOW"]] = 6000;
+            }
+            else
+            {
+                AIShorts[AINameIndexDic["r_PUMP2_FLOW"]] = 3277;
+            }
+
+            if (DOBytes[DONameIndexDic["c_METAL2_PUMP_ON"]] == 1)
+            {
+                AIShorts[AINameIndexDic["r_PUMP2_FLOW"]] = 6000;
+            }
+            else
+            {
+                AIShorts[AINameIndexDic["r_PUMP1_FLOW"]] = 3277;
+            }
+
+            if (DOBytes[DONameIndexDic["c_METAL1_PUMP_ON"]] == 1)
+            {
+                AIShorts[AINameIndexDic["r_PUMP1_FLOW"]] = 6000;
+            }
+            else
+            {
+                AIShorts[AINameIndexDic["r_PUMP1_FLOW"]] = 3277;
             }
         }
         #endregion

+ 84 - 20
Framework/Common/Alarm/AlarmListManager.cs

@@ -27,7 +27,7 @@ namespace MECF.Framework.Common.Alarm
         /// <summary>
         /// 模块数据告警字典(key-模块数据项,value-warn对象)
         /// </summary>
-        private ConcurrentDictionary<string, AlarmList> _moduleDataItemWarnDictionary= new ConcurrentDictionary<string, AlarmList>();
+        private ConcurrentDictionary<string, AlarmList> _moduleDataItemWarnDictionary = new ConcurrentDictionary<string, AlarmList>();
         /// <summary>
         /// 模块报警数据
         /// </summary>
@@ -49,7 +49,7 @@ namespace MECF.Framework.Common.Alarm
                 {
                     _moduleAlarmDictionary[item.ModuleName] = item;
                 }
-                else if (item.AlarmType == (int)AlarmType.Warning)
+                else if (item.AlarmType == (int)AlarmType.Warning || item.AlarmType == (int)AlarmType.DataError)
                 {
                     _moduleDataItemWarnDictionary[$"{item.ModuleName}.{item.DataItem}"] = item;
                 }
@@ -89,7 +89,7 @@ namespace MECF.Framework.Common.Alarm
             {
                 _moduleAlarmDictionary[alarm.ModuleName] = alarm;
                 AlarmListRecorder.UpdateAlarmList(alarm);
-                AlarmList alarmList=_alarmLists.Find(O=>O.ModuleName == alarm.ModuleName);
+                AlarmList alarmList = _alarmLists.Find(O => O.ModuleName == alarm.ModuleName && O.AlarmType == (int)AlarmType.Error);
                 if (alarmList != null)
                 {
                     alarmList.Clone(alarm);
@@ -102,15 +102,15 @@ namespace MECF.Framework.Common.Alarm
         /// <param name="moduleName"></param>
         /// <param name="dataItem"></param>
         /// <param name="warnMsg"></param>
-        public bool AddWarn(string moduleName,string dataItem,string warnMsg)
+        public bool AddWarn(string moduleName, string dataItem, string warnMsg)
         {
             string str = $"{moduleName}.{dataItem}";
-            if(!_moduleDataItemWarnDictionary.ContainsKey(str))
+            if (!_moduleDataItemWarnDictionary.ContainsKey(str))
             {
                 AlarmList alarm = new AlarmList();
-                alarm.ModuleName= moduleName;
-                alarm.DataItem= dataItem;
-                alarm.AlarmMsg= warnMsg;
+                alarm.ModuleName = moduleName;
+                alarm.DataItem = dataItem;
+                alarm.AlarmMsg = warnMsg;
                 alarm.AlarmType = (int)AlarmType.Warning;
                 alarm.CreateTime = DateTime.Now;
                 _moduleDataItemWarnDictionary[str] = alarm;
@@ -121,20 +121,44 @@ namespace MECF.Framework.Common.Alarm
             return false;
         }
         /// <summary>
+        /// 增加DataError
+        /// </summary>
+        /// <param name="moduleName"></param>
+        /// <param name="dataItem"></param>
+        /// <param name="warnMsg"></param>
+        public bool AddDataError(string moduleName, string dataItem, string warnMsg)
+        {
+            string str = $"{moduleName}.{dataItem}";
+            if (!_moduleDataItemWarnDictionary.ContainsKey(str))
+            {
+                AlarmList alarm = new AlarmList();
+                alarm.ModuleName = moduleName;
+                alarm.DataItem = dataItem;
+                alarm.AlarmMsg = warnMsg;
+                alarm.AlarmType = (int)AlarmType.DataError;
+                alarm.CreateTime = DateTime.Now;
+                _moduleDataItemWarnDictionary[str] = alarm;
+                AlarmListRecorder.AddAlarmList(alarm);
+                _alarmLists.Add(alarm);
+                return true;
+            }
+            return false;
+        }
+        /// <summary>
         /// 确认
         /// </summary>
         /// <param name="moduleName"></param>
         /// <param name="dataItem"></param>
-        public void Acknowledge(string moduleName,string dataItem)
+        public void Acknowledge(string moduleName, string dataItem)
         {
             string str = $"{moduleName}.{dataItem}";
             if (_moduleDataItemWarnDictionary.ContainsKey(str))
             {
                 _moduleDataItemWarnDictionary.TryRemove(str, out AlarmList alarmList);
-                if(alarmList != null)
+                if (alarmList != null)
                 {
                     AlarmListRecorder.RemoveAlarmList(alarmList);
-                    AlarmList alarm = _alarmLists.Find(O => O.ModuleName == moduleName && O.AlarmType == (int)AlarmType.Warning && O.DataItem == alarmList.DataItem);
+                    AlarmList alarm = _alarmLists.Find(O => O.ModuleName == moduleName && (O.AlarmType == (int)AlarmType.Warning || O.AlarmType == (int)AlarmType.DataError) && O.DataItem == alarmList.DataItem);
                     if (alarm != null)
                     {
                         _alarmLists.Remove(alarm);
@@ -149,25 +173,25 @@ namespace MECF.Framework.Common.Alarm
         /// <returns></returns>
         public AlarmList GetAlarmListByModule(string moduleName)
         {
-            return _moduleAlarmDictionary.ContainsKey(moduleName) ? _moduleAlarmDictionary[moduleName]:null;
+            return _moduleAlarmDictionary.ContainsKey(moduleName) ? _moduleAlarmDictionary[moduleName] : null;
         }
         /// <summary>
         /// 检验模块Alarm确认后移除
         /// </summary>
         /// <param name="moduleName"></param>
         /// <param name="state"></param>
-        public void CheckModuleAlamAndRemove(string moduleName,string state)
+        public void CheckModuleAlamAndRemove(string moduleName, string state)
         {
-            if(IsContained(moduleName))
+            if (IsContained(moduleName))
             {
-                AlarmList alarmList=GetAlarmListByModule(moduleName);
-                
-                if (alarmList != null )
+                AlarmList alarmList = GetAlarmListByModule(moduleName);
+
+                if (alarmList != null)
                 {
                     if (alarmList.ModuleState == state || string.IsNullOrEmpty(state))
                     {
                         RemoveAlarm(moduleName);
-                        AlarmList alarm=_alarmLists.Find(O=>O.ModuleName==moduleName);
+                        AlarmList alarm = _alarmLists.Find(O => O.ModuleName == moduleName);
                         if (alarm != null)
                         {
                             _alarmLists.Remove(alarm);
@@ -188,10 +212,50 @@ namespace MECF.Framework.Common.Alarm
                 if (alarmList != null)
                 {
                     AlarmListRecorder.RemoveAlarmList(alarmList);
+                    int index = _alarmLists.FindIndex(O => O.ModuleName == moduleName && O.AlarmType == (int)AlarmType.Error);
+                    if (index != -1)
+                    {
+                        _alarmLists.RemoveAt(index);
+                    }
                 }
             }
         }
         /// <summary>
+        /// 初始化成功时移除相关的DataError
+        /// </summary>
+        /// <param name="moduleName"></param>
+        public void RemoveDataError(string moduleName)
+        {
+            foreach (var item in _moduleDataItemWarnDictionary.Keys)
+            {
+                if (item.Contains(moduleName) && _moduleDataItemWarnDictionary[item].AlarmType == (int)AlarmType.DataError)
+                {
+                    _moduleDataItemWarnDictionary.TryRemove(item, out AlarmList alarmList);
+                    if (alarmList != null)
+                    {
+                        AlarmListRecorder.RemoveAlarmList(alarmList);
+                        AlarmList alarm = _alarmLists.Find(O => O.ModuleName == moduleName && O.DataItem == alarmList.DataItem);
+                        if (alarm != null)
+                        {
+                            _alarmLists.Remove(alarm);
+                        }
+                    }
+                }
+            }
+        }
+        /// <summary>
+        /// 判断是否存在dataerror
+        /// </summary>
+        /// <param name="module"></param>
+        /// <param name="dataItem"></param>
+        /// <returns></returns>
+        public bool IsContainDataError(string module, string dataItem)
+        {
+            bool result = false;
+            result = _moduleDataItemWarnDictionary.ContainsKey($"{module}.{dataItem}");
+            return result;
+        }
+        /// <summary>
         /// 清除所有报警
         /// </summary>
         public void ClearAllAlarm()
@@ -199,7 +263,7 @@ namespace MECF.Framework.Common.Alarm
             _alarmLists.Clear();
             _moduleAlarmDictionary.Clear();
             AlarmListRecorder.RemoveAllAlarmList();
-        }          
-        
+        }
+
     }
 }

+ 7 - 6
Framework/Common/CommonData/AlarmList.cs

@@ -25,7 +25,7 @@ namespace MECF.Framework.Common.CommonData
         /// 当前步骤
         /// </summary>
         [DataMember]
-        public int ModuleStep {  get; set; }
+        public int ModuleStep { get; set; }
         /// <summary>
         /// 模块指令
         /// </summary>
@@ -42,7 +42,7 @@ namespace MECF.Framework.Common.CommonData
         [DataMember]
         public string DataItem { get; set; }
         /// <summary>
-        /// 报警类型(0-错误,1-警告)
+        /// 报警类型(0-错误,1-警告,2-数据错误)
         /// </summary>
         [DataMember]
         public int AlarmType { get; set; }
@@ -63,7 +63,7 @@ namespace MECF.Framework.Common.CommonData
         /// <param name="moduleState"></param>
         /// <param name="moduleCmd"></param>
         /// <param name="alarmMsg"></param>
-        public AlarmList(string moduleName, string moduleState, int moduleCmd, string alarmMsg,int step,int alarmType)
+        public AlarmList(string moduleName, string moduleState, int moduleCmd, string alarmMsg, int step, int alarmType)
         {
             ModuleName = moduleName;
             ModuleState = moduleState;
@@ -84,7 +84,7 @@ namespace MECF.Framework.Common.CommonData
         public void Clone(AlarmList alarmList)
         {
             ModuleCmd = alarmList.ModuleCmd;
-            ModuleState=alarmList.ModuleState;
+            ModuleState = alarmList.ModuleState;
             ModuleStep = alarmList.ModuleStep;
             AlarmMsg = alarmList.AlarmMsg;
             AlarmType = alarmList.AlarmType;
@@ -94,7 +94,8 @@ namespace MECF.Framework.Common.CommonData
 
     public enum AlarmType
     {
-        Error=0,
-        Warning=1
+        Error = 0,
+        Warning = 1,
+        DataError = 2
     }
 }

+ 3 - 0
Framework/Common/CommonData/Reservoir/StandardHotReservoirData.cs

@@ -18,6 +18,7 @@ namespace MECF.Framework.Common.CommonData.Reservoir
         private double _waterLevel;
         private bool _lowLevel;
         private bool _highLevel;
+        private bool _safetyHighLevel;
         private double _hedFlow;
         private List<bool> _replenLevel;
         #endregion
@@ -38,6 +39,8 @@ namespace MECF.Framework.Common.CommonData.Reservoir
         public bool LowLevel { get { return _lowLevel; } set { _lowLevel = value; InvokePropertyChanged(nameof(LowLevel)); } }
 
         public bool HighLevel { get { return _highLevel; } set { _highLevel = value; InvokePropertyChanged(nameof(HighLevel)); } }
+        
+        public bool SafetyHighLevel { get { return _safetyHighLevel; } set { _safetyHighLevel = value; InvokePropertyChanged(nameof(SafetyHighLevel)); } }
 
         public double HedFlow { get { return _hedFlow; } set { _hedFlow = value;InvokePropertyChanged(nameof(HedFlow)); } } 
 

+ 18 - 13
Framework/Common/DBCore/MetalUsageRecorder.cs

@@ -39,12 +39,15 @@ namespace MECF.Framework.Common.DBCore
                 data.MetalName = ds.Tables[0].Rows[i]["metal_name"].ToString();
                 data.TotalUsage = double.Parse(ds.Tables[0].Rows[i]["total_usage"].ToString());
                 data.AnodeAUsage = double.Parse(ds.Tables[0].Rows[i]["anode_a_usage"].ToString());
-                data.AnodeBUsage= double.Parse(ds.Tables[0].Rows[i]["anode_b_usage"].ToString());
-                data.MembranceAUsage= double.Parse(ds.Tables[0].Rows[i]["membrance_a_usage"].ToString());
-                data.MembranceBUsage= double.Parse(ds.Tables[0].Rows[i]["membrance_b_usage"].ToString());
+                data.AnodeBUsage = double.Parse(ds.Tables[0].Rows[i]["anode_b_usage"].ToString());
+                data.MembranceAUsage = double.Parse(ds.Tables[0].Rows[i]["membrance_a_usage"].ToString());
+                data.MembranceBUsage = double.Parse(ds.Tables[0].Rows[i]["membrance_b_usage"].ToString());
                 data.TotalWafers = int.Parse(ds.Tables[0].Rows[i]["total_wafers"].ToString());
                 data.AnodeAWafers = int.Parse(ds.Tables[0].Rows[i]["anode_a_wafers"].ToString());
                 data.AnodeBWafers = int.Parse(ds.Tables[0].Rows[i]["anode_b_wafers"].ToString());
+                data.AnodeABathUsage = int.Parse(ds.Tables[0].Rows[i]["anode_a_bath_usage"].ToString());
+                data.AnodeBBathUsage = int.Parse(ds.Tables[0].Rows[i]["anode_b_bath_usage"].ToString());
+                data.BathResetTime = DateTime.Parse(ds.Tables[0].Rows[i]["bath_reset_time"].ToString());
                 result.Add(data);
             }
 
@@ -60,11 +63,11 @@ namespace MECF.Framework.Common.DBCore
         /// <returns></returns>
         public static int AddMetalUsage(MetalUsage info)
         {
-            string sql =string.Format(@"Insert into metal_usage(metal_name, total_usage,anode_a_usage,anode_b_usage,membrance_a_usage,
-                                 membrance_b_usage,total_wafers,anode_a_wafers,anode_b_wafers,create_time, update_time)
-                Values('{0}',{1},{2},{3},{4},{5},{6},{7},{8},'{9}','{10}');",
-                        info.MetalName,info.TotalUsage,info.AnodeAUsage,info.AnodeBUsage,info.MembranceAUsage,info.MembranceBUsage,
-                        info.TotalWafers,info.AnodeAWafers,info.AnodeBWafers, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
+            string sql = string.Format(@"Insert into metal_usage(metal_name, total_usage,anode_a_usage,anode_b_usage,membrance_a_usage,
+                                 membrance_b_usage,total_wafers,anode_a_wafers,anode_b_wafers,anode_a_bath_usage,anode_b_bath_usage,bath_reset_time,create_time, update_time)
+                Values('{0}',{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},'{11}','{12}','{13}');",
+                        info.MetalName, info.TotalUsage, info.AnodeAUsage, info.AnodeBUsage, info.MembranceAUsage, info.MembranceBUsage,
+                        info.TotalWafers, info.AnodeAWafers, info.AnodeBWafers, info.AnodeABathUsage, info.AnodeBBathUsage, info.BathResetTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
             return DB.SyncInsert(sql);
         }
         /// <summary>
@@ -77,9 +80,10 @@ namespace MECF.Framework.Common.DBCore
         {
             string sql = string.Format(@"update metal_usage set total_usage={0},anode_a_usage={1},anode_b_usage={2},
                             membrance_a_usage={3},membrance_b_usage={4},total_wafers={5},anode_a_wafers={6},
-                            anode_b_wafers={7},update_time='{8}' where metal_name='{9}';",
-                        info.TotalUsage, info.AnodeAUsage, info.AnodeBUsage,info.MembranceAUsage, info.MembranceBUsage, 
-                        info.TotalWafers, info.AnodeAWafers,info.AnodeBWafers,DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),metalName);
+                            anode_b_wafers={7},anode_a_bath_usage={8},anode_b_bath_usage={9},bath_reset_time='{10}',update_time='{11}' where metal_name='{12}';",
+                        info.TotalUsage, info.AnodeAUsage, info.AnodeBUsage, info.MembranceAUsage, info.MembranceBUsage,
+                        info.TotalWafers, info.AnodeAWafers, info.AnodeBWafers, info.AnodeABathUsage, info.AnodeBBathUsage, info.BathResetTime.ToString("yyyy-MM-dd HH:mm:ss.fff"),
+                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), metalName);
             DB.Update(sql);
         }
 
@@ -93,9 +97,10 @@ namespace MECF.Framework.Common.DBCore
         {
             string sql = string.Format(@"update metal_usage set total_usage={0},anode_a_usage={1},anode_b_usage={2},
                             membrance_a_usage={3},membrance_b_usage={4},total_wafers={5},anode_a_wafers={6},
-                            anode_b_wafers={7},update_time='{8}' where metal_name='{9}';",
+                            anode_b_wafers={7},anode_a_bath_usage={8},anode_b_bath_usage={9},bath_reset_time='{10}',update_time='{11}' where metal_name='{12}';",
                         info.TotalUsage, info.AnodeAUsage, info.AnodeBWafers, info.MembranceAUsage, info.MembranceBUsage,
-                        info.TotalWafers, info.AnodeAWafers, info.AnodeBWafers, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), metalName);
+                        info.TotalWafers, info.AnodeAWafers, info.AnodeBWafers, info.AnodeABathUsage, info.AnodeBBathUsage, info.BathResetTime.ToString("yyyy-MM-dd HH:mm:ss.fff"),
+                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), metalName);
             return DB.SyncUpdate(sql);
         }
     }

+ 9 - 9
Framework/Common/DBCore/ReservoirUsageRecorder.cs

@@ -39,8 +39,8 @@ namespace MECF.Framework.Common.DBCore
                 data.ReservoirName = ds.Tables[0].Rows[i]["reservoir_name"].ToString();
                 data.TotalUsage = double.Parse(ds.Tables[0].Rows[i]["total_usage"].ToString());
                 data.BathUsage = double.Parse(ds.Tables[0].Rows[i]["bath_usage"].ToString());
-                data.AnodeUsage= double.Parse(ds.Tables[0].Rows[i]["anode_usage"].ToString());
-                data.MembranceUsage= double.Parse(ds.Tables[0].Rows[i]["membrance_usage"].ToString());
+                data.AnodeUsage = double.Parse(ds.Tables[0].Rows[i]["anode_usage"].ToString());
+                data.MembranceUsage = double.Parse(ds.Tables[0].Rows[i]["membrance_usage"].ToString());
                 data.BathUsageDays = int.Parse(ds.Tables[0].Rows[i]["bath_usage_days"].ToString());
                 data.TotalWafers = int.Parse(ds.Tables[0].Rows[i]["total_wafers"].ToString());
                 data.BathResetTime = DateTime.Parse(ds.Tables[0].Rows[i]["bath_reset_time"].ToString());
@@ -60,12 +60,12 @@ namespace MECF.Framework.Common.DBCore
         /// <returns></returns>
         public static void AddReservoirUsage(ReservoirUsage info)
         {
-            string sql =string.Format(@"Insert into reservoir_usage(reservoir_name, total_usage,bath_usage,anode_usage,membrance_usage,
+            string sql = string.Format(@"Insert into reservoir_usage(reservoir_name, total_usage,bath_usage,anode_usage,membrance_usage,
                                  total_wafers,bath_usage_days,bath_reset_time,create_time, update_time, cmm_anode_usage, cmm_membrance_usage)
                 Values('{0}',{1},{2},{3},{4},{5},{6},'{7}','{8}','{9}','{10}','{11}');",
-                        info.ReservoirName,info.TotalUsage,info.BathUsage,info.AnodeUsage,info.MembranceUsage,
-                        info.TotalWafers,info.BathUsageDays,info.BathResetTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), 
-                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),info.CMMAnodeUsage,info.CMMMembranceUsage);
+                        info.ReservoirName, info.TotalUsage, info.BathUsage, info.AnodeUsage, info.MembranceUsage,
+                        info.TotalWafers, info.BathUsageDays, info.BathResetTime.ToString("yyyy-MM-dd HH:mm:ss.fff"),
+                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), info.CMMAnodeUsage, info.CMMMembranceUsage);
             DB.Insert(sql);
         }
         /// <summary>
@@ -79,9 +79,9 @@ namespace MECF.Framework.Common.DBCore
             string sql = string.Format(@"update reservoir_usage set total_usage={0},bath_usage={1},anode_usage={2},
                             membrance_usage={3},total_wafers={4},bath_usage_days={5},
                             bath_reset_time='{6}',update_time='{7}',cmm_anode_usage='{9}',cmm_membrance_usage='{10}' where reservoir_name='{8}';",
-                        info.TotalUsage, info.BathUsage, info.AnodeUsage,info.MembranceUsage, 
-                        info.TotalWafers, info.BathUsageDays,info.BathResetTime.ToString("yyyy-MM-dd HH:mm:ss.fff"),
-                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),reservoirName, info.CMMAnodeUsage, info.CMMMembranceUsage);
+                        info.TotalUsage, info.BathUsage, info.AnodeUsage, info.MembranceUsage,
+                        info.TotalWafers, info.BathUsageDays, info.BathResetTime.ToString("yyyy-MM-dd HH:mm:ss.fff"),
+                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), reservoirName, info.CMMAnodeUsage, info.CMMMembranceUsage);
             DB.Update(sql);
         }
 

+ 9 - 0
Framework/Common/ProcessCell/MetalUsage.cs

@@ -30,6 +30,15 @@ namespace MECF.Framework.Common.ProcessCell
         public int AnodeAWafers { get; set; }
         [DataMember]
         public int AnodeBWafers { get; set; }
+        [DataMember]
+        public int AnodeABathUsage { get; set; }
+        [DataMember]
+        public int AnodeBBathUsage { get; set; }
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [DataMember]
+        public DateTime BathResetTime { get; set; }
         /// <summary>
         /// 创建时间
         /// </summary>

+ 30 - 14
Framework/Common/ToolLayout/MetalUsageManager.cs

@@ -1,4 +1,5 @@
 using Aitex.Core.Util;
+using DocumentFormat.OpenXml.Spreadsheet;
 using MECF.Framework.Common.DBCore;
 using MECF.Framework.Common.ProcessCell;
 using System;
@@ -9,7 +10,7 @@ using System.Threading.Tasks;
 
 namespace MECF.Framework.Common.ToolLayout
 {
-    public class MetalUsageManager : Singleton<MetalUsageManager>   
+    public class MetalUsageManager : Singleton<MetalUsageManager>
     {
         #region 内部变量
         /// <summary>
@@ -23,7 +24,7 @@ namespace MECF.Framework.Common.ToolLayout
         public void Initialize()
         {
             List<MetalUsage> metalUsages = MetalUsageRecorder.GetAllMetalUsages();
-            foreach(var metalUsage in metalUsages)
+            foreach (var metalUsage in metalUsages)
             {
                 _metalUsageDictionary[metalUsage.MetalName] = metalUsage;
             }
@@ -33,31 +34,31 @@ namespace MECF.Framework.Common.ToolLayout
         /// </summary>
         /// <param name="metalName"></param>
         /// <param name="usage"></param>
-        public void UpdateMetalUsage(string metalName,string side,double anodeAUsage,double anodeBUsage)
+        public void UpdateMetalUsage(string metalName, string side, double anodeAUsage, double anodeBUsage)
         {
             MetalUsage metalUsage = null;
             bool isAdd = false;
             if (!_metalUsageDictionary.ContainsKey(metalName))
-            { 
-                metalUsage= new MetalUsage();
+            {
+                metalUsage = new MetalUsage();
                 metalUsage.MetalName = metalName;
                 _metalUsageDictionary[metalName] = metalUsage;
                 isAdd = true;
             }
             else
             {
-                metalUsage=_metalUsageDictionary[metalName];
+                metalUsage = _metalUsageDictionary[metalName];
             }
             int waferCount = 0;
             if (string.IsNullOrEmpty(side))
             {
                 metalUsage.AnodeAUsage += anodeAUsage;
                 metalUsage.AnodeBUsage += anodeBUsage;
-                metalUsage.MembranceAUsage+= anodeAUsage;
+                metalUsage.MembranceAUsage += anodeAUsage;
                 metalUsage.MembranceBUsage += anodeBUsage;
                 metalUsage.AnodeAWafers += 1;
                 metalUsage.AnodeBWafers += 1;
-                metalUsage.TotalUsage += anodeAUsage+anodeBUsage;
+                metalUsage.TotalUsage += anodeAUsage + anodeBUsage;
                 metalUsage.TotalWafers += 2;
                 waferCount = 2;
             }
@@ -79,28 +80,39 @@ namespace MECF.Framework.Common.ToolLayout
                 metalUsage.TotalWafers += 1;
                 waferCount = 1;
             }
+            DateTime now = DateTime.Now;
             if (isAdd)
             {
+                metalUsage.AnodeABathUsage = 0;
+                metalUsage.AnodeBBathUsage = 0;
+                metalUsage.BathResetTime = now;
                 MetalUsageRecorder.AddMetalUsage(metalUsage);
             }
             else
             {
+                int days = (int)Math.Floor(now.Subtract(metalUsage.BathResetTime).TotalDays);
+                if (days >= metalUsage.AnodeABathUsage)
+                {
+                    metalUsage.AnodeABathUsage = days;
+                }
+                if (days >= metalUsage.AnodeBBathUsage)
+                {
+                    metalUsage.AnodeBBathUsage = days;
+                }
                 MetalUsageRecorder.UpdateMetalUsageData(metalName, metalUsage);
             }
-
-            string reservoirName= ReservoirItemManager.Instance.GetReservoirByMetal(metalName);
-
+            string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(metalName);
             ReservoirUsageManager.Instance.UpdateReservoirUsage(reservoirName, anodeAUsage, anodeBUsage, waferCount);
         }
         /// <summary>
         /// 在PMCounter页面手动修改值
         /// </summary>
         /// <param name="metalName"></param>
-        public void UpdateMetalUsageByManualOperation(string metalName,string CounterName, string NewValue)
+        public void UpdateMetalUsageByManualOperation(string metalName, string CounterName, string NewValue)
         {
-            if(_metalUsageDictionary.ContainsKey(metalName))
+            if (_metalUsageDictionary.ContainsKey(metalName))
             {
-                switch (CounterName) 
+                switch (CounterName)
                 {
                     case "Total Usage(AHr)":
                         _metalUsageDictionary[metalName].TotalUsage = double.Parse(NewValue); break;
@@ -118,6 +130,10 @@ namespace MECF.Framework.Common.ToolLayout
                         _metalUsageDictionary[metalName].AnodeAWafers = int.Parse(NewValue); break;
                     case "Anode B Total Wafers":
                         _metalUsageDictionary[metalName].AnodeBWafers = int.Parse(NewValue); break;
+                    case "Anode A bath Usage(Days)":
+                        _metalUsageDictionary[metalName].AnodeABathUsage = int.Parse(NewValue); break;
+                    case "Anode B bath Usage(Days)":
+                        _metalUsageDictionary[metalName].AnodeBBathUsage = int.Parse(NewValue); break;
                 }
                 MetalUsageRecorder.UpdateMetalUsageData(metalName, _metalUsageDictionary[metalName]);
             }

+ 2 - 2
Framework/Common/ToolLayout/ReservoirUsageManager.cs

@@ -41,7 +41,7 @@ namespace MECF.Framework.Common.ToolLayout
         /// </summary>
         /// <param name="metalName"></param>
         /// <param name="usage"></param>
-        public void UpdateReservoirUsage(string reservoirName, double anodeAUsage, double anodeBUsage,int waferCount)
+        public void UpdateReservoirUsage(string reservoirName, double anodeAUsage, double anodeBUsage, int waferCount)
         {
             if (!_reservoirLockDictionary.ContainsKey(reservoirName))
             {
@@ -69,7 +69,7 @@ namespace MECF.Framework.Common.ToolLayout
                 reservoirUsage.AnodeUsage += anodeAUsage + anodeBUsage;
                 reservoirUsage.MembranceUsage += anodeAUsage + anodeBUsage;
                 reservoirUsage.TotalWafers += waferCount;
-                DateTime now=DateTime.Now;
+                DateTime now = DateTime.Now;
 
                 if (isAdd)
                 {

+ 39 - 4
Framework/SimulatorCore/Commons/TemperatureControllerSerialPortDevice.cs

@@ -49,18 +49,18 @@ namespace MECF.Framework.Simulator.Core.Commons
             { 0x48,"Saved" }
         };
 
-        private double[] _reserviorValues = { 16.6, 16.6, 16.6 };
+        private double[] _reserviorValues = { 16.6, 16.6, 16.6, 16.6 };
 
-        private double[] _heatValues = { 16.5, 16.5, 16.5 };
+        private double[] _heatValues = { 16.5, 16.5, 16.5, 16.5 };
 
-        private double[] _targetValues = { 0, 0, 0 };
+        private double[] _targetValues = { 0, 0, 0, 0 };
 
         private int _controlOperation = 0;
 
         //private byte[] alarm = new byte[12] { 0,0,0,0,1,0,0,0,0,0,0,0};
         private byte[] alarm = new byte[3] {0x30,0x33,0x30};
 
-        System.Timers.Timer[] _timers = new System.Timers.Timer[3];
+        System.Timers.Timer[] _timers = new System.Timers.Timer[4];
 
         #endregion
 
@@ -77,6 +77,8 @@ namespace MECF.Framework.Simulator.Core.Commons
             _timers[1].Elapsed += Timer_Elapsed1;
             _timers[2] = new System.Timers.Timer(50);
             _timers[2].Elapsed += Timer_Elapsed2;
+            _timers[3] = new System.Timers.Timer(50);
+            _timers[3].Elapsed += Timer_Elapsed3;
         }
         /// <summary>
         /// TC1-1的调温
@@ -177,6 +179,39 @@ namespace MECF.Framework.Simulator.Core.Commons
                 _timers[2].Stop();
             }
         }
+        /// <summary>
+        /// TC1-4的调温
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void Timer_Elapsed3(object sender, System.Timers.ElapsedEventArgs e)
+        {
+            if (Math.Abs(_heatValues[3] - _targetValues[3]) >= 0.2)
+            {
+                //内部调温
+                if (_heatValues[3] < _targetValues[3])
+                {
+                    _heatValues[3] += 0.1;
+                }
+                else
+                {
+                    _heatValues[3] -= 0.1;
+                }
+                //外部调温
+                if (_reserviorValues[3] < _targetValues[3])
+                {
+                    _reserviorValues[3] += 0.1;
+                }
+                else
+                {
+                    _reserviorValues[3] -= 0.1;
+                }
+            }
+            else
+            {
+                _timers[3].Stop();
+            }
+        }
         protected override string MessageConvert(byte[] byt)
         {
             string str = "";