CompactMembranReservoirDevice.cs 123 KB

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