CompactMembranReservoirDevice.cs 123 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723
  1. using Aitex.Core.RT.DataCenter;
  2. using Aitex.Core.RT.Device;
  3. using Aitex.Core.RT.Log;
  4. using Aitex.Core.RT.OperationCenter;
  5. using Aitex.Core.RT.RecipeCenter;
  6. using Aitex.Core.RT.SCCore;
  7. using Aitex.Core.Util;
  8. using MECF.Framework.Common.Beckhoff.ModuleIO;
  9. using MECF.Framework.Common.CommonData.Reservoir;
  10. using MECF.Framework.Common.Persistent.Reservoirs;
  11. using MECF.Framework.Common.TwinCat;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Reflection;
  15. using MECF.Framework.Common.RecipeCenter;
  16. using MECF.Framework.Common.ToolLayout;
  17. using System.Collections.ObjectModel;
  18. using MECF.Framework.Common.CommonData;
  19. using MECF.Framework.Common.Beckhoff.IOAxis;
  20. using System.Linq;
  21. using MECF.Framework.Common.Alarm;
  22. using MECF.Framework.Common.ProcessCell;
  23. using MECF.Framework.Common.Persistent.Temperature;
  24. using CyberX8_Core;
  25. using CyberX8_RT.Devices.Facilities;
  26. using CyberX8_RT.Devices.Metal;
  27. using CyberX8_RT.Devices.Reservoir;
  28. using CyberX8_RT.Devices.Safety;
  29. using CyberX8_RT.Devices.Temperature;
  30. using CyberX8_RT.Modules.Metal;
  31. using CyberX8_RT.Modules.Reservoir;
  32. using CyberX8_RT.Modules;
  33. using MECF.Framework.Common.IOCore;
  34. namespace CyberX8_RT.Devices.Reservoir
  35. {
  36. public class CompactMembranReservoirDevice : BaseDevice, IDevice
  37. {
  38. private enum ReservoirOperation
  39. {
  40. None,
  41. ManualANDiReplen,
  42. ManualCADiReplen,
  43. AutoANDiReplen,
  44. AutoCADiReplen
  45. }
  46. #region 常量
  47. private const string PERSISTENT_VALUE = "PersistentValue";
  48. private const string CA_DI_REPLEN = "CADiReplen";
  49. private const string AN_DI_REPLEN = "ANDiReplen";
  50. private const string CA_WATER_LEVEL = "CAWaterLevel";
  51. private const string AN_WATER_LEVEL = "ANWaterLevel";
  52. private const string AN_PUMP = "ANPump";
  53. private const string CROSS_DOSE_ENABLE = "CrossDoseEnable";
  54. private const string TRANSFER_PUMP_STM_STATUS = "TransferPumpSTMStatus";
  55. private const string TRANSFER_PUMP_POS_STATUS = "TransferPumpPOSStatus";
  56. private const string TRANSFER_ACTUAL_POSITION = "TransferActualPosition";
  57. private const string TRANSFER_PUMP_ENABLE = "TransferPumpEnable";
  58. private const string TRANSFER_PUMP_RESET = "TransferPumpReset";
  59. private const string TRANSFER_PUMP_EXECUTE = "TransferPumpExecute";
  60. private const string TRANSFER_PUMP_TARGET_POSITION = "TransferPumpTargetPosition";
  61. private const string TRANSFER_PUMP_SPEED = "TransferPumpSpeed";
  62. private const string TRANSFER_PUMP_START_TYPE = "TransferPumpStartType";
  63. private const string TRANSFER_PUMP_ACCELERATION = "TransferPumpAcceleration";
  64. private const string TRANSFER_PUMP_DECELERATION = "TransferPumpDeceleration";
  65. private const string AN_BYPASS_FLOW = "ANBypassFlow";
  66. private const string AN_A_DRAIN_PUMP = "ANADrainPump";
  67. private const string AN_B_DRAIN_PUMP = "ANBDrainPump";
  68. private const string AN_BY_PASS = "ANByPass";
  69. //private const string AN_SLIP_STREAM_PUMP = "ANSlipStreamPump";
  70. private const string AN_TRANSFER_FLOW = "ANTransferFlow";
  71. //private const string CA_SLIP_STREAM_PUMP = "CASlipStreamPump";
  72. private const string CA_PUMP_SPEED = "CAPumpSpeed";
  73. private const string CA_PUMP_RUNNING = "CAPumpRunning";
  74. private const string CA_HED_FLOW = "CAHedFlow";
  75. private const string CDA_FLOW_VALVE = "CDAFlowValve";
  76. private const string CA_BY_PASS = "CAByPass";
  77. private const string CA_PUMP_ENABLE = "CAPumpEnable";
  78. private const string EVAPORATORLEVEL = "EvaporatorLevel";
  79. private const string AN_BYPASS_COUNTERFLOW = "ANBypassFlow";
  80. private const string AN_SAMPLE_FLOW = "ANSampleFlow";
  81. private const string CA_SAMPLE_FLOW = "CASampleFlow";
  82. private const string STRATUS = "Stratus";
  83. private const string AUTO = "Auto";
  84. private const string COUNTER_VALUE = "CounterValue";
  85. private const string COUNTER_START = "Start";
  86. private const string COUNTER_STOP = "Stop";
  87. private const string COUNTER_RESET = "Reset";
  88. private const int ENABLE = 5;
  89. #endregion
  90. #region 内部变量
  91. /// <summary>
  92. /// AN Level取样平均值
  93. /// </summary>
  94. private double _avgANLevel;
  95. /// <summary>
  96. /// AN Level取样队列
  97. /// </summary>
  98. private Queue<double> _ANLevelSamples;
  99. /// <summary>
  100. /// CA Level取样平均值
  101. /// </summary>
  102. private double _avgCALevel;
  103. /// <summary>
  104. /// CA Level取样队列
  105. /// </summary>
  106. private Queue<double> _CALevelSamples;
  107. /// <summary>
  108. /// AN/CA level计算平均值取样数
  109. /// </summary>
  110. private int levelSampleCount;
  111. /// <summary>
  112. /// Prewet 持久性数值对象
  113. /// </summary>
  114. private ReservoirsPersistentValue _persistentValue;
  115. /// <summary>
  116. /// 变量是否初始化字典
  117. /// </summary>
  118. private Dictionary<string, bool> _variableInitializeDic = new Dictionary<string, bool>();
  119. /// <summary>
  120. /// 数据
  121. /// </summary>
  122. private CompactMembranReservoirData _reservoirData = new CompactMembranReservoirData();
  123. /// <summary>
  124. /// Recipe
  125. /// </summary>
  126. private ResRecipe _resRecipe;
  127. /// <summary>
  128. /// 阳极Pump速度
  129. /// </summary>
  130. private double _anPumpSpeed = 0;
  131. /// <summary>
  132. /// 阴极Pump速度
  133. /// </summary>
  134. private double _caPumpSpeed = 0;
  135. /// <summary>
  136. /// 定时器
  137. /// </summary>
  138. private PeriodicJob _periodicJob;
  139. /// <summary>
  140. /// 注水Helper
  141. /// </summary>
  142. private ReservoirDiReplenHelper _direplenHelper;
  143. /// <summary>
  144. /// 泵速Helper
  145. /// </summary>
  146. private ReservoirPumpSpeedHelper _pumpSpeedHelper;
  147. /// <summary>
  148. /// 当前操作
  149. /// </summary>
  150. private ReservoirOperation _currentOperation;
  151. /// <summary>
  152. /// 手动注水时间(秒)
  153. /// </summary>
  154. private int _manualReplenSecond = 0;
  155. /// <summary>
  156. /// 注水是否出错
  157. /// </summary>
  158. private bool _isDiReplenInFault = false;
  159. /// <summary>
  160. /// Fast leak Test时间间隔
  161. /// </summary>
  162. private int _aNLeakOperatingUpdateTime;
  163. /// <summary>
  164. /// Fast leak Test Tolerance Value
  165. /// </summary>
  166. private double _aNFastLeakLevelTolerance;
  167. /// <summary>
  168. /// 计时器是否正在运行
  169. /// </summary>
  170. private bool _isTestRunning = false;
  171. /// <summary>
  172. /// 是否检测到漏液
  173. /// </summary>
  174. private bool _isLeakDetected = false;
  175. /// <summary>
  176. /// 漏液的体积
  177. /// </summary>
  178. private double _leakVolume;
  179. /// <summary>
  180. /// 开始检测slow leak test时的ANLevel
  181. /// </summary>
  182. private double _StartSlowLeakTestANLevel;
  183. /// <summary>
  184. /// 配置的metal device集合
  185. /// </summary>
  186. private ObservableCollection<CompactMembranMetalDevice> _metalDevices = new ObservableCollection<CompactMembranMetalDevice>();
  187. /// <summary>
  188. /// 是否存在anflow有流量
  189. /// </summary>
  190. private bool _isHasAnFlow;
  191. /// <summary>
  192. /// 是否存在metal 在auto模式
  193. /// </summary>
  194. private bool _isHasMetalInAuto;
  195. /// <summary>
  196. /// 设备是否进行过初始化
  197. /// </summary>
  198. private bool _isInitialized;
  199. /// <summary>
  200. /// 是否安装CrossDose
  201. /// </summary>
  202. private bool _isCrossDoseInstalled;
  203. /// <summary>
  204. /// fastleaktest的开始时间
  205. /// </summary>
  206. private DateTime _fastLeakStartTime;
  207. /// <summary>
  208. /// slowleaktest的开始时间
  209. /// </summary>
  210. private DateTime _slowLeakStartTime;
  211. /// <summary>
  212. /// fastleak 测试时间间隔
  213. /// </summary>
  214. private TimeSpan _fastLeakTestSpan;
  215. /// <summary>
  216. /// slowleak 测试时间间隔
  217. /// </summary>
  218. private TimeSpan _slowLeakTestSpan;
  219. /// <summary>
  220. /// clearLeakVolumeTime
  221. /// </summary>
  222. private double _clearLeakVolumeTime;
  223. /// <summary>
  224. /// ANTransferFlow(CrossDose Flow)
  225. /// </summary>
  226. private CounterFlowData _anTransferFlow = new CounterFlowData();
  227. /// <summary>
  228. /// ReservoirANByPassCounterFlow
  229. /// </summary>
  230. private CounterFlowData _reservoirCounterByPassFlow = new CounterFlowData();
  231. /// <summary>
  232. /// Counter字典
  233. /// </summary>
  234. private Dictionary<string, CounterFlowData> _nameCounterFlowData = new Dictionary<string, CounterFlowData>();
  235. /// <summary>
  236. /// CrossDoseHelper
  237. /// </summary>
  238. private CrossDoseHelper _crossDoseHelper;
  239. /// <summary>
  240. /// CrossDose是否初始化
  241. /// </summary>
  242. private bool _isCrossDoseInitialized;
  243. /// <summary>
  244. /// WarningFlag
  245. /// </summary>
  246. private List<bool> _isCAFlowRateWARN;
  247. private List<bool> _isANAFlowRateWARN;
  248. private List<bool> _isANBFlowRateWARN;
  249. private bool _isTCControlWARN = false;
  250. /// <summary>
  251. /// flow fault hold off时长
  252. /// </summary>
  253. private int _flowFaultHoldOffTime = 10;
  254. private DateTime _AnPumpSafeDetectTime;
  255. private double _metalTotalFlow;
  256. /// <summary>
  257. /// ErrorMessage
  258. /// </summary>
  259. private bool _isAnPumpSafeDetectedActivate = false;
  260. private bool _isANAutoDIReplenError = false;
  261. private bool _isCAAutoDIReplenError = false;
  262. private bool _isSystemAutoMode = false;
  263. /// <summary>
  264. /// 用于控制打印错误log
  265. /// </summary>
  266. private HashSet<string> errorLogSet = new HashSet<string>();
  267. #endregion
  268. #region 属性
  269. /// <summary>
  270. /// 数据
  271. /// </summary>
  272. public CompactMembranReservoirData ReservoirData { get { return _reservoirData; } }
  273. /// <summary>
  274. /// 操作模式
  275. /// </summary>
  276. public string OperationMode { get { return _persistentValue.OperatingMode; } }
  277. /// <summary>
  278. /// 工程模式
  279. /// </summary>
  280. public string EngineerMode { get { return _persistentValue.RecipeOperatingMode; } }
  281. /// <summary>
  282. /// 阳极是否需要补水
  283. /// </summary>
  284. public bool AnNeedDireplen { get { return CheckANNeedDiReplen(); } }
  285. /// <summary>
  286. /// 阴极是否需要补水
  287. /// </summary>
  288. public bool CANeedDiReplen { get { return CheckCANeedDiReplen(); } }
  289. /// <summary>
  290. /// 检验阴极是否highlevel
  291. /// </summary>
  292. public bool IsCAHighLevel { get { return CheckCAHighLevelStatus(); } }
  293. /// <summary>
  294. /// 检验阴极是否lowlevel
  295. /// </summary>
  296. public bool IsCALowLevel { get { return CheckCALowLevelStatus(); } }
  297. /// <summary>
  298. /// 检验阳极是否highlevel
  299. /// </summary>
  300. public bool IsANHighLevel { get { return CheckANHighLevelStatus(); } }
  301. /// <summary>
  302. /// 检验阳极是否lowlevel
  303. /// </summary>
  304. public bool IsANLowLevel { get { return CheckANLowLevelStatus(); } }
  305. /// <summary>
  306. /// 正在补水
  307. /// </summary>
  308. public bool IsDireplenOn { get { return _reservoirData.ANDiReplen || _reservoirData.CADiReplen; } }
  309. /// <summary>
  310. /// 当前Recipe
  311. /// </summary>
  312. public ResRecipe Recipe { get { return _resRecipe; } }
  313. /// <summary>
  314. /// 是否自动模式
  315. /// </summary>
  316. public bool IsAuto { get { return _persistentValue.OperatingMode == AUTO; } }
  317. /// <summary>
  318. /// ANTransferFlow
  319. /// </summary>
  320. public CounterFlowData ANTransferFlow { get { return _anTransferFlow; } }
  321. /// <summary>
  322. /// ReservoirCounterByPassFlow
  323. /// </summary>
  324. public CounterFlowData ReservoirCounterByPassFlow { get { return _reservoirCounterByPassFlow; } }
  325. #endregion
  326. /// <summary>
  327. /// 初始化成功清除对应的错误log
  328. /// </summary>
  329. /// <param name="module"></param>
  330. public void ClearErrorLogSet(string module)
  331. {
  332. // 使用构造函数复制 HashSet
  333. HashSet<string> newHashSet = new HashSet<string>(errorLogSet);
  334. foreach (var item in newHashSet)
  335. {
  336. if (item.Contains(module))
  337. {
  338. errorLogSet.Remove(item);
  339. }
  340. }
  341. }
  342. /// <summary>
  343. /// 构造函数
  344. /// </summary>
  345. /// <param name="moduleName"></param>
  346. /// <param name="name"></param>
  347. public CompactMembranReservoirDevice(string moduleName) : base(moduleName, moduleName, moduleName, moduleName)
  348. {
  349. _anPumpSpeed = SC.GetValue<double>($"Reservoir.ANDefaultPumpSpeed");
  350. _caPumpSpeed = SC.GetValue<double>("Reservoir.CADefaultPumpSpeed");
  351. _aNLeakOperatingUpdateTime = SC.GetValue<int>($"Reservoir.{Module}.ANLeakOperatingUpdateTime");
  352. _aNFastLeakLevelTolerance = SC.GetValue<double>($"Reservoir.{Module}.ANFastLeakLevelTolerance");
  353. _clearLeakVolumeTime = SC.GetValue<double>($"Reservoir.{Module}.CleraLeakVolumeTime");
  354. _flowFaultHoldOffTime = SC.GetValue<int>($"Reservoir.{Module}.FlowFaultHoldOffTime") / 1000;
  355. levelSampleCount = SC.GetValue<int>("Reservoir.LevelAvgSamples");
  356. levelSampleCount = levelSampleCount == 0 ? 20 : levelSampleCount;
  357. _ANLevelSamples = new Queue<double>(levelSampleCount);
  358. _CALevelSamples = new Queue<double>(levelSampleCount);
  359. _periodicJob = new PeriodicJob(200, OnTimer, $"{Module}.Timer", true, true);
  360. double updateTime = _aNLeakOperatingUpdateTime > 0 ? Convert.ToDouble(_aNLeakOperatingUpdateTime) : 3.00;//配置文件没有则默认3分钟
  361. _fastLeakTestSpan = TimeSpan.FromMinutes(updateTime);
  362. //slow leak test 时间间隔一个小时,因为leak test开始后要等待clearleakvolumeTime重新开始,因此时间间隔就等于两者相加,第一次执行减掉就行。
  363. _slowLeakTestSpan = TimeSpan.FromMinutes(60) + TimeSpan.FromMinutes(_clearLeakVolumeTime);
  364. }
  365. /// <summary>
  366. /// 初始化
  367. /// </summary>
  368. /// <returns></returns>
  369. public bool Initialize()
  370. {
  371. InitializeParameter();
  372. InitializeRoutine();
  373. SubscribeData();
  374. InitializeOperation();
  375. SubscribeValueAction();
  376. return true;
  377. }
  378. /// <summary>
  379. /// 初始化Routine
  380. /// </summary>
  381. private void InitializeRoutine()
  382. {
  383. }
  384. /// <summary>
  385. /// 初始化参数
  386. /// </summary>
  387. private void InitializeParameter()
  388. {
  389. _persistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(Module);
  390. if (_persistentValue == null)
  391. {
  392. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Persistent Value Object is not exist");
  393. }
  394. if (!string.IsNullOrEmpty(_persistentValue.Recipe))
  395. {
  396. _resRecipe = RecipeFileManager.Instance.LoadGenericityRecipe<ResRecipe>(_persistentValue.Recipe);
  397. }
  398. _direplenHelper = new ReservoirDiReplenHelper(Module, _persistentValue);
  399. _pumpSpeedHelper = new ReservoirPumpSpeedHelper(Module, this);
  400. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
  401. if (reservoirItem != null)
  402. {
  403. foreach (var item in reservoirItem.MetalCells)
  404. {
  405. if (item.ModuleName != Module)
  406. {
  407. CompactMembranMetalDevice metalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(item.ModuleName);
  408. if (metalDevice != null)
  409. {
  410. _metalDevices.Add(metalDevice);
  411. }
  412. }
  413. }
  414. if (reservoirItem.CrossDoseType != "" && reservoirItem.CrossDoseType != "None")
  415. {
  416. _isCrossDoseInstalled = true;
  417. _crossDoseHelper = new CrossDoseHelper(Module);
  418. _isCrossDoseInitialized = false;
  419. }
  420. _isCAFlowRateWARN = new List<bool>(new bool[_metalDevices.Count]);
  421. _isANAFlowRateWARN = new List<bool>(new bool[_metalDevices.Count]);
  422. _isANBFlowRateWARN = new List<bool>(new bool[_metalDevices.Count]);
  423. }
  424. }
  425. /// <summary>
  426. /// 订阅数据
  427. /// </summary>
  428. private void SubscribeData()
  429. {
  430. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
  431. DATA.Subscribe($"{Module}.ReservoirData", () => _reservoirData, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  432. DATA.Subscribe($"{Module}.ReservoirAverageANLevel", () => _avgANLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  433. DATA.Subscribe($"{Module}.ReservoirAverageCALevel", () => _avgCALevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  434. DATA.Subscribe($"{Module}.{PERSISTENT_VALUE}", () => _persistentValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  435. DATA.Subscribe($"{Module}.ANPumpSpeed", () => _anPumpSpeed, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  436. DATA.Subscribe($"{Module}.CAPumpSpeed", () => _caPumpSpeed, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  437. DATA.Subscribe($"{Module}.RecipeName", () => (_resRecipe != null ? _resRecipe.Ppid : ""), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  438. DATA.Subscribe($"{Module}.ANLevel", () => _reservoirData.ANLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  439. DATA.Subscribe($"{Module}.CALevel", () => _reservoirData.CALevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  440. DATA.Subscribe($"{Module}.ANBypassFlow", () => _reservoirData.ANBypassFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  441. DATA.Subscribe($"{Module}.HedFlow", () => _reservoirData.CAHedFlow, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  442. DATA.Subscribe($"{Module}.CurrentRecipe", () => _resRecipe, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  443. DATA.Subscribe($"{Module}.DIValveMaxOnTime", () => SC.GetValue<double>($"Reservoir.{Module}.DIValveMaxOnTime") * 60, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  444. DATA.Subscribe($"{Module}.IsManualCAReplen", () => { return _currentOperation == ReservoirOperation.ManualCADiReplen; }, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  445. DATA.Subscribe($"{Module}.IsManualANReplen", () => { return _currentOperation == ReservoirOperation.ManualANDiReplen; }, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  446. DATA.Subscribe($"{Module}.IsCAHighLevel", () => IsCAHighLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  447. DATA.Subscribe($"{Module}.IsCALowLevel", () => IsCALowLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  448. DATA.Subscribe($"{Module}.IsANHighLevel", () => IsANHighLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  449. DATA.Subscribe($"{Module}.IsANLowLevel", () => IsANLowLevel, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  450. DATA.Subscribe($"{Module}.IsDIReplenInFault", () => _isDiReplenInFault, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  451. DATA.Subscribe($"{Module}.EvaporatorType", () => reservoirItem.EvaporatorType, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  452. DATA.Subscribe($"{Module}.CroseDoseType", () => reservoirItem.CrossDoseType, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  453. DATA.Subscribe($"{Module}.IsLeakDetected", () => _isLeakDetected, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  454. DATA.Subscribe($"{Module}.IsCrossDoseInstalled", () => _isCrossDoseInstalled, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  455. DATA.Subscribe($"{Module}.ANBypassCounterFlow", () => ReservoirCounterByPassFlow.CounterValue, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  456. if (_isCrossDoseInstalled)
  457. {
  458. DATA.Subscribe($"{Module}.ANTransferFlow", () => ANTransferFlow != null ? ANTransferFlow.CounterValue : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  459. DATA.Subscribe($"{Module}.IsCalibrateEnable", () => (_crossDoseHelper != null && _crossDoseHelper.CrossDoseState == RState.Running) ? false : true, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  460. }
  461. }
  462. /// <summary>
  463. /// 初始化操作
  464. /// </summary>
  465. private void InitializeOperation()
  466. {
  467. OP.Subscribe($"{Module}.DisabledAction", DisabledOperation);
  468. OP.Subscribe($"{Module}.ManualAction", ManualOperation);
  469. OP.Subscribe($"{Module}.AutoAction", AutoOperation);
  470. OP.Subscribe($"{Module}.EngineeringModeAction", EngineeringModeOperation);
  471. OP.Subscribe($"{Module}.ProductionModeAction", ProductionModeOperation);
  472. OP.Subscribe($"{Module}.LoadRecipe", LoadRecipeOperation);
  473. OP.Subscribe($"{Module}.AnPumpOn", AnPumpOnOperation);
  474. OP.Subscribe($"{Module}.ANPumpSpeed", ANPumpSpeed);
  475. OP.Subscribe($"{Module}.AnPumpOff", AnPumpOffOperation);
  476. OP.Subscribe($"{Module}.AnADrainPumpOn", AnADrainPumpOn);
  477. OP.Subscribe($"{Module}.AnADrainPumpOff", AnADrainPumpOff);
  478. OP.Subscribe($"{Module}.AnBDrainPumpOn", AnBDrainPumpOn);
  479. OP.Subscribe($"{Module}.AnBDrainPumpOff", AnBDrainPumpOff);
  480. OP.Subscribe($"{Module}.ANDiReplenOn", ANDiReplenOnOperation);
  481. OP.Subscribe($"{Module}.ANDiReplenOff", ANDiReplenOff);
  482. OP.Subscribe($"{Module}.ANByPassOn", ANByPassOn);
  483. OP.Subscribe($"{Module}.ANByPassOff", ANByPassOff);
  484. OP.Subscribe($"{Module}.CAPumpOn", CAPumpOn);
  485. OP.Subscribe($"{Module}.CAPumpSpeed", CAPumpSpeedOperation);
  486. OP.Subscribe($"{Module}.CAPumpOff", CAPumpOff);
  487. OP.Subscribe($"{Module}.CADiReplenOn", CADiReplenOnOperation);
  488. OP.Subscribe($"{Module}.CADiReplenOff", CADiReplenOff);
  489. OP.Subscribe($"{Module}.CDAFlowOn", CDAFlowOn);
  490. OP.Subscribe($"{Module}.CDAFlowOff", CDAFlowOff);
  491. OP.Subscribe($"{Module}.CAByPassOn", CAByPassOn);
  492. OP.Subscribe($"{Module}.CAByPassOff", CAByPassOff);
  493. OP.Subscribe($"{Module}.ANSampleOn", ANSampleOn);
  494. OP.Subscribe($"{Module}.ANSampleOff", ANSampleOff);
  495. OP.Subscribe($"{Module}.CASampleOn", CASampleOn);
  496. OP.Subscribe($"{Module}.CASampleOff", CASampleOff);
  497. OP.Subscribe($"{Module}.ManualANDiReplen", ManualANDiReplen);
  498. OP.Subscribe($"{Module}.ManualCADiReplen", ManualCADiReplen);
  499. OP.Subscribe($"{Module}.BaseLineKeyDown", BaseLineKeyDownAction);
  500. OP.Subscribe($"{Module}.StartLeakTest", StartLeakTestAction);
  501. OP.Subscribe($"{Module}.ResetTotalTime", ResetTotalTime);
  502. OP.Subscribe($"{Module}.ClearSlowLeak", ClearSlowLeak);
  503. if (_isCrossDoseInstalled)
  504. {
  505. OP.Subscribe($"{Module}.StartDosing", StartDosing);
  506. OP.Subscribe($"{Module}.HaltDosing", HaltDosing);
  507. OP.Subscribe($"{Module}.SetPumpFactor", SetPumpFactor);
  508. OP.Subscribe($"{Module}.CrossDoseOn", CrossDoseOn);
  509. OP.Subscribe($"{Module}.CrossDoseOff", CrossDoseOff);
  510. OP.Subscribe($"{Module}.ResetCrossDose", ResetCrossDose);
  511. }
  512. }
  513. #region Operation
  514. /// <summary>
  515. /// 重置时长
  516. /// </summary>
  517. /// <param name="cmd"></param>
  518. /// <param name="objs"></param>
  519. /// <returns></returns>
  520. private bool ResetTotalTime(string cmd, object[] objs)
  521. {
  522. _persistentValue.TotalReplen = 0;
  523. _persistentValue.LastTotalReplen = 0;
  524. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  525. return true;
  526. }
  527. /// <summary>
  528. /// DisabledAction
  529. /// </summary>
  530. /// <param name="cmd"></param>
  531. /// <param name="param"></param>
  532. /// <returns></returns>
  533. private bool DisabledOperation(string cmd, object[] args)
  534. {
  535. string currentOperation = "Disabled";
  536. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  537. if (_persistentValue != null && reservoirEntity != null && _persistentValue.OperatingMode != currentOperation)
  538. {
  539. string preOperation = _persistentValue.OperatingMode;
  540. if (reservoirEntity.IsBusy)
  541. {
  542. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} is Busy, can't switch to Disabled mode");
  543. return false;
  544. }
  545. if (_persistentValue.OperatingMode == "Auto" && reservoirEntity.IsMetalBusy)
  546. {
  547. string busymodule = "";
  548. if (_metalDevices != null)
  549. {
  550. foreach (var item in _metalDevices)
  551. {
  552. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(item.Module.ToString());
  553. if (metalEntity != null && metalEntity.IsBusy)
  554. {
  555. busymodule += metalEntity.Module.ToString() + "/";
  556. }
  557. }
  558. }
  559. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{busymodule} is Busy, can't switch to Disabled mode");
  560. return false;
  561. }
  562. foreach (var metalDevice in _metalDevices)
  563. {
  564. metalDevice.DisabledOperation("", null);
  565. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(metalDevice.Module);
  566. metalEntity.AbortRecipe(null);
  567. metalDevice.EnterDisabledOperation();
  568. }
  569. if (_isCrossDoseInstalled)
  570. {
  571. HaltDosing("", null);
  572. InitializeCrossDose(false);
  573. }
  574. EnterDisabledOperation();
  575. reservoirEntity.EnterInit();
  576. _persistentValue.OperatingMode = currentOperation;
  577. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
  578. }
  579. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  580. _currentOperation = ReservoirOperation.None;
  581. return true;
  582. }
  583. /// <summary>
  584. /// ManualAction
  585. /// </summary>
  586. /// <param name="cmd"></param>
  587. /// <param name="param"></param>
  588. /// <returns></returns>
  589. private bool ManualOperation(string cmd, object[] args)
  590. {
  591. string currentOperation = "Manual";
  592. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  593. if (_persistentValue != null && reservoirEntity != null && _persistentValue.OperatingMode != currentOperation)
  594. {
  595. string preOperation = _persistentValue.OperatingMode;
  596. if (reservoirEntity.IsBusy)
  597. {
  598. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} is Busy, can't switch to Manual mode");
  599. return false;
  600. }
  601. if (_persistentValue.OperatingMode == "Auto" && reservoirEntity.IsMetalBusy)
  602. {
  603. string busymodule = "";
  604. if (_metalDevices != null)
  605. {
  606. foreach (var item in _metalDevices)
  607. {
  608. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(item.Module.ToString());
  609. if (metalEntity != null && metalEntity.IsBusy)
  610. {
  611. busymodule += metalEntity.Module.ToString() + "/";
  612. }
  613. }
  614. }
  615. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{busymodule} is Busy, can't switch to Manual mode");
  616. return false;
  617. }
  618. foreach (var metalDevice in _metalDevices)
  619. {
  620. metalDevice.ManualOperation("", null);
  621. }
  622. if (_isCrossDoseInstalled) InitializeCrossDose(false);
  623. reservoirEntity.EnterInit();
  624. if (_reservoirData.ANDiReplen) ANDiReplenOff("", null);
  625. if (_reservoirData.CADiReplen) CADiReplenOff("", null);
  626. _persistentValue.OperatingMode = currentOperation;
  627. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
  628. }
  629. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  630. _currentOperation = ReservoirOperation.None;
  631. return true;
  632. }
  633. /// <summary>
  634. /// AutoAction
  635. /// </summary>
  636. /// <param name="cmd"></param>
  637. /// <param name="param"></param>
  638. /// <returns></returns>
  639. private bool AutoOperation(string cmd, object[] args)
  640. {
  641. if (IsANLowLevel || IsCALowLevel)
  642. {
  643. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"LowLevel is activated, can't switch to Auto mode");
  644. return false;
  645. }
  646. string currentOperation = "Auto";
  647. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  648. if (_persistentValue != null && reservoirEntity != null && _persistentValue.OperatingMode != currentOperation)
  649. {
  650. string preOperation = _persistentValue.OperatingMode;
  651. if (reservoirEntity.IsBusy)
  652. {
  653. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} is Busy, can't switch to Auto mode");
  654. return false;
  655. }
  656. if (_isCrossDoseInstalled) InitializeCrossDose(false);
  657. reservoirEntity.EnterInit();
  658. if (_reservoirData.ANDiReplen) ANDiReplenOff("", null);
  659. if (_reservoirData.CADiReplen) CADiReplenOff("", null);
  660. _isDiReplenInFault = false;
  661. _persistentValue.OperatingMode = currentOperation;
  662. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"Operating mode is switched from {preOperation} to {currentOperation}");
  663. }
  664. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  665. return true;
  666. }
  667. /// <summary>
  668. /// EngineeringModeAction
  669. /// </summary>
  670. /// <param name="cmd"></param>
  671. /// <param name="param"></param>
  672. /// <returns></returns>
  673. private bool EngineeringModeOperation(string cmd, object[] args)
  674. {
  675. string currentRecipeOperation = "Engineering";
  676. if (_persistentValue != null)
  677. {
  678. _persistentValue.RecipeOperatingMode = currentRecipeOperation;
  679. }
  680. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  681. return true;
  682. }
  683. /// <summary>
  684. /// ProductionAction
  685. /// </summary>
  686. /// <param name="cmd"></param>
  687. /// <param name="param"></param>
  688. /// <returns></returns>
  689. private bool ProductionModeOperation(string cmd, object[] args)
  690. {
  691. string currentRecipeOperation = "Production";
  692. if (_persistentValue != null)
  693. {
  694. _persistentValue.RecipeOperatingMode = currentRecipeOperation;
  695. }
  696. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  697. return true;
  698. }
  699. /// <summary>
  700. /// 加载Recipe
  701. /// </summary>
  702. /// <param name="cmd"></param>
  703. /// <param name="args"></param>
  704. /// <returns></returns>
  705. private bool LoadRecipeOperation(string cmd, object[] args)
  706. {
  707. _persistentValue.Recipe = args[0].ToString();
  708. string[] fileRoute = _persistentValue.Recipe.Split('\\');
  709. string recipeRoute = "";
  710. if (fileRoute.Length > 2)
  711. {
  712. recipeRoute = fileRoute[fileRoute.Length - 2];
  713. }
  714. _resRecipe = RecipeFileManager.Instance.LoadGenericityRecipe<ResRecipe>(_persistentValue.Recipe);
  715. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module.ToString());
  716. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module.ToString(), $"Load {recipeRoute} Recipe {_resRecipe.Ppid} Success");
  717. return true;
  718. }
  719. /// <summary>
  720. /// Enter Disabled Operation
  721. /// </summary>
  722. /// <returns></returns>
  723. private void EnterDisabledOperation()
  724. {
  725. if (_reservoirData.CAPumpEnable)
  726. {
  727. CAPumpOff("CAPumpOff", null);
  728. }
  729. if (_reservoirData.ANPump > 0)
  730. {
  731. AnPumpOffOperation("", null);
  732. }
  733. if (_reservoirData.ANADrainPump > 0)
  734. {
  735. AnADrainPumpOff("", null);
  736. }
  737. if (_reservoirData.ANBDrainPump > 0)
  738. {
  739. AnBDrainPumpOff("", null);
  740. }
  741. if (_reservoirData.ANByPass)
  742. {
  743. ANByPassOff("", null);
  744. }
  745. if (_reservoirData.ANDiReplen)
  746. {
  747. ANDiReplenOff("", null);
  748. }
  749. if (_reservoirData.CADiReplen)
  750. {
  751. CADiReplenOff("", null);
  752. }
  753. }
  754. #endregion
  755. #region AN DiReplen
  756. /// <summary>
  757. /// 阳极DI Replen On
  758. /// </summary>
  759. /// <param name="cmd"></param>
  760. /// <param name="args"></param>
  761. /// <returns></returns>
  762. private bool ANDiReplenOnOperation(string cmd, object[] args)
  763. {
  764. return ANDiReplenOn(true);
  765. }
  766. /// <summary>
  767. /// 阳极DI Replen On
  768. /// </summary>
  769. /// <param name="showError"></param>
  770. /// <returns></returns>
  771. public bool ANDiReplenOn(bool showError)
  772. {
  773. if (IsANHighLevel)
  774. {
  775. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"ANHighLevel is activate,Can't do AN_DIReple");
  776. return false;
  777. }
  778. if (IsANLowLevel)
  779. {
  780. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"ANLowLevel is activate,Can't do AN_DIReple");
  781. return false;
  782. }
  783. bool preCondition = CheckPreDiReplenCondition(showError);
  784. if (!preCondition)
  785. {
  786. return false;
  787. }
  788. if (ReservoirData.CADiReplen)
  789. {
  790. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "CADiReplen is on");
  791. return false;
  792. }
  793. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_DI_REPLEN}");
  794. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  795. }
  796. /// <summary>
  797. /// 阳极DI Replen On
  798. /// </summary>
  799. /// <param name="cmd"></param>
  800. /// <param name="args"></param>
  801. /// <returns></returns>
  802. private bool ANDiReplenOff(string cmd, object[] args)
  803. {
  804. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_DI_REPLEN}");
  805. bool result = BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  806. if (result)
  807. {
  808. _persistentValue.IsDiReplenOn = false;
  809. if (_currentOperation == ReservoirOperation.ManualANDiReplen || _currentOperation == ReservoirOperation.AutoANDiReplen)
  810. {
  811. _currentOperation = ReservoirOperation.None;
  812. _persistentValue.LastTotalReplen = _persistentValue.TotalReplen;
  813. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  814. }
  815. }
  816. return result;
  817. }
  818. /// <summary>
  819. /// 检验DiReplen前置条件
  820. /// </summary>
  821. /// <returns></returns>
  822. public bool CheckPreDiReplenCondition(bool showError)
  823. {
  824. if (!CheckFacilitiesDiReplenStatus() && showError)
  825. {
  826. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Facilities DiReplen is Off");
  827. return false;
  828. }
  829. SafetyDevice safetyDevice = DEVICE.GetDevice<SafetyDevice>("Safety");
  830. if (safetyDevice != null && safetyDevice.SafetyData.ReservoirHighLevel)
  831. {
  832. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Safety high is Activate");
  833. return false;
  834. }
  835. if (CheckOtherReservoirDiReplenStatus(showError))
  836. {
  837. return false;
  838. }
  839. return true;
  840. }
  841. /// <summary>
  842. /// 检验总Di有没有开
  843. /// </summary>
  844. /// <returns></returns>
  845. private bool CheckFacilitiesDiReplenStatus()
  846. {
  847. SystemFacilities systemFacilities = DEVICE.GetDevice<SystemFacilities>("System.Facilities");
  848. if (systemFacilities != null)
  849. {
  850. return systemFacilities.DIReplenEnable;
  851. }
  852. return false;
  853. }
  854. /// <summary>
  855. /// 检验是否其他Reservoir Direplen已经
  856. /// </summary>
  857. /// <returns></returns>
  858. private bool CheckOtherReservoirDiReplenStatus(bool showError)
  859. {
  860. List<string> reservoirs = ReservoirItemManager.Instance.InstalledModules;
  861. foreach (string item in reservoirs)
  862. {
  863. if (item != Module)
  864. {
  865. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(item);
  866. if (reservoirItem.SubType == STRATUS)
  867. {
  868. StandardHotReservoirDevice tmpDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(item);
  869. if (tmpDevice.ReservoirData.DiReplen && showError)
  870. {
  871. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{item} direplen valve is on");
  872. return true;
  873. }
  874. }
  875. else
  876. {
  877. CompactMembranReservoirDevice tmpDevice = DEVICE.GetDevice<CompactMembranReservoirDevice>(item);
  878. if (tmpDevice.ReservoirData.ANDiReplen && showError)
  879. {
  880. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{item} ANDireplen valve is on");
  881. return true;
  882. }
  883. if (tmpDevice.ReservoirData.CADiReplen && showError)
  884. {
  885. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{item} CADireplen valve is on");
  886. return true;
  887. }
  888. }
  889. }
  890. }
  891. return false;
  892. }
  893. #endregion
  894. #region AnPump
  895. /// <summary>
  896. /// AN Pump On 操作
  897. /// </summary>
  898. /// <param name="cmd"></param>
  899. /// <param name="args"></param>
  900. /// <returns></returns>
  901. public bool AnPumpOnOperation(string cmd, object[] args)
  902. {
  903. double anPumpSpeed = SC.GetValue<double>($"Reservoir.ANDefaultPumpSpeed");
  904. return AnPump(anPumpSpeed);
  905. }
  906. /// <summary>
  907. /// AN Pump Off操作
  908. /// </summary>
  909. /// <param name="cmd"></param>
  910. /// <param name="args"></param>
  911. /// <returns></returns>
  912. private bool AnPumpOffOperation(string cmd, object[] args)
  913. {
  914. return AnPump(0);
  915. }
  916. /// <summary>
  917. /// AN Pump
  918. /// </summary>
  919. /// <param name="speed"></param>
  920. /// <returns></returns>
  921. public bool AnPump(double speed)
  922. {
  923. if (speed == 0) //关pump时关掉配置的metal的fill valve
  924. {
  925. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
  926. if (reservoirItem != null)
  927. {
  928. List<MetalItem> metalItems = reservoirItem.MetalCells;
  929. if (metalItems != null && metalItems.Count > 0)
  930. {
  931. foreach (MetalItem metalItem in metalItems)
  932. {
  933. if (metalItem.Installed)
  934. {
  935. CompactMembranMetalDevice metalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(metalItem.ModuleName);
  936. if (metalDevice != null)
  937. {
  938. metalDevice.AnSideAFillOff("ANAFillOff", null);
  939. metalDevice.AnSideBFillOff("ANBFillOff", null);
  940. }
  941. }
  942. }
  943. }
  944. }
  945. }
  946. SafetyDevice safetyDevice = DEVICE.GetDevice<SafetyDevice>("Safety");
  947. if (safetyDevice != null && !safetyDevice.SafetyData.PumpEdm)
  948. {
  949. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Safety PumpEdm is Activate");
  950. return false;
  951. }
  952. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_PUMP}");
  953. return BeckhoffIOManager.Instance.WriteIoValue(ioName, speed);
  954. }
  955. /// <summary>
  956. /// AN Pump调整速度
  957. /// </summary>
  958. /// <param name="cmd"></param>
  959. /// <param name="args"></param>
  960. /// <returns></returns>
  961. public bool ANPumpSpeed(string cmd, object[] args)
  962. {
  963. if (double.TryParse(args[0].ToString(), out double speed))
  964. {
  965. _anPumpSpeed = speed;
  966. if (_anPumpSpeed > 0)
  967. {
  968. _reservoirData.ANPump = _anPumpSpeed;
  969. }
  970. return AnPump(speed);
  971. }
  972. else
  973. {
  974. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{args[0]} is nor invalid speed");
  975. return false;
  976. }
  977. }
  978. #endregion
  979. #region AN Drain Pump
  980. /// <summary>
  981. /// 阳极A面Drain Pump On
  982. /// </summary>
  983. /// <param name="cmd"></param>
  984. /// <param name="args"></param>
  985. /// <returns></returns>
  986. public bool AnADrainPumpOn(string cmd, object[] args)
  987. {
  988. double speed = SC.GetValue<double>($"Reservoir.DrainSpeed");
  989. return AnADrainPump(speed);
  990. }
  991. /// <summary>
  992. /// 阳极A面Drain Pump Off
  993. /// </summary>
  994. /// <param name="cmd"></param>
  995. /// <param name="args"></param>
  996. /// <returns></returns>
  997. private bool AnADrainPumpOff(string cmd, object[] args)
  998. {
  999. return AnADrainPump(0);
  1000. }
  1001. /// <summary>
  1002. /// 阳极B面Drain Pump On
  1003. /// </summary>
  1004. /// <param name="cmd"></param>
  1005. /// <param name="args"></param>
  1006. /// <returns></returns>
  1007. public bool AnBDrainPumpOn(string cmd, object[] args)
  1008. {
  1009. double speed = SC.GetValue<double>($"Reservoir.DrainSpeed");
  1010. return AnBDrainPump(speed);
  1011. }
  1012. /// <summary>
  1013. /// 阳极B面Drain Pump Off
  1014. /// </summary>
  1015. /// <param name="cmd"></param>
  1016. /// <param name="args"></param>
  1017. /// <returns></returns>
  1018. private bool AnBDrainPumpOff(string cmd, object[] args)
  1019. {
  1020. return AnBDrainPump(0);
  1021. }
  1022. /// <summary>
  1023. /// 阳极A Drain Pump
  1024. /// </summary>
  1025. /// <param name="speed"></param>
  1026. /// <returns></returns>
  1027. public bool AnADrainPump(double speed)
  1028. {
  1029. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_A_DRAIN_PUMP}");
  1030. return BeckhoffIOManager.Instance.WriteIoValue(ioName, speed);
  1031. }
  1032. /// <summary>
  1033. /// 阳极B Drain Pump
  1034. /// </summary>
  1035. /// <param name="speed"></param>
  1036. /// <returns></returns>
  1037. public bool AnBDrainPump(double speed)
  1038. {
  1039. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_B_DRAIN_PUMP}");
  1040. return BeckhoffIOManager.Instance.WriteIoValue(ioName, speed);
  1041. }
  1042. #endregion
  1043. #region AN ByPass
  1044. /// <summary>
  1045. /// 阳极ByPass On
  1046. /// </summary>
  1047. /// <param name="cmd"></param>
  1048. /// <param name="args"></param>
  1049. /// <returns></returns>
  1050. private bool ANByPassOn(string cmd, object[] args)
  1051. {
  1052. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_BY_PASS}");
  1053. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  1054. }
  1055. /// <summary>
  1056. /// 阳极ByPass Off
  1057. /// </summary>
  1058. /// <param name="cmd"></param>
  1059. /// <param name="args"></param>
  1060. /// <returns></returns>
  1061. private bool ANByPassOff(string cmd, object[] args)
  1062. {
  1063. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_BY_PASS}");
  1064. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  1065. }
  1066. #endregion
  1067. #region CA Pump
  1068. /// <summary>
  1069. /// CA Pump调速
  1070. /// </summary>
  1071. /// <param name="cmd"></param>
  1072. /// <param name="args"></param>
  1073. /// <returns></returns>
  1074. private bool CAPumpSpeedOperation(string cmd, object[] args)
  1075. {
  1076. double caMaxPumpSpeed = 0;
  1077. if (SC.ContainsItem("Reservoir.CAMaxPumpSpeed"))
  1078. {
  1079. caMaxPumpSpeed = SC.GetValue<double>("Reservoir.CAMaxPumpSpeed");
  1080. }
  1081. if (double.TryParse(args[0].ToString(), out double speed))
  1082. {
  1083. _caPumpSpeed = speed;
  1084. if (_caPumpSpeed > caMaxPumpSpeed)
  1085. {
  1086. LOG.WriteLog(eEvent.WARN_METAL, Module, $"CA pump speed:{_caPumpSpeed} is over CA max pump speed {caMaxPumpSpeed}!");
  1087. return false;
  1088. }
  1089. return CAPumpSpeed(_caPumpSpeed);
  1090. }
  1091. else
  1092. {
  1093. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{args[0]} is nor invalid speed");
  1094. return false;
  1095. }
  1096. }
  1097. /// <summary>
  1098. /// 设置阴极泵速
  1099. /// </summary>
  1100. /// <param name="caPumpSpeed"></param>
  1101. /// <returns></returns>
  1102. public bool CAPumpSpeed(double caPumpSpeed)
  1103. {
  1104. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_SPEED}");
  1105. return BeckhoffIOManager.Instance.WriteIoValue(ioName, caPumpSpeed);
  1106. }
  1107. /// <summary>
  1108. /// 阴极Pump On
  1109. /// </summary>
  1110. /// <param name="cmd"></param>
  1111. /// <param name="args"></param>
  1112. /// <returns></returns>
  1113. private bool CAPumpOn(string cmd, object[] args)
  1114. {
  1115. double caPumpSpeed = SC.GetValue<double>("Reservoir.CADefaultPumpSpeed");
  1116. bool result = CAPumpSpeed(caPumpSpeed);
  1117. if (result)
  1118. {
  1119. string enableIOName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_ENABLE}");
  1120. return BeckhoffIOManager.Instance.WriteIoValue(enableIOName, true);
  1121. }
  1122. else
  1123. {
  1124. return false;
  1125. }
  1126. }
  1127. /// <summary>
  1128. /// 阴极Pump Off
  1129. /// </summary>
  1130. /// <param name="cmd"></param>
  1131. /// <param name="args"></param>
  1132. /// <returns></returns>
  1133. private bool CAPumpOff(string cmd, object[] args)
  1134. {
  1135. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_PUMP_ENABLE}");
  1136. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  1137. }
  1138. #endregion
  1139. #region CA DiReplen
  1140. /// <summary>
  1141. /// 阴极DI Replen On
  1142. /// </summary>
  1143. /// <param name="cmd"></param>
  1144. /// <param name="args"></param>
  1145. /// <returns></returns>
  1146. private bool CADiReplenOnOperation(string cmd, object[] args)
  1147. {
  1148. return CADiReplenOn(true);
  1149. }
  1150. /// <summary>
  1151. /// 阴极DI Replen On
  1152. /// </summary>
  1153. /// <param name="showError"></param>
  1154. /// <returns></returns>
  1155. private bool CADiReplenOn(bool showError)
  1156. {
  1157. bool preCondition = CheckPreDiReplenCondition(showError);
  1158. if (!preCondition)
  1159. {
  1160. return false;
  1161. }
  1162. if (IsCAHighLevel)
  1163. {
  1164. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CAHighLevel is activate,Can't do CA_DIReple");
  1165. return false;
  1166. }
  1167. if (IsCALowLevel)
  1168. {
  1169. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CALowLevel is activate,Can't do CA_DIReple");
  1170. return false;
  1171. }
  1172. if (ReservoirData.ANDiReplen)
  1173. {
  1174. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "ANDiReplen is on");
  1175. return false;
  1176. }
  1177. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_DI_REPLEN}");
  1178. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  1179. }
  1180. /// <summary>
  1181. /// 阴极DI Replen Off
  1182. /// </summary>
  1183. /// <param name="cmd"></param>
  1184. /// <param name="args"></param>
  1185. /// <returns></returns>
  1186. private bool CADiReplenOff(string cmd, object[] args)
  1187. {
  1188. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_DI_REPLEN}");
  1189. bool result = BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  1190. if (result)
  1191. {
  1192. _persistentValue.IsDiReplenOn = false;
  1193. if (_currentOperation == ReservoirOperation.ManualCADiReplen || _currentOperation == ReservoirOperation.AutoCADiReplen)
  1194. {
  1195. _currentOperation = ReservoirOperation.None;
  1196. _persistentValue.LastTotalReplen = _persistentValue.TotalReplen;
  1197. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  1198. }
  1199. }
  1200. return result;
  1201. }
  1202. #endregion
  1203. #region CDA Flow
  1204. /// <summary>
  1205. /// 阴极CDA Flow On
  1206. /// </summary>
  1207. /// <param name="cmd"></param>
  1208. /// <param name="args"></param>
  1209. /// <returns></returns>
  1210. private bool CDAFlowOn(string cmd, object[] args)
  1211. {
  1212. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CDA_FLOW_VALVE}");
  1213. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  1214. }
  1215. /// <summary>
  1216. /// 阴极CDA Flow Off
  1217. /// </summary>
  1218. /// <param name="cmd"></param>
  1219. /// <param name="args"></param>
  1220. /// <returns></returns>
  1221. private bool CDAFlowOff(string cmd, object[] args)
  1222. {
  1223. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CDA_FLOW_VALVE}");
  1224. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  1225. }
  1226. #endregion
  1227. #region CA ByPass
  1228. /// <summary>
  1229. /// 阴极ByPass On
  1230. /// </summary>
  1231. /// <param name="cmd"></param>
  1232. /// <param name="args"></param>
  1233. /// <returns></returns>
  1234. public bool CAByPassOn(string cmd, object[] args)
  1235. {
  1236. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_BY_PASS}");
  1237. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  1238. }
  1239. /// <summary>
  1240. /// 阴极ByPass Off
  1241. /// </summary>
  1242. /// <param name="cmd"></param>
  1243. /// <param name="args"></param>
  1244. /// <returns></returns>
  1245. public bool CAByPassOff(string cmd, object[] args)
  1246. {
  1247. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_BY_PASS}");
  1248. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  1249. }
  1250. #endregion
  1251. #region DiReplen Operation
  1252. /// <summary>
  1253. /// 手动阳极注水
  1254. /// </summary>
  1255. /// <param name="cmd"></param>
  1256. /// <param name="args"></param>
  1257. /// <returns></returns>
  1258. private bool ManualANDiReplen(string cmd, object[] args)
  1259. {
  1260. return ManualDiReplen(ANDiReplenOnOperation, ReservoirOperation.ManualANDiReplen, args[0].ToString());
  1261. }
  1262. /// <summary>
  1263. /// 手动阴极注水
  1264. /// </summary>
  1265. /// <param name="cmd"></param>
  1266. /// <param name="args"></param>
  1267. /// <returns></returns>
  1268. private bool ManualCADiReplen(string cmd, object[] args)
  1269. {
  1270. return ManualDiReplen(CADiReplenOnOperation, ReservoirOperation.ManualCADiReplen, args[0].ToString());
  1271. }
  1272. /// <summary>
  1273. /// 将前端输入的baseline更新到持久化文件
  1274. /// </summary>
  1275. /// <param name="cmd"></param>
  1276. /// <param name="args"></param>
  1277. /// <returns></returns>
  1278. private bool BaseLineKeyDownAction(string cmd, object[] args)
  1279. {
  1280. string variableName = args[0].ToString();
  1281. //baseline输入了一个不同的值的话,将新值写入持久化文件
  1282. if (_persistentValue.ANBaseLineLevel.ToString() != args[1].ToString())
  1283. {
  1284. PropertyInfo property = _persistentValue.GetType().GetProperty(variableName);
  1285. if (property != null)
  1286. {
  1287. property.SetValue(_persistentValue, args[1]);
  1288. }
  1289. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  1290. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" New ANBaseline {args[1]} was inputed");
  1291. _isTestRunning = false;
  1292. }
  1293. return true;
  1294. }
  1295. private bool StartLeakTestAction(string cmd, object[] args)
  1296. {
  1297. //前端重复点击start直接返回true;
  1298. if (_isTestRunning)
  1299. {
  1300. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Fast leak test has already started");
  1301. return true;
  1302. }
  1303. //判断是否启动fast leak test 参数【0】表示是否初始化,参数【1】表示是否有metal有流量
  1304. if ((bool)args[0] && (bool)args[1])
  1305. {
  1306. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Fast leak test is start");
  1307. _isTestRunning = true;
  1308. //记录fast leak test的开始时间
  1309. _fastLeakStartTime = DateTime.Now;
  1310. //记录slow leak test的开始时间,第一次的开始时间需要加上这个配置时间,正好使第一次执行slow leak test的时间间隔使为1小时。
  1311. _slowLeakStartTime = DateTime.Now + TimeSpan.FromMinutes(_clearLeakVolumeTime);
  1312. //记录slow leak test的开始液位
  1313. _StartSlowLeakTestANLevel = ReservoirData.ANLevel;
  1314. }
  1315. else
  1316. {
  1317. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Leak test precondition not met, stoped");
  1318. _isTestRunning = false;
  1319. }
  1320. return true;
  1321. }
  1322. /// Fast leak test
  1323. /// </summary>
  1324. /// <param name="sender"></param>
  1325. /// <param name="e"></param>
  1326. private bool FastLeakTestAction()
  1327. {
  1328. bool isHasMetalFlow = false;
  1329. foreach (var metalDevice in _metalDevices)
  1330. {
  1331. if (metalDevice.ANACellFlow.CounterValue > 0 || metalDevice.ANBCellFlow.CounterValue > 0)
  1332. {
  1333. isHasMetalFlow = true;
  1334. }
  1335. }
  1336. if (!isHasMetalFlow)
  1337. {
  1338. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" No ANFLow in {Module}, current fast leak test is skiped");
  1339. //更新_faseLeak的启动时间,使其可以自动周期性检测
  1340. _fastLeakStartTime = DateTime.Now;
  1341. return true;
  1342. }
  1343. double aNBaseLineLevel = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(Module).ANBaseLineLevel;
  1344. if (_reservoirData.ANLevel < aNBaseLineLevel - _aNFastLeakLevelTolerance)
  1345. {
  1346. _isLeakDetected = true; //用于前端页面指示灯
  1347. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $" Fast Leak was Detected,Current ANLevel is{_reservoirData.ANLevel},baseline is{aNBaseLineLevel}. Related pump and valve was closed");
  1348. AnPumpOffOperation($"{Module}.AnPumpOff", null);
  1349. //关闭对应的anolyte flow valve
  1350. foreach (var metalDevice in _metalDevices)
  1351. {
  1352. metalDevice.AnSideAFillOff($"{metalDevice.Name}.ANAFillOff", null);
  1353. metalDevice.AnSideBFillOff($"{metalDevice.Name}.ANBFillOff", null);
  1354. metalDevice.AnSideADrainOff($"{metalDevice.Name}.ANADrainOff", null);
  1355. metalDevice.AnSideBDrainOff($"{metalDevice.Name}.ANBDrainOff", null);
  1356. }
  1357. }
  1358. else
  1359. {
  1360. _isLeakDetected = false;
  1361. string variableName = "ANBaseLineLevel";
  1362. PropertyInfo property = _persistentValue.GetType().GetProperty(variableName);
  1363. if (property != null)
  1364. {
  1365. property.SetValue(_persistentValue, _reservoirData.ANLevel);
  1366. }
  1367. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  1368. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $"No fast leak test was Detected, leak test baseLine was updated");
  1369. }
  1370. //更新_faseLeak的启动时间,使其可以自动周期性检测
  1371. _fastLeakStartTime = DateTime.Now;
  1372. return true;
  1373. }
  1374. /// Slow leak test
  1375. /// </summary>
  1376. /// <param name="sender"></param>
  1377. /// <param name="e"></param>
  1378. private bool SlowLeakTestAction()
  1379. {
  1380. ReservoirEntity _reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  1381. if (_reservoirEntity != null && _reservoirEntity.IsInitialized)
  1382. {
  1383. _isInitialized = true;
  1384. }
  1385. else
  1386. {
  1387. _isInitialized = false;
  1388. }
  1389. if (_persistentValue.OperatingMode == AUTO)
  1390. {
  1391. foreach (var metalDevice in _metalDevices)
  1392. {
  1393. if (metalDevice.ANACellFlow.CounterValue > 0 || metalDevice.ANBCellFlow.CounterValue > 0)
  1394. {
  1395. _isHasAnFlow = true;
  1396. }
  1397. if ("Auto".Equals(metalDevice.OperationMode))
  1398. {
  1399. _isHasMetalInAuto = true;
  1400. }
  1401. }
  1402. if (_isHasAnFlow && _isHasMetalInAuto && _isInitialized)
  1403. {
  1404. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Slow leak test is start");
  1405. _leakVolume = ReservoirData.ANLevel - _StartSlowLeakTestANLevel;
  1406. if (_leakVolume > SC.GetValue<double>($"Reservoir.{Module}.MaxLeakVolume"))
  1407. {
  1408. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, " Slow leak was detected");
  1409. }
  1410. }
  1411. }
  1412. //更新当前液位
  1413. _StartSlowLeakTestANLevel = ReservoirData.ANLevel;
  1414. //更新启动时间
  1415. _slowLeakStartTime = DateTime.Now;
  1416. return true;
  1417. }
  1418. /// <summary>
  1419. /// 重新开始slow leak test
  1420. /// </summary>
  1421. /// <param name="cmd"></param>
  1422. /// <param name="objs"></param>
  1423. /// <returns></returns>
  1424. private bool ClearSlowLeak(string cmd, object[] objs)
  1425. {
  1426. _StartSlowLeakTestANLevel = ReservoirData.ANLevel;
  1427. _slowLeakStartTime = DateTime.Now;
  1428. LOG.WriteLog(eEvent.INFO_RESERVOIR, Module, $" Slow leak test was reset");
  1429. return true;
  1430. }
  1431. /// <summary>
  1432. /// 手动注水
  1433. /// </summary>
  1434. /// <param name="direplenOn"></param>
  1435. /// <param name="direplenOperation"></param>
  1436. /// <returns></returns>
  1437. private bool ManualDiReplen(Func<string, object[], bool> direplenOn, ReservoirOperation direplenOperation, string timeLength)
  1438. {
  1439. if (_currentOperation != ReservoirOperation.None)
  1440. {
  1441. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"current operation is {_currentOperation},cannot execute {direplenOperation}");
  1442. return false;
  1443. }
  1444. bool result = direplenOn("", null);
  1445. if (result)
  1446. {
  1447. _currentOperation = direplenOperation;
  1448. _persistentValue.DiReplenTime = DateTime.Now;
  1449. ReservoirsPersistentManager.Instance.UpdatePersistentValue(Module);
  1450. int.TryParse(timeLength, out _manualReplenSecond);
  1451. }
  1452. return result;
  1453. }
  1454. /// <summary>
  1455. /// 阳极自动注水
  1456. /// </summary>
  1457. /// <returns></returns>
  1458. public bool AutoANDiReplen()
  1459. {
  1460. if (IsANLowLevel)
  1461. {
  1462. if (!_isANAutoDIReplenError)
  1463. {
  1464. _isANAutoDIReplenError = true;
  1465. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"ANLowLevel is activate,Can't AutoANDireplen");
  1466. }
  1467. return false;
  1468. }
  1469. else
  1470. {
  1471. _isANAutoDIReplenError = false;
  1472. }
  1473. return AutoDireplen(ANDiReplenOn, ReservoirOperation.AutoANDiReplen);
  1474. }
  1475. /// <summary>
  1476. /// 阴极自动流水
  1477. /// </summary>
  1478. /// <returns></returns>
  1479. public bool AutoCADiReplen()
  1480. {
  1481. if (IsCALowLevel)
  1482. {
  1483. if (!_isCAAutoDIReplenError)
  1484. {
  1485. _isCAAutoDIReplenError = true;
  1486. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"CALowLevel is activate,Can't AutoANDireplen");
  1487. }
  1488. return false;
  1489. }
  1490. else
  1491. {
  1492. _isCAAutoDIReplenError = false;
  1493. }
  1494. return AutoDireplen(CADiReplenOn, ReservoirOperation.AutoCADiReplen);
  1495. }
  1496. /// <summary>
  1497. /// 自动注水
  1498. /// </summary>
  1499. /// <returns></returns>
  1500. private bool AutoDireplen(Func<bool, bool> direplenOn, ReservoirOperation reservoirOperation)
  1501. {
  1502. if (_currentOperation != ReservoirOperation.None)
  1503. {
  1504. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"current operation is {_currentOperation},cannot execute {reservoirOperation}");
  1505. return false;
  1506. }
  1507. if (_resRecipe == null)
  1508. {
  1509. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"recipe is null");
  1510. return false;
  1511. }
  1512. bool result = direplenOn(false);
  1513. if (result)
  1514. {
  1515. _currentOperation = reservoirOperation;
  1516. _persistentValue.DiReplenTime = DateTime.Now;
  1517. }
  1518. return result;
  1519. }
  1520. #endregion
  1521. #region CrossDose
  1522. /// <summary>
  1523. /// CrossDose开阀
  1524. /// </summary>
  1525. /// <param name="cmd"></param>
  1526. /// <param name="args"></param>
  1527. /// <returns></returns>
  1528. public bool CrossDoseOn(string cmd, object[] args)
  1529. {
  1530. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CROSS_DOSE_ENABLE}");
  1531. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  1532. }
  1533. /// <summary>
  1534. /// CrossDose关阀
  1535. /// </summary>
  1536. /// <param name="cmd"></param>
  1537. /// <param name="args"></param>
  1538. /// <returns></returns>
  1539. public bool CrossDoseOff(string cmd, object[] args)
  1540. {
  1541. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CROSS_DOSE_ENABLE}");
  1542. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  1543. }
  1544. /// <summary>
  1545. /// 手动Dosing
  1546. /// </summary>
  1547. /// <param name="cmd"></param>
  1548. /// <param name="args"></param>
  1549. /// <returns></returns>
  1550. private bool StartDosing(string cmd, object[] args)
  1551. {
  1552. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  1553. if (!_isCrossDoseInitialized)
  1554. {
  1555. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, "Please initialize Cross Dose");
  1556. return false;
  1557. }
  1558. double crossDoseVolume = (double)args[0];
  1559. _crossDoseHelper.SetManualDoseOperation();
  1560. return _crossDoseHelper.StartDosing(crossDoseVolume);
  1561. }
  1562. /// <summary>
  1563. /// 停止Dosing
  1564. /// </summary>
  1565. /// <param name="cmd"></param>
  1566. /// <param name="args"></param>
  1567. /// <returns></returns>
  1568. private bool HaltDosing(string cmd, object[] args)
  1569. {
  1570. _crossDoseHelper.ResetDoseOperation();
  1571. _crossDoseHelper.HaltDosing();
  1572. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CROSS_DOSE_ENABLE}");
  1573. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  1574. }
  1575. /// <summary>
  1576. /// Set Pump Factor
  1577. /// </summary>
  1578. /// <param name="cmd"></param>
  1579. /// <param name="args"></param>
  1580. /// <returns></returns>
  1581. private bool SetPumpFactor(string cmd, object[] args)
  1582. {
  1583. double targetPumpFactor = (double)args[0];
  1584. _crossDoseHelper.SetPumpfactor(targetPumpFactor);
  1585. return true;
  1586. }
  1587. /// <summary>
  1588. /// CrossDose初始化
  1589. /// </summary>
  1590. /// <param name="isInitialized"></param>
  1591. public void InitializeCrossDose(bool isInitialized)
  1592. {
  1593. _isCrossDoseInitialized = isInitialized;
  1594. }
  1595. /// <summary>
  1596. /// Reset CrossDose
  1597. /// </summary>
  1598. /// <param name="cmd"></param>
  1599. /// <param name="args"></param>
  1600. /// <returns></returns>
  1601. public bool ResetCrossDose(string cmd, object[] args)
  1602. {
  1603. return _crossDoseHelper.ResetCrossDose();
  1604. }
  1605. /// <summary>
  1606. /// Reset Monitor
  1607. /// </summary>
  1608. /// <param name="cmd"></param>
  1609. /// <param name="args"></param>
  1610. /// <returns></returns>
  1611. public bool ResetCrossDoseMonitor()
  1612. {
  1613. return _crossDoseHelper.ResetCrossDoseMonitor();
  1614. }
  1615. #endregion
  1616. #region Sample
  1617. /// <summary>
  1618. /// ANSample开阀
  1619. /// </summary>
  1620. /// <param name="cmd"></param>
  1621. /// <param name="args"></param>
  1622. /// <returns></returns>
  1623. public bool ANSampleOn(string cmd, object[] args)
  1624. {
  1625. SystemFacilities systemFacility = DEVICE.GetDevice<SystemFacilities>("System.Facilities");
  1626. if (systemFacility != null && !systemFacility.SampleFluidDetect)
  1627. {
  1628. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "SampleFluidDetect is Activate. Can't open ANSample");
  1629. return false;
  1630. }
  1631. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_SAMPLE_FLOW}");
  1632. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  1633. }
  1634. /// <summary>
  1635. /// ANSample关阀
  1636. /// </summary>
  1637. /// <param name="cmd"></param>
  1638. /// <param name="args"></param>
  1639. /// <returns></returns>
  1640. public bool ANSampleOff(string cmd, object[] args)
  1641. {
  1642. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{AN_SAMPLE_FLOW}");
  1643. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  1644. }
  1645. /// <summary>
  1646. /// CASample开阀
  1647. /// </summary>
  1648. /// <param name="cmd"></param>
  1649. /// <param name="args"></param>
  1650. /// <returns></returns>
  1651. public bool CASampleOn(string cmd, object[] args)
  1652. {
  1653. SystemFacilities systemFacility = DEVICE.GetDevice<SystemFacilities>("System.Facilities");
  1654. if (systemFacility != null && !systemFacility.SampleFluidDetect)
  1655. {
  1656. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "SampleFluidDetect is Activate. Can't open CASample");
  1657. return false;
  1658. }
  1659. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_SAMPLE_FLOW}");
  1660. return BeckhoffIOManager.Instance.WriteIoValue(ioName, true);
  1661. }
  1662. /// <summary>
  1663. /// CASample关阀
  1664. /// </summary>
  1665. /// <param name="cmd"></param>
  1666. /// <param name="args"></param>
  1667. /// <returns></returns>
  1668. public bool CASampleOff(string cmd, object[] args)
  1669. {
  1670. string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{CA_SAMPLE_FLOW}");
  1671. return BeckhoffIOManager.Instance.WriteIoValue(ioName, false);
  1672. }
  1673. #endregion
  1674. /// <summary>
  1675. /// 订阅变量数值发生变化
  1676. /// </summary>
  1677. private void SubscribeValueAction()
  1678. {
  1679. BeckhoffIoSubscribeUpdateVariable(CA_DI_REPLEN);
  1680. BeckhoffIoSubscribeUpdateVariable(AN_DI_REPLEN);
  1681. BeckhoffIoSubscribeUpdateVariable(CA_WATER_LEVEL);
  1682. BeckhoffIoSubscribeUpdateVariable(AN_WATER_LEVEL);
  1683. BeckhoffIoSubscribeUpdateVariable(AN_PUMP);
  1684. BeckhoffIoSubscribeUpdateVariable(CROSS_DOSE_ENABLE);
  1685. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_STM_STATUS);
  1686. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_POS_STATUS);
  1687. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_TARGET_POSITION);
  1688. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_ENABLE);
  1689. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_EXECUTE);
  1690. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_RESET);
  1691. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_SPEED);
  1692. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_START_TYPE);
  1693. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_ACCELERATION);
  1694. BeckhoffIoSubscribeUpdateVariable(TRANSFER_PUMP_DECELERATION);
  1695. BeckhoffIoSubscribeUpdateVariable(TRANSFER_ACTUAL_POSITION);
  1696. BeckhoffIoSubscribeUpdateVariable(AN_BYPASS_FLOW);
  1697. BeckhoffIoSubscribeUpdateVariable(AN_A_DRAIN_PUMP);
  1698. BeckhoffIoSubscribeUpdateVariable(AN_B_DRAIN_PUMP);
  1699. BeckhoffIoSubscribeUpdateVariable(AN_SAMPLE_FLOW);
  1700. BeckhoffIoSubscribeUpdateVariable(CA_SAMPLE_FLOW);
  1701. BeckhoffIoSubscribeUpdateVariable(CA_PUMP_SPEED);
  1702. BeckhoffIoSubscribeUpdateVariable(CA_PUMP_RUNNING);
  1703. BeckhoffIoSubscribeUpdateVariable(CA_HED_FLOW);
  1704. BeckhoffIoSubscribeUpdateVariable(CDA_FLOW_VALVE);
  1705. BeckhoffIoSubscribeUpdateVariable(AN_BY_PASS);
  1706. BeckhoffIoSubscribeUpdateVariable(CA_BY_PASS);
  1707. BeckhoffIoSubscribeUpdateVariable(CA_PUMP_ENABLE);
  1708. BeckhoffIoSubscribeUpdateVariable(EVAPORATORLEVEL);
  1709. BeckhoffCounterSubscribeUpdateVariable(AN_TRANSFER_FLOW, ANTransferFlow);
  1710. BeckhoffCounter anTransferFlowCounter = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_TRANSFER_FLOW}");
  1711. if (anTransferFlowCounter != null)
  1712. {
  1713. ANTransferFlow.Period = anTransferFlowCounter.Period;
  1714. }
  1715. BeckhoffCounterSubscribeUpdateVariable(AN_BYPASS_COUNTERFLOW, ReservoirCounterByPassFlow);
  1716. BeckhoffCounter reservoirCounterByPassFlow = BeckhoffCounterManager.Instance.GetBeckhoffCounter($"{Module}.{AN_BYPASS_COUNTERFLOW}");
  1717. if (reservoirCounterByPassFlow != null)
  1718. {
  1719. ReservoirCounterByPassFlow.Period = reservoirCounterByPassFlow.Period;
  1720. }
  1721. }
  1722. /// <summary>
  1723. /// 订阅IO变量
  1724. /// </summary>
  1725. /// <param name="variable"></param>
  1726. private void BeckhoffIoSubscribeUpdateVariable(string variable)
  1727. {
  1728. _variableInitializeDic[variable] = false;
  1729. IOModuleManager.Instance.SubscribeModuleVariable(Module, variable, UpdateVariableValue);
  1730. }
  1731. /// <summary>
  1732. /// 订阅Counter变量
  1733. /// </summary>
  1734. /// <param name="variable"></param>
  1735. private void BeckhoffCounterSubscribeUpdateVariable(string variable, CounterFlowData counterFlowData)
  1736. {
  1737. _nameCounterFlowData[$"{Module}.{variable}"] = counterFlowData;
  1738. BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_VALUE, UpdateCounterVariableValue);
  1739. BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_START, UpdateCounterVariableValue);
  1740. BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_STOP, UpdateCounterVariableValue);
  1741. BeckhoffCounterManager.Instance.SubscribeModuleVariable($"{Module}.{variable}", COUNTER_RESET, UpdateCounterVariableValue);
  1742. }
  1743. /// <summary>
  1744. /// 更新变量数值
  1745. /// </summary>
  1746. /// <param name="variable"></param>
  1747. /// <param name="value"></param>
  1748. private void UpdateCounterVariableValue(string variable, object value)
  1749. {
  1750. string[] strAry = variable.Split('.');
  1751. string lastVariable = strAry[strAry.Length - 1];
  1752. PropertyInfo property = null;
  1753. string key = variable.Replace($".{lastVariable}", "");
  1754. if (_nameCounterFlowData.ContainsKey(key))
  1755. {
  1756. CounterFlowData counterFlowData = _nameCounterFlowData[key];
  1757. if (counterFlowData != null)
  1758. {
  1759. property = counterFlowData.GetType().GetProperty(lastVariable);
  1760. if (property != null)
  1761. {
  1762. property.SetValue(counterFlowData, value);
  1763. }
  1764. }
  1765. }
  1766. }
  1767. /// <summary>
  1768. /// 更新变量数值
  1769. /// </summary>
  1770. /// <param name="variable"></param>
  1771. /// <param name="value"></param>
  1772. private void UpdateVariableValue(string variable, object value)
  1773. {
  1774. if (!ReservoirData.IsDataInitialized)
  1775. {
  1776. ReservoirData.IsDataInitialized = true;
  1777. }
  1778. PropertyInfo property = ReservoirData.GetType().GetProperty(variable);
  1779. if (property != null)
  1780. {
  1781. property.SetValue(ReservoirData, value);
  1782. if (variable == AN_WATER_LEVEL)
  1783. {
  1784. string anLevelCurve = SC.GetStringValue($"Reservoir.{Module}.ANLevelCurve");
  1785. ReservoirData.ANLevel = LevelCurveManager.Instance.CalculateLevelByWaterLevel(ReservoirData.ANWaterLevel, anLevelCurve);
  1786. }
  1787. else if (variable == CA_WATER_LEVEL)
  1788. {
  1789. string caLevelCurve = SC.GetStringValue($"Reservoir.{Module}.CALevelCurve");
  1790. ReservoirData.CALevel = LevelCurveManager.Instance.CalculateLevelByWaterLevel(ReservoirData.CAWaterLevel, caLevelCurve);
  1791. }
  1792. }
  1793. if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable])
  1794. {
  1795. _variableInitializeDic[variable] = true;
  1796. }
  1797. }
  1798. /// <summary>
  1799. /// 是否所有IO变量初始化完成
  1800. /// </summary>
  1801. /// <returns></returns>
  1802. private bool AllIoVariableInitialized()
  1803. {
  1804. foreach (string item in _variableInitializeDic.Keys)
  1805. {
  1806. if (!_variableInitializeDic[item])
  1807. {
  1808. LOG.WriteLog(eEvent.ERR_RINSE, Module, $"{item} is not initialized");
  1809. return false;
  1810. }
  1811. }
  1812. return true;
  1813. }
  1814. /// <summary>
  1815. /// 检验阳极是否需要补水
  1816. /// </summary>
  1817. /// <returns></returns>
  1818. private bool CheckANNeedDiReplen()
  1819. {
  1820. if (IsAuto && _resRecipe != null)
  1821. {
  1822. if (_resRecipe.ANDIReplenEnable && _resRecipe.ANDIReplenCurrentRate == 0 && _resRecipe.ANDIReplenTimeRate == 0)
  1823. {
  1824. double levelHysteresis = SC.GetValue<double>("Reservoir.LevelHysteresis");
  1825. return _reservoirData.ANLevel < _resRecipe.ReservoirANLevel - levelHysteresis;
  1826. }
  1827. return false;
  1828. }
  1829. else
  1830. {
  1831. return false;
  1832. }
  1833. }
  1834. /// <summary>
  1835. /// 检验CA是否需要注水
  1836. /// </summary>
  1837. /// <returns></returns>
  1838. public bool CheckCANeedDiReplen()
  1839. {
  1840. if (IsAuto && _resRecipe != null)
  1841. {
  1842. if (_resRecipe.DIReplenEnable && _resRecipe.DIReplenTimeRate == 0 && _resRecipe.DIReplenCurrentRate == 0)
  1843. {
  1844. double levelHysteresis = SC.GetValue<double>("Reservoir.LevelHysteresis");
  1845. return _reservoirData.CALevel < _resRecipe.ReservoirCALevel - levelHysteresis;
  1846. }
  1847. return false;
  1848. }
  1849. else
  1850. {
  1851. return false;
  1852. }
  1853. }
  1854. /// <summary>
  1855. /// 检验阴极是否highlevel
  1856. /// </summary>
  1857. public bool CheckCAHighLevelStatus()
  1858. {
  1859. return ReservoirData.CAWaterLevel > SC.GetValue<double>($"Reservoir.{Module}.CAHighLevel") ? true : false;
  1860. }
  1861. /// <summary>
  1862. /// 检验阴极是否lowlevel
  1863. /// </summary>
  1864. public bool CheckCALowLevelStatus()
  1865. {
  1866. return ReservoirData.CAWaterLevel < SC.GetValue<double>($"Reservoir.{Module}.CALowLevel") ? true : false;
  1867. }
  1868. /// <summary>
  1869. /// 检验阳极是否highlevel
  1870. /// </summary>
  1871. public bool CheckANHighLevelStatus()
  1872. {
  1873. return ReservoirData.ANWaterLevel > SC.GetValue<double>($"Reservoir.{Module}.ANHighLevel") ? true : false;
  1874. }
  1875. /// <summary>
  1876. /// 检验阳极是否lowlevel
  1877. /// </summary>
  1878. public bool CheckANLowLevelStatus()
  1879. {
  1880. return ReservoirData.ANWaterLevel < SC.GetValue<double>($"Reservoir.{Module}.ANLowLevel") ? true : false;
  1881. }
  1882. /// <summary>
  1883. /// CAFlowRate Check
  1884. /// </summary>
  1885. private void CAFlowRateCheck()
  1886. {
  1887. if (_resRecipe == null) return;
  1888. for (int i = 0; i < _metalDevices.Count; i++)
  1889. {
  1890. CompactMembranMetalDevice hotMetalDevice = _metalDevices[i];
  1891. if (hotMetalDevice != null && !hotMetalDevice.IsDisable && hotMetalDevice.IsAuto)
  1892. {
  1893. if (hotMetalDevice.MetalDeviceData == null) continue;
  1894. if (!hotMetalDevice.FlowValveStable) continue;
  1895. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(hotMetalDevice.Name);
  1896. double cellFlow = hotMetalDevice.MetalDeviceData.CellFlow;
  1897. if (cellFlow < _resRecipe.CAFlowRateErrorLow)
  1898. {
  1899. if (!metalEntity.IsError)
  1900. {
  1901. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{hotMetalDevice.Name} cellflow:{cellFlow} is less than recipe's CAFlowRateErrorLow parameter:{_resRecipe.CAFlowRateErrorLow}");
  1902. metalEntity.PostMsg(MetalMsg.Error);
  1903. }
  1904. }
  1905. else if (cellFlow < _resRecipe.CAFlowRateWarningLow)
  1906. {
  1907. if (!_isCAFlowRateWARN[i])
  1908. {
  1909. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{hotMetalDevice.Name} cellflow:{cellFlow} is less than recipe's CAFlowRateWarningLow parameter:{_resRecipe.CAFlowRateWarningLow}");
  1910. _isCAFlowRateWARN[i] = true;
  1911. }
  1912. }
  1913. else
  1914. {
  1915. _isCAFlowRateWARN[i] = false;
  1916. }
  1917. }
  1918. }
  1919. }
  1920. /// <summary>
  1921. /// ANFlowRate Check
  1922. /// </summary>
  1923. private void ANFlowRateCheck()
  1924. {
  1925. if (_resRecipe == null) return;
  1926. for (int i = 0; i < _metalDevices.Count; i++)
  1927. {
  1928. CompactMembranMetalDevice hotMetalDevice = _metalDevices[i];
  1929. if (hotMetalDevice != null && !hotMetalDevice.IsDisable && hotMetalDevice.IsAuto)
  1930. {
  1931. if (hotMetalDevice.MetalDeviceData == null) continue;
  1932. //ANACellFlow
  1933. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(hotMetalDevice.Name);
  1934. if (hotMetalDevice.MetalDeviceData.ANAPinEnable && hotMetalDevice.ANAFlowValveStable)
  1935. {
  1936. double ANAcellFlow = hotMetalDevice.ANACellFlow.CounterValue;
  1937. if (ANAcellFlow < _resRecipe.ANFlowRateErrorLow)
  1938. {
  1939. if (!metalEntity.IsError)
  1940. {
  1941. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{hotMetalDevice.Name} ANASideflow:{ANAcellFlow} is less than recipe's ANFlowRateErrorLow parameter:{_resRecipe.ANFlowRateErrorLow}");
  1942. metalEntity.PostMsg(MetalMsg.Error);
  1943. }
  1944. }
  1945. else if (ANAcellFlow < _resRecipe.ANFlowRateWarningLow)
  1946. {
  1947. if (!_isANAFlowRateWARN[i])
  1948. {
  1949. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{hotMetalDevice.Name} ANASideflow:{ANAcellFlow} is less than recipe's ANFlowRateWarningLow parameter:{_resRecipe.ANFlowRateWarningLow}");
  1950. _isANAFlowRateWARN[i] = true;
  1951. }
  1952. }
  1953. else
  1954. {
  1955. _isANAFlowRateWARN[i] = false;
  1956. }
  1957. }
  1958. //ANBCellFlow
  1959. if (hotMetalDevice.MetalDeviceData.ANBPinEnable && hotMetalDevice.ANBFlowValveStable)
  1960. {
  1961. double ANBcellFlow = hotMetalDevice.ANBCellFlow.CounterValue;
  1962. if (ANBcellFlow < _resRecipe.ANFlowRateErrorLow)
  1963. {
  1964. if (!metalEntity.IsError)
  1965. {
  1966. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{hotMetalDevice.Name} ANBSideflow:{ANBcellFlow} is less than recipe's ANFlowRateErrorLow parameter:{_resRecipe.ANFlowRateErrorLow}");
  1967. metalEntity.PostMsg(MetalMsg.Error);
  1968. }
  1969. }
  1970. else if (ANBcellFlow < _resRecipe.ANFlowRateWarningLow)
  1971. {
  1972. if (!_isANBFlowRateWARN[i])
  1973. {
  1974. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{hotMetalDevice.Name} ANBSideflow:{ANBcellFlow} is less than recipe's ANFlowRateWarningLow parameter:{_resRecipe.ANFlowRateWarningLow}");
  1975. _isANBFlowRateWARN[i] = true;
  1976. }
  1977. }
  1978. else
  1979. {
  1980. _isANBFlowRateWARN[i] = false;
  1981. }
  1982. }
  1983. }
  1984. }
  1985. }
  1986. /// <summary>
  1987. /// Temperature Check
  1988. /// </summary>
  1989. private void TemperatureCheck()
  1990. {
  1991. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  1992. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
  1993. TemperatureController temperatureController = DEVICE.GetDevice<TemperatureController>(reservoirItem.TCID);
  1994. if (temperatureController == null || temperatureController.TemperatureData == null || _resRecipe == null
  1995. || temperatureController.TemperatureData.ControlOperationModel != ENABLE) return;
  1996. double tempValue = temperatureController.TemperatureData.ReserviorTemperature;
  1997. if (tempValue > _resRecipe.TemperatureErrorHigh && !reservoirEntity.IsError)
  1998. {
  1999. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{temperatureController.Name} temperature:{tempValue} is over recipe's TemperatureErrorHigh parameter:{_resRecipe.TemperatureErrorHigh}");
  2000. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2001. }
  2002. else if (tempValue < _resRecipe.TemperatureErrorLow && !reservoirEntity.IsError)
  2003. {
  2004. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{temperatureController.Name} temperature:{tempValue} is less than recipe's TemperatureErrorLow parameter:{_resRecipe.TemperatureErrorLow}");
  2005. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2006. }
  2007. else if (tempValue > _resRecipe.TemperatureWarningHigh)
  2008. {
  2009. if (!_isTCControlWARN)
  2010. {
  2011. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{temperatureController.Name} temperature:{tempValue} is over recipe's TemperatureWarningHigh parameter:{_resRecipe.TemperatureWarningHigh}");
  2012. _isTCControlWARN = true;
  2013. }
  2014. }
  2015. else if (tempValue < _resRecipe.TemperatureWarningLow)
  2016. {
  2017. if (!_isTCControlWARN)
  2018. {
  2019. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{temperatureController.Name} temperature;{tempValue} is less than recipe's TemperatureWarningLow parameter:{_resRecipe.TemperatureWarningLow}");
  2020. _isTCControlWARN = true;
  2021. }
  2022. }
  2023. else
  2024. {
  2025. _isTCControlWARN = false;
  2026. }
  2027. }
  2028. /// <summary>
  2029. /// AN LowLevel触发对应操作
  2030. /// </summary>
  2031. private void ANLowLevelOperation()
  2032. {
  2033. if (IsANLowLevel)
  2034. {
  2035. if (_reservoirData.ANPump > 0)
  2036. {
  2037. AnPumpOffOperation("ANPumpOff", null);
  2038. }
  2039. foreach (var metalDevice in _metalDevices)
  2040. {
  2041. if (metalDevice.MetalDeviceData.ANAPinEnable)
  2042. {
  2043. metalDevice.AnSideAFillOff($"{metalDevice.Name}.ANAFillOff", null);
  2044. }
  2045. if (metalDevice.MetalDeviceData.ANBPinEnable)
  2046. {
  2047. metalDevice.AnSideBFillOff($"{metalDevice.Name}.ANBFillOff", null);
  2048. }
  2049. }
  2050. }
  2051. }
  2052. /// <summary>
  2053. /// CA Low Level触发对应操作
  2054. /// </summary>
  2055. private void CALowLevelOperation()
  2056. {
  2057. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
  2058. if (IsCALowLevel)
  2059. {
  2060. if (_reservoirData.CAPumpEnable)
  2061. {
  2062. CAPumpOff("CAPumpOff", null);
  2063. }
  2064. foreach (var metalDevice in _metalDevices)
  2065. {
  2066. if (metalDevice.MetalDeviceData.CellFlowValve)
  2067. {
  2068. metalDevice.CellFlowValveOff($"{metalDevice.Name}.FlowOff", null);
  2069. }
  2070. }
  2071. //禁用TC
  2072. if (!String.IsNullOrEmpty(reservoirItem.TCID))
  2073. {
  2074. TemperatureController temperatureController = DEVICE.GetDevice<TemperatureController>(reservoirItem.TCID);
  2075. if (temperatureController != null && temperatureController.TemperatureData.ControlOperationModel == 5)
  2076. {
  2077. temperatureController.DisableOperation("", null);
  2078. }
  2079. }
  2080. }
  2081. }
  2082. /// <summary>
  2083. /// High Level Common Operation
  2084. /// </summary>
  2085. private void HighLevelOperation()
  2086. {
  2087. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  2088. SystemFacilities systemFacilities = DEVICE.GetDevice<SystemFacilities>("System.Facilities");
  2089. if (systemFacilities != null)
  2090. {
  2091. if (systemFacilities.DIFillEnable) systemFacilities.DiFillDisableOperation("DIFillDisableOpeartion", null);
  2092. if (systemFacilities.DIReplenEnable) systemFacilities.DiReplenDisableOperation("DiReplenDisableOperation", null);
  2093. if (_reservoirData.ANDiReplen)
  2094. {
  2095. _currentOperation = ReservoirOperation.None;
  2096. ANDiReplenOff("", null);
  2097. }
  2098. if (_reservoirData.CADiReplen)
  2099. {
  2100. _currentOperation = ReservoirOperation.None;
  2101. CADiReplenOff("", null);
  2102. }
  2103. }
  2104. if (!reservoirEntity.IsError) reservoirEntity.PostMsg(ReservoirMsg.Error);
  2105. }
  2106. /// <summary>
  2107. /// Low Level common Operation
  2108. /// </summary>
  2109. private void LowLevelOperation()
  2110. {
  2111. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  2112. foreach (var metalDevice in _metalDevices)
  2113. {
  2114. MetalEntity metalEntity = Singleton<RouteManager>.Instance.GetModule<MetalEntity>(metalDevice.DeviceID);
  2115. if (metalEntity != null && !metalEntity.IsError)
  2116. {
  2117. metalEntity.PostMsg(MetalMsg.Error);
  2118. }
  2119. }
  2120. if (!reservoirEntity.IsError) reservoirEntity.PostMsg(ReservoirMsg.Error);
  2121. }
  2122. /// <summary>
  2123. /// WaterLevelMonitor
  2124. /// </summary>
  2125. private void WaterLevelMonitor()
  2126. {
  2127. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
  2128. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  2129. _isSystemAutoMode = reservoirEntity.IsAuto; ;
  2130. //触发low将对应的reservoir和对应metal切成error
  2131. if (IsANLowLevel)
  2132. {
  2133. if (!errorLogSet.Contains($"{Module}.IsANLowLevel"))
  2134. {
  2135. errorLogSet.Add($"{Module}.IsANLowLevel");
  2136. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current ANWaterlevel:{ReservoirData.ANWaterLevel} is lower than ANLowLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.ANLowLevel")}");
  2137. }
  2138. ANLowLevelOperation();
  2139. LowLevelOperation();
  2140. if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "ANWaterLevel"))//模块处于Auto模式使将报错信息加入到Alarm
  2141. {
  2142. AlarmListManager.Instance.AddDataError(Module,
  2143. $"ANWaterLevel", $"Current ANWaterlevel:{ReservoirData.ANWaterLevel} is lower than ANLowLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.ANLowLevel")}");
  2144. }
  2145. }
  2146. else if (IsANHighLevel)
  2147. {
  2148. if (!errorLogSet.Contains($"{Module}.IsANHighLevel"))
  2149. {
  2150. errorLogSet.Add($"{Module}.IsANHighLevel");
  2151. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current ANWaterlevel:{ReservoirData.ANWaterLevel} is larger than ANHighLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.ANHighLevel")}");
  2152. }
  2153. HighLevelOperation();
  2154. if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "ANWaterLevel"))
  2155. {
  2156. AlarmListManager.Instance.AddDataError(Module,
  2157. $"ANWaterLevel", $"Current ANWaterlevel:{ReservoirData.ANWaterLevel} is larger than ANHighLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.ANHighLevel")}");
  2158. }
  2159. }
  2160. if (IsCALowLevel)
  2161. {
  2162. if (!errorLogSet.Contains($"{Module}.IsCALowLevel"))
  2163. {
  2164. errorLogSet.Add($"{Module}.IsCALowLevel");
  2165. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current CAWaterlevel:{ReservoirData.CAWaterLevel} is lower than CALowLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.CALowLevel")}");
  2166. }
  2167. CALowLevelOperation();
  2168. LowLevelOperation();
  2169. if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "CAWaterLevel"))
  2170. {
  2171. AlarmListManager.Instance.AddDataError(Module,
  2172. $"CAWaterLevel", $"Current CAWaterlevel:{ReservoirData.CAWaterLevel} is lower than CALowLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.CALowLevel")}");
  2173. }
  2174. }
  2175. else if (IsCAHighLevel)
  2176. {
  2177. if (!errorLogSet.Contains($"{Module}.IsCAHighLevel"))
  2178. {
  2179. errorLogSet.Add($"{Module}.IsCAHighLevel");
  2180. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current CAWaterlevel:{ReservoirData.CAWaterLevel} is large than CAHighLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.CAHighLevel")}");
  2181. }
  2182. HighLevelOperation();
  2183. if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "CAWaterLevel"))
  2184. {
  2185. AlarmListManager.Instance.AddDataError(Module,
  2186. $"CAWaterLevel", $"Current CAWaterlevel:{ReservoirData.CAWaterLevel} is large than CAHighLevel Config:{SC.GetValue<double>($"Reservoir.{Module}.CAHighLevel")}");
  2187. }
  2188. }
  2189. //水位触发recipe里面的high/low参数将对应的reservoir切成error
  2190. if (_resRecipe == null) return;
  2191. //ANLevel监控
  2192. if (ReservoirData.ANLevel < _resRecipe.ANLevelErrorLow)
  2193. {
  2194. if (!errorLogSet.Contains($"{Module}.ANLevel"))
  2195. {
  2196. errorLogSet.Add($"{Module}.ANLevel");
  2197. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current ANlevel:{ReservoirData.ANLevel} is lower than ResRecipe.ANLevelErrorLow:{_resRecipe.ANLevelErrorLow}");
  2198. }
  2199. if (!reservoirEntity.IsError)
  2200. {
  2201. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2202. }
  2203. if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "ANLevel"))
  2204. {
  2205. AlarmListManager.Instance.AddDataError(Module,
  2206. $"ANLevel", $"Current ANlevel:{ReservoirData.ANLevel} is lower than ResRecipe.ANLevelErrorLow:{_resRecipe.ANLevelErrorLow}");
  2207. }
  2208. }
  2209. else if (ReservoirData.ANLevel > _resRecipe.ANLevelErrorHigh)
  2210. {
  2211. if (!errorLogSet.Contains($"{Module}.ANLevel"))
  2212. {
  2213. errorLogSet.Add($"{Module}.ANLevel");
  2214. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current ANlevel:{ReservoirData.ANLevel} is larger than ResRecipe.ANLevelErrorHigh:{_resRecipe.ANLevelErrorHigh}");
  2215. }
  2216. if (!reservoirEntity.IsError)
  2217. {
  2218. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2219. }
  2220. if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "ANLevel"))
  2221. {
  2222. AlarmListManager.Instance.AddDataError(Module,
  2223. $"ANLevel", $"Current ANlevel:{ReservoirData.ANLevel} is larger than ResRecipe.ANLevelErrorHigh:{_resRecipe.ANLevelErrorHigh}");
  2224. }
  2225. }
  2226. //CALevel监控
  2227. if (ReservoirData.CALevel < _resRecipe.CALevelErrorLow)
  2228. {
  2229. if (!errorLogSet.Contains($"{Module}.CALevel"))
  2230. {
  2231. errorLogSet.Add($"{Module}.CALevel");
  2232. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current CAlevel:{ReservoirData.CALevel} is lower than ResRecipe.CALevelErrorLow:{_resRecipe.CALevelErrorLow}");
  2233. }
  2234. if (!reservoirEntity.IsError)
  2235. {
  2236. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2237. }
  2238. if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "CALevel"))
  2239. {
  2240. AlarmListManager.Instance.AddDataError(Module,
  2241. $"CALevel", $"Current CAlevel:{ReservoirData.CALevel} is lower than ResRecipe.CALevelErrorLow:{_resRecipe.CALevelErrorLow}");
  2242. }
  2243. }
  2244. else if (ReservoirData.CALevel > _resRecipe.CALevelErrorHigh)
  2245. {
  2246. if (!errorLogSet.Contains($"{Module}.CALevel"))
  2247. {
  2248. errorLogSet.Add($"{Module}.CALevel");
  2249. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Current CAlevel:{ReservoirData.CALevel} is larger than ResRecipe.CALevelErrorHigh:{_resRecipe.CALevelErrorHigh}");
  2250. }
  2251. if (!reservoirEntity.IsError)
  2252. {
  2253. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2254. }
  2255. if (_isSystemAutoMode && !AlarmListManager.Instance.IsContainDataError(Module, "CALevel"))
  2256. {
  2257. AlarmListManager.Instance.AddDataError(Module,
  2258. $"CALevel", $"Current CAlevel:{ReservoirData.CALevel} is larger than ResRecipe.CALevelErrorHigh:{_resRecipe.CALevelErrorHigh}");
  2259. }
  2260. }
  2261. }
  2262. /// <summary>
  2263. /// 定时器
  2264. /// </summary>
  2265. /// <returns></returns>
  2266. private bool OnTimer()
  2267. {
  2268. //补水监控
  2269. if (_direplenHelper != null)
  2270. {
  2271. _direplenHelper.MonitorPeriodTime();
  2272. if (_currentOperation == ReservoirOperation.ManualANDiReplen)
  2273. {
  2274. bool result = _direplenHelper.MonitorManualDiReplenComplete(_manualReplenSecond, ANDiReplenOff);
  2275. if (result)
  2276. {
  2277. _currentOperation = ReservoirOperation.None;
  2278. }
  2279. }
  2280. if (_currentOperation == ReservoirOperation.ManualCADiReplen)
  2281. {
  2282. bool result = _direplenHelper.MonitorManualDiReplenComplete(_manualReplenSecond, CADiReplenOff);
  2283. if (result)
  2284. {
  2285. _currentOperation = ReservoirOperation.None;
  2286. }
  2287. }
  2288. if (_currentOperation == ReservoirOperation.AutoANDiReplen)
  2289. {
  2290. AutoDiReplenMonitor(ANDiReplenOff, _reservoirData.ANLevel, _resRecipe.ReservoirANLevel, _resRecipe.ANDIReplenEnable,
  2291. _resRecipe.ANDIReplenTimeRate, _resRecipe.ANDIReplenCurrentRate);
  2292. }
  2293. if (_currentOperation == ReservoirOperation.AutoCADiReplen)
  2294. {
  2295. AutoDiReplenMonitor(CADiReplenOff, _reservoirData.CALevel, _resRecipe.ReservoirCALevel, _resRecipe.DIReplenEnable,
  2296. _resRecipe.DIReplenTimeRate, _resRecipe.DIReplenCurrentRate);
  2297. }
  2298. }
  2299. //计算AN/CA level的平均值
  2300. if (ReservoirData != null)
  2301. {
  2302. //AN
  2303. if (_ANLevelSamples.Count >= levelSampleCount)
  2304. {
  2305. _ANLevelSamples.Dequeue();
  2306. _ANLevelSamples.Enqueue(ReservoirData.ANLevel);
  2307. }
  2308. else
  2309. {
  2310. _ANLevelSamples.Enqueue(ReservoirData.ANLevel);
  2311. }
  2312. //CA
  2313. if (_CALevelSamples.Count >= levelSampleCount)
  2314. {
  2315. _CALevelSamples.Dequeue();
  2316. _CALevelSamples.Enqueue(ReservoirData.CALevel);
  2317. }
  2318. else
  2319. {
  2320. _CALevelSamples.Enqueue(ReservoirData.CALevel);
  2321. }
  2322. _avgANLevel = _ANLevelSamples.Count > 0 ? _ANLevelSamples.Average() : 0;
  2323. _avgCALevel = _CALevelSamples.Count > 0 ? _CALevelSamples.Average() : 0;
  2324. }
  2325. _metalTotalFlow = 0;
  2326. ReservoirItem reservoirItem = ReservoirItemManager.Instance.GetReservoirItem(Module);
  2327. if (reservoirItem != null)
  2328. {
  2329. List<MetalItem> metalItems = reservoirItem.MetalCells;
  2330. if (metalItems != null && metalItems.Count > 0)
  2331. {
  2332. foreach (MetalItem metalItem in metalItems)
  2333. {
  2334. if (metalItem.Installed)
  2335. {
  2336. CompactMembranMetalDevice metalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(metalItem.ModuleName);
  2337. if (metalDevice != null)
  2338. {
  2339. _metalTotalFlow += metalDevice.ANACellFlow.CounterValue;
  2340. _metalTotalFlow += metalDevice.ANBCellFlow.CounterValue;
  2341. }
  2342. }
  2343. }
  2344. }
  2345. }
  2346. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  2347. //pump安全性检验
  2348. if (_reservoirData.ANPump > 0 && (_reservoirData.ANBypassFlow + ReservoirCounterByPassFlow.CounterValue + _metalTotalFlow) < SC.GetValue<double>($"Reservoir.{Module}.ByPassMetalTotalFlowMinLimit"))
  2349. {
  2350. if (!_isAnPumpSafeDetectedActivate)
  2351. {
  2352. _isAnPumpSafeDetectedActivate = true;
  2353. _AnPumpSafeDetectTime = DateTime.Now;
  2354. }
  2355. if ((DateTime.Now - _AnPumpSafeDetectTime).TotalSeconds > _flowFaultHoldOffTime && _isAnPumpSafeDetectedActivate)
  2356. {
  2357. if (reservoirEntity.IsAuto && !reservoirEntity.IsError)
  2358. {
  2359. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2360. }
  2361. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Total flow is less than configuration item ByPassMetalTotalFlowMinLimit :{SC.GetValue<double>($"Reservoir.{Module}.ByPassMetalTotalFlowMinLimit")}, AN Pump off");
  2362. _isAnPumpSafeDetectedActivate = false;
  2363. AnPump(0);
  2364. }
  2365. }
  2366. else
  2367. {
  2368. _isAnPumpSafeDetectedActivate = false;
  2369. }
  2370. foreach (CompactMembranMetalDevice device in _metalDevices)
  2371. {
  2372. device.OnTimer(_periodicJob.Interval);
  2373. }
  2374. if (reservoirEntity != null && reservoirEntity.IsError && _isCrossDoseInstalled && _reservoirData.TransferPumpEnable && _reservoirData.TransferPumpExecute)
  2375. {
  2376. _crossDoseHelper.HaltDosing();
  2377. }
  2378. // 判断排气是否触发漏液警报
  2379. if (_reservoirData != null && _reservoirData.EvaporatorLevel && "STD".Equals(reservoirItem.EvaporatorType)) //_reservoirData.EvaporatorLevel true表示触发漏液
  2380. {
  2381. if (_reservoirData.CDAFlowValve)
  2382. {
  2383. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"EvaporatorLevel is Activate");
  2384. CDAFlowOff("CDAFlowOff", null);
  2385. }
  2386. if (_reservoirData.CAPumpEnable)
  2387. {
  2388. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"EvaporatorLevel is Activate");
  2389. CAPumpOff("CAPumpOff", null);
  2390. }
  2391. }
  2392. //WaterLevel Monitor
  2393. WaterLevelMonitor();
  2394. //触发Safetyhigh将reservoir切成error
  2395. SafetyDevice safetyDevice = DEVICE.GetDevice<SafetyDevice>("Safety");
  2396. if (safetyDevice != null && safetyDevice.SafetyData.ReservoirHighLevel && !reservoirEntity.IsError)
  2397. {
  2398. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"Safety high is Activate");
  2399. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2400. }
  2401. //Sample检测
  2402. SystemFacilities systemFacility = DEVICE.GetDevice<SystemFacilities>("System.Facilities");
  2403. if (systemFacility != null && !systemFacility.SampleFluidDetect)
  2404. {
  2405. if (ReservoirData.ANSampleFlow) ANSampleOff("", null);
  2406. if (ReservoirData.CASampleFlow) CASampleOff("", null);
  2407. }
  2408. if (reservoirEntity == null || !reservoirEntity.IsInitialized)
  2409. {
  2410. return true;
  2411. }
  2412. if (_isCrossDoseInstalled)
  2413. {
  2414. if (_crossDoseHelper.CrossDoseState == RState.Running)
  2415. {
  2416. _crossDoseHelper.CrossDoseStatusMonitor();
  2417. }
  2418. if (_crossDoseHelper.ResetState == RState.Running)
  2419. {
  2420. _crossDoseHelper.ResetCrossDoseMonitor();
  2421. }
  2422. if (_persistentValue.OperatingMode == "Auto")
  2423. {
  2424. _crossDoseHelper.AutoCrossDoseMonitor(_isCrossDoseInitialized);
  2425. }
  2426. else
  2427. {
  2428. _crossDoseHelper.CrossDoseOperationMonitor();
  2429. }
  2430. }
  2431. if (_persistentValue.OperatingMode == AUTO)
  2432. {
  2433. _pumpSpeedHelper.Monitor(_resRecipe);
  2434. //CAFlowRate判断
  2435. CAFlowRateCheck();
  2436. //ANFlowRate判断
  2437. ANFlowRateCheck();
  2438. //Temperature判断
  2439. TemperatureCheck();
  2440. }
  2441. //判断是否到启动fast leak test的时间
  2442. if (DateTime.Now - _fastLeakStartTime >= _fastLeakTestSpan - TimeSpan.FromMilliseconds(200) && DateTime.Now - _fastLeakStartTime <= _fastLeakTestSpan + TimeSpan.FromMilliseconds(200))
  2443. {
  2444. FastLeakTestAction();
  2445. }
  2446. //判断是否到启动slow leak test的时间
  2447. if (DateTime.Now - _slowLeakStartTime >= _slowLeakTestSpan - TimeSpan.FromMilliseconds(200) && DateTime.Now - _slowLeakStartTime <= _slowLeakTestSpan + TimeSpan.FromMilliseconds(200))
  2448. {
  2449. SlowLeakTestAction();
  2450. }
  2451. return true;
  2452. }
  2453. /// <summary>
  2454. /// 自动注水监控
  2455. /// </summary>
  2456. /// <param name="direplenOff"></param>
  2457. /// <param name="level"></param>
  2458. /// <param name="recipeLevel"></param>
  2459. private void AutoDiReplenMonitor(Func<string, object[], bool> direplenOff, double level, double recipeLevel, bool replenEnable,
  2460. int direplenTimeRate, int direplenCurrentRate)
  2461. {
  2462. bool result = _direplenHelper.AutoDiReplenMonitorTimeOut(direplenOff);
  2463. if (result)
  2464. {
  2465. _currentOperation = ReservoirOperation.None;
  2466. //触发注水异常信号
  2467. _isDiReplenInFault = true;
  2468. }
  2469. else
  2470. {
  2471. //按液位补水
  2472. result = _direplenHelper.AutoDiReplenMonitorComplete(level, recipeLevel, replenEnable, direplenTimeRate, direplenCurrentRate, direplenOff);
  2473. if (result)
  2474. {
  2475. _currentOperation = ReservoirOperation.None;
  2476. }
  2477. }
  2478. }
  2479. /// <summary>
  2480. /// ReservoirUsage监控
  2481. /// </summary>
  2482. public void ReservoirUsageMonitor()
  2483. {
  2484. ReservoirUsage reservoirUsage = ReservoirUsageManager.Instance.GetReservoirUsage(Module);
  2485. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(Module);
  2486. if (reservoirUsage == null || reservoirEntity == null) return;
  2487. //reservoirTotalAmpHours Check
  2488. double reservoirTotalAmpHoursWarningLimit = 0;
  2489. if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalAmpHoursWarningLimit"))
  2490. {
  2491. reservoirTotalAmpHoursWarningLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.ReservoirTotalAmpHoursWarningLimit");
  2492. }
  2493. double reservoirTotalAmpHoursFaultLimit = 0;
  2494. if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalAmpHoursFaultLimit"))
  2495. {
  2496. reservoirTotalAmpHoursFaultLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.ReservoirTotalAmpHoursFaultLimit");
  2497. }
  2498. if (reservoirUsage.TotalUsage > reservoirTotalAmpHoursFaultLimit && reservoirTotalAmpHoursFaultLimit != 0)
  2499. {
  2500. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Total Usage(AHr):{reservoirUsage.TotalUsage} is over config item ReservoirTotalAmpHoursFaultLimit:{reservoirTotalAmpHoursFaultLimit}");
  2501. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2502. AlarmListManager.Instance.AddDataError(Module,
  2503. $"TotalUsage", $"{Module} Total Usage(AHr):{reservoirUsage.TotalUsage} is over ReservoirTotalAmpHoursFaultLimit:{reservoirTotalAmpHoursFaultLimit}");
  2504. }
  2505. else if (reservoirUsage.TotalUsage > reservoirTotalAmpHoursWarningLimit && reservoirTotalAmpHoursWarningLimit != 0)
  2506. {
  2507. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Total Usage(AHr):{reservoirUsage.TotalUsage} is over config item ReservoirTotalAmpHoursWarningLimit:{reservoirTotalAmpHoursWarningLimit}");
  2508. AlarmListManager.Instance.AddWarn(Module,
  2509. $"TotalUsage", $"{Module} Total Usage(AHr):{reservoirUsage.TotalUsage} is over ReservoirTotalAmpHoursWarningLimit:{reservoirTotalAmpHoursWarningLimit}");
  2510. }
  2511. //MembraneTotalAmpHoursCheck
  2512. double membraneTotalAmpHoursWarningLimit = 0;
  2513. if (SC.ContainsItem($"Reservoir.{Module}.MembraneTotalAmpHoursWarningLimit"))
  2514. {
  2515. membraneTotalAmpHoursWarningLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.MembraneTotalAmpHoursWarningLimit");
  2516. }
  2517. double membraneTotalAmpHoursFaultLimit = 0;
  2518. if (SC.ContainsItem($"Reservoir.{Module}.MembraneTotalAmpHoursFaultLimit"))
  2519. {
  2520. membraneTotalAmpHoursFaultLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.MembraneTotalAmpHoursFaultLimit");
  2521. }
  2522. if (reservoirUsage.MembranceUsage > membraneTotalAmpHoursFaultLimit && membraneTotalAmpHoursFaultLimit != 0)
  2523. {
  2524. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Membrane Usage(AHr):{reservoirUsage.MembranceUsage} is over config item MembraneTotalAmpHoursFaultLimit:{membraneTotalAmpHoursFaultLimit}");
  2525. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2526. AlarmListManager.Instance.AddDataError(Module,
  2527. $"MembraneUsage", $"{Module} Membrane Usage(AHr):{reservoirUsage.MembranceUsage} is over MembraneTotalAmpHoursFaultLimit:{membraneTotalAmpHoursFaultLimit}");
  2528. }
  2529. else if (reservoirUsage.MembranceUsage > membraneTotalAmpHoursWarningLimit && membraneTotalAmpHoursWarningLimit != 0)
  2530. {
  2531. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Membrane Usage(AHr):{reservoirUsage.MembranceUsage} is over config item MembraneTotalAmpHoursWarningLimit:{membraneTotalAmpHoursWarningLimit}");
  2532. AlarmListManager.Instance.AddWarn(Module,
  2533. $"MembraneUsage", $"{Module} Membrane Usage(AHr):{reservoirUsage.MembranceUsage} is over MembraneTotalAmpHoursWarningLimit:{membraneTotalAmpHoursWarningLimit}");
  2534. }
  2535. //ANBathTotalAmpHoursCheck
  2536. double anBathTotalAmpHoursWarningLimit = 0;
  2537. if (SC.ContainsItem($"Reservoir.{Module}.ANBathTotalAmpHoursWarningLimit"))
  2538. {
  2539. anBathTotalAmpHoursWarningLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.ANBathTotalAmpHoursWarningLimit");
  2540. }
  2541. double anBathTotalAmpHoursFaultLimit = 0;
  2542. if (SC.ContainsItem($"Reservoir.{Module}.ANBathTotalAmpHoursFaultLimit"))
  2543. {
  2544. anBathTotalAmpHoursFaultLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.ANBathTotalAmpHoursFaultLimit");
  2545. }
  2546. if (reservoirUsage.AnodeUsage > anBathTotalAmpHoursFaultLimit && anBathTotalAmpHoursFaultLimit != 0)
  2547. {
  2548. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Anolyte Bath Usage(AHr):{reservoirUsage.AnodeUsage} is over config item ANBathTotalAmpHoursFaultLimit:{anBathTotalAmpHoursFaultLimit}");
  2549. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2550. AlarmListManager.Instance.AddDataError(Module,
  2551. $"AnodeUsage", $"{Module} Anolyte Bath Usage(AHr):{reservoirUsage.AnodeUsage} is over ANBathTotalAmpHoursFaultLimit:{anBathTotalAmpHoursFaultLimit}");
  2552. }
  2553. else if (reservoirUsage.AnodeUsage > anBathTotalAmpHoursWarningLimit && anBathTotalAmpHoursWarningLimit != 0)
  2554. {
  2555. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Anolyte Bath Usage(AHr):{reservoirUsage.AnodeUsage} is over config item ANBathTotalAmpHoursWarningLimit:{anBathTotalAmpHoursWarningLimit}");
  2556. AlarmListManager.Instance.AddWarn(Module,
  2557. $"AnodeUsage", $"{Module} Anolyte Bath Usage(AHr):{reservoirUsage.AnodeUsage} is over ANBathTotalAmpHoursWarningLimit:{anBathTotalAmpHoursWarningLimit}");
  2558. }
  2559. //BathTotalAmpHoursCheck
  2560. double bathTotalAmpHoursWarningLimit = 0;
  2561. if (SC.ContainsItem($"Reservoir.{Module}.BathTotalAmpHoursWarningLimit"))
  2562. {
  2563. bathTotalAmpHoursWarningLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.BathTotalAmpHoursWarningLimit");
  2564. }
  2565. double bathTotalAmpHoursFaultLimit = 0;
  2566. if (SC.ContainsItem($"Reservoir.{Module}.BathTotalAmpHoursFaultLimit"))
  2567. {
  2568. bathTotalAmpHoursFaultLimit = (double)SC.GetValue<double>($"Reservoir.{Module}.BathTotalAmpHoursFaultLimit");
  2569. }
  2570. if (reservoirUsage.BathUsage > bathTotalAmpHoursFaultLimit && bathTotalAmpHoursFaultLimit != 0)
  2571. {
  2572. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Bath Usage(AHr):{reservoirUsage.BathUsage} is over config item BathTotalAmpHoursFaultLimit:{bathTotalAmpHoursFaultLimit}");
  2573. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2574. AlarmListManager.Instance.AddDataError(Module,
  2575. $"BathUsage", $"{Module} Bath Usage(AHr):{reservoirUsage.BathUsage} is over BathTotalAmpHoursFaultLimit:{bathTotalAmpHoursFaultLimit}");
  2576. }
  2577. else if (reservoirUsage.BathUsage > bathTotalAmpHoursWarningLimit && bathTotalAmpHoursWarningLimit != 0)
  2578. {
  2579. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Bath Usage(AHr):{reservoirUsage.BathUsage} is over config item BathTotalAmpHoursWarningLimit:{bathTotalAmpHoursWarningLimit}");
  2580. AlarmListManager.Instance.AddWarn(Module,
  2581. $"BathUsage", $"{Module} Bath Usage(AHr):{reservoirUsage.BathUsage} is over BathTotalAmpHoursWarningLimit:{bathTotalAmpHoursWarningLimit}");
  2582. }
  2583. //BathTotalDaysCheck
  2584. int bathTotalDaysWarningLimit = 0;
  2585. if (SC.ContainsItem($"Reservoir.{Module}.BathTotalDaysWarningLimit"))
  2586. {
  2587. bathTotalDaysWarningLimit = SC.GetValue<int>($"Reservoir.{Module}.BathTotalDaysWarningLimit");
  2588. }
  2589. int bathTotalDaysFaultLimit = 0;
  2590. if (SC.ContainsItem($"Reservoir.{Module}.BathTotalDaysFaultLimit"))
  2591. {
  2592. bathTotalDaysFaultLimit = SC.GetValue<int>($"Reservoir.{Module}.BathTotalDaysFaultLimit");
  2593. }
  2594. if (reservoirUsage.BathUsageDays > bathTotalDaysFaultLimit && bathTotalDaysFaultLimit != 0)
  2595. {
  2596. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Bath Usage(Days):{reservoirUsage.BathUsageDays} is over config item BathTotalDaysFaultLimit:{bathTotalDaysFaultLimit}");
  2597. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2598. AlarmListManager.Instance.AddDataError(Module,
  2599. $"BathUsageDays", $"{Module} Bath Usage(Days):{reservoirUsage.BathUsageDays} is over BathTotalDaysFaultLimit:{bathTotalDaysFaultLimit}");
  2600. }
  2601. else if (reservoirUsage.BathUsageDays > bathTotalDaysWarningLimit && bathTotalDaysWarningLimit != 0)
  2602. {
  2603. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Bath Usage(Days):{reservoirUsage.BathUsage} is over config item BathTotalDaysWarningLimit:{bathTotalDaysWarningLimit}");
  2604. AlarmListManager.Instance.AddWarn(Module,
  2605. $"BathUsageDays", $"{Module} Bath Usage(Days):{reservoirUsage.BathUsageDays} is over BathTotalDaysWarningLimit:{bathTotalDaysWarningLimit}");
  2606. }
  2607. //ReservoirTotalWafersCheck
  2608. int reservoirTotalWafersWarningLimit = 0;
  2609. if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalWafersWarningLimit"))
  2610. {
  2611. reservoirTotalWafersWarningLimit = SC.GetValue<int>($"Reservoir.{Module}.ReservoirTotalWafersWarningLimit");
  2612. }
  2613. int reservoirTotalWafersFaultLimit = 0;
  2614. if (SC.ContainsItem($"Reservoir.{Module}.ReservoirTotalWafersFaultLimit"))
  2615. {
  2616. reservoirTotalWafersFaultLimit = SC.GetValue<int>($"Reservoir.{Module}.ReservoirTotalWafersFaultLimit");
  2617. }
  2618. if (reservoirUsage.TotalWafers > reservoirTotalWafersFaultLimit && reservoirTotalWafersFaultLimit != 0)
  2619. {
  2620. LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, $"{Module} Total Wafers:{reservoirUsage.TotalWafers} is over config item ReservoirTotalWafersFaultLimit:{reservoirTotalWafersFaultLimit}");
  2621. reservoirEntity.PostMsg(ReservoirMsg.Error);
  2622. AlarmListManager.Instance.AddDataError(Module,
  2623. $"TotalWafers", $"{Module} Total Wafers:{reservoirUsage.TotalWafers} is over ReservoirTotalWafersFaultLimit:{reservoirTotalWafersFaultLimit}");
  2624. }
  2625. else if (reservoirUsage.TotalWafers > reservoirTotalWafersWarningLimit && reservoirTotalWafersWarningLimit != 0)
  2626. {
  2627. LOG.WriteLog(eEvent.WARN_RESERVOIR, Module, $"{Module} Total Wafers:{reservoirUsage.TotalWafers} is over config item ReservoirTotalWafersWarningLimit:{reservoirTotalWafersWarningLimit}");
  2628. AlarmListManager.Instance.AddWarn(Module,
  2629. $"TotalWafers", $"{Module} Total Wafers:{reservoirUsage.TotalWafers} is over ReservoirTotalWafersWarningLimit:{reservoirTotalWafersWarningLimit}");
  2630. }
  2631. }
  2632. public void Monitor()
  2633. {
  2634. }
  2635. public void Reset()
  2636. {
  2637. }
  2638. public void Terminate()
  2639. {
  2640. }
  2641. }
  2642. }