MetalEntity.cs 72 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298
  1. using Aitex.Core.RT.DataCenter;
  2. using Aitex.Core.RT.Fsm;
  3. using Aitex.Core.RT.Log;
  4. using Aitex.Core.Util;
  5. using Aitex.Core.Utilities;
  6. using MECF.Framework.Common.Equipment;
  7. using MECF.Framework.Common.WaferHolder;
  8. using System;
  9. using MECF.Framework.Common.ToolLayout;
  10. using MECF.Framework.Common.Persistent.Reservoirs;
  11. using Aitex.Core.RT.OperationCenter;
  12. using MECF.Framework.Common.RecipeCenter;
  13. using Aitex.Core.RT.RecipeCenter;
  14. using MECF.Framework.Common.SubstrateTrackings;
  15. using Aitex.Core.RT.Device;
  16. using MECF.Framework.Common.Routine;
  17. using MECF.Framework.Common.ProcessCell;
  18. using Aitex.Core.RT.SCCore;
  19. using MECF.Framework.Common.Alarm;
  20. using CyberX8_Core;
  21. using CyberX8_RT.Devices.Metal;
  22. using CyberX8_RT.Devices.Reservoir;
  23. using CyberX8_RT.Modules.Metal;
  24. using CyberX8_RT.Modules.Reservoir;
  25. using CyberX8_RT.Modules;
  26. using CyberX8_RT.Modules.EFEM;
  27. using static Mono.Security.X509.X520;
  28. namespace CyberX8_RT.Modules.Metal
  29. {
  30. public class MetalEntity : Entity, IEntity, IModuleEntity
  31. {
  32. #region 常量
  33. private const string STRATUS = "Stratus";
  34. private const string AUTO = "Auto";
  35. private const string MANUAL = "Manual";
  36. private const string DISABLED = "Disabled";
  37. private const string ENGINEERING = "Engineering";
  38. private const string PRODUCTION = "Production";
  39. #endregion
  40. #region 内部变量
  41. /// <summary>
  42. /// 已经完成的Cycle次数
  43. /// </summary>
  44. private int _achievedCycle = 0;
  45. /// <summary>
  46. /// Metal项
  47. /// </summary>
  48. private MetalItem _metalItem;
  49. /// <summary>
  50. /// 持久化对象
  51. /// </summary>
  52. private MetalPersistentValue _persistentValue;
  53. /// <summary>
  54. /// c&m Initialize routine
  55. /// </summary>
  56. private CompactEmbranceInitializeRoutine _compactEmbranceInitializeRoutine;
  57. /// <summary>
  58. /// C&M Runrecipe routine
  59. /// </summary>
  60. private CompactEmbranceRunRecipeRoutine _compactEmbranceRunRecipeRoutine;
  61. /// <summary>
  62. /// S&H Initialize Routine
  63. /// </summary>
  64. private StandardHotInitializeRoutine _standardHotInitializeRoutine;
  65. /// <summary>
  66. /// S&H RunRecipe Routine
  67. /// </summary>
  68. private StandardHotRunRecipeRoutine _standardHotRunRecipeRoutine;
  69. /// <summary>
  70. /// Current short test routine
  71. /// </summary>
  72. private CurrentShortTestRoutine _currentShortTestRoutine;
  73. /// <summary>
  74. /// 当前Recipe
  75. /// </summary>
  76. private DepRecipe _currentRecipe = null;
  77. /// <summary>
  78. /// recipe时间
  79. /// </summary>
  80. private int _recipeTime;
  81. /// <summary>
  82. /// 循环次数
  83. /// </summary>
  84. private int _cycle = 0;
  85. /// <summary>
  86. /// 运行Recipe面
  87. /// </summary>
  88. private string _recipeSide = "";
  89. /// <summary>
  90. /// 当前RunRecipe Routine
  91. /// </summary>
  92. private RoutineBase _currentRunRecipeRoutine;
  93. /// <summary>
  94. /// Runrecipe已经运行的时间
  95. /// </summary>
  96. private int _runrecipeElapsedTime = 0;
  97. /// <summary>
  98. /// run recipe start time
  99. /// </summary>
  100. private DateTime _runRecipeStartTime;
  101. /// <summary>
  102. /// run recipe complete time
  103. /// </summary>
  104. private DateTime _runRecipeCompleteTime;
  105. /// <summary>
  106. /// 所在reservoir
  107. /// </summary>
  108. private StandardHotReservoirDevice _reservoirDevice;
  109. /// <summary>
  110. /// 所在reservoir名字
  111. /// </summary>
  112. private string _reservoirName;
  113. /// <summary>
  114. /// 当前完成recipe次数
  115. /// </summary>
  116. private int _currentCycleTimes;
  117. #endregion
  118. #region 属性
  119. /// <summary>
  120. /// 模块名称
  121. /// </summary>
  122. public ModuleName Module { get; private set; }
  123. /// <summary>
  124. /// 初始化状态
  125. /// </summary>
  126. public bool IsInit { get { return fsm.State == (int)MetalState.Init; } }
  127. /// <summary>
  128. /// 空闲状态
  129. /// </summary>
  130. public bool IsIdle { get { return fsm.State == (int)MetalState.Idle; } }
  131. /// <summary>
  132. /// 是否发生错误
  133. /// </summary>
  134. public bool IsError { get { return fsm.State == (int)MetalState.Error; } }
  135. /// <summary>
  136. /// 是否正在作业
  137. /// </summary>
  138. public bool IsBusy { get { return fsm.State > (int)MetalState.Idle; } }
  139. /// <summary>
  140. /// 是否初始化完成
  141. /// </summary>
  142. public bool IsInitialized { get { return fsm.State >= (int)MetalState.Initialized; } }
  143. /// <summary>
  144. /// 是否禁用
  145. /// </summary>
  146. public bool IsDisable { get { return _persistentValue == null || _persistentValue.OperatingMode == DISABLED; } }
  147. /// <summary>
  148. /// 自动模式
  149. /// </summary>
  150. public bool IsAuto { get { return _persistentValue != null && _persistentValue.OperatingMode == AUTO; } }
  151. /// <summary>
  152. /// 自动模式
  153. /// </summary>
  154. public bool IsManual { get { return _persistentValue != null && _persistentValue.OperatingMode == MANUAL; } }
  155. /// <summary>
  156. /// 是否为工程模式
  157. /// </summary>
  158. public bool IsEngineering { get { return _persistentValue != null && _persistentValue.RecipeOperatingMode == ENGINEERING; } }
  159. /// <summary>
  160. /// 是否为产品模式
  161. /// </summary>
  162. public bool IsProduction { get { return _persistentValue != null && _persistentValue.RecipeOperatingMode == PRODUCTION; } }
  163. /// <summary>
  164. /// WaferHolder信息
  165. /// </summary>
  166. public WaferHolderInfo WaferHolderInfo { get { return WaferHolderManager.Instance.GetWaferHolder(Module.ToString()); } }
  167. /// <summary>
  168. /// 已完成的RunRecipeCycle次数
  169. /// </summary>
  170. public int AchievedCycle { get { return _achievedCycle; } }
  171. /// <summary>
  172. /// 当前状态机状态
  173. /// </summary>
  174. public int State { get { return fsm.State; } }
  175. /// <summary>
  176. /// 当前Metal设置的WaferSize
  177. /// </summary>
  178. public int MetalWaferSize { get { return _persistentValue.MetalWaferSize; } }
  179. /// <summary>
  180. /// recipe时长
  181. /// </summary>
  182. public int RecipeTime { get { return _recipeTime; } }
  183. /// <summary>
  184. /// 剩余时间
  185. /// </summary>
  186. public override int TimeToReady
  187. {
  188. get
  189. {
  190. if (IsIdle)
  191. {
  192. return 0;
  193. }
  194. switch (fsm.State)
  195. {
  196. case (int)MetalState.RunReciping:
  197. return Math.Max(_recipeTime - fsm.ElapsedTime / 1000, 0);
  198. default:
  199. return 0;
  200. }
  201. }
  202. }
  203. /// <summary>
  204. /// 用量
  205. /// </summary>
  206. public MetalUsage MetalUsage { get { return MetalUsageManager.Instance.GetMetalUsage(Module.ToString()); } }
  207. #endregion
  208. /// <summary>
  209. /// 构造函数
  210. /// </summary>
  211. /// <param name="moduleName"></param>
  212. public MetalEntity(ModuleName moduleName)
  213. {
  214. this.Module = moduleName;
  215. WaferManager.Instance.SubscribeLocation(Module, 2);
  216. InitialFsm();
  217. }
  218. /// <summary>
  219. /// 初始化
  220. /// </summary>
  221. /// <returns></returns>
  222. protected override bool Init()
  223. {
  224. InitializeDATA();
  225. InitializeParameter();
  226. InitializeRoutine();
  227. InitializeOperation();
  228. return true;
  229. }
  230. /// <summary>
  231. /// 初始化参数
  232. /// </summary>
  233. private void InitializeParameter()
  234. {
  235. _persistentValue = MetalPersistentManager.Instance.GetMetalPersistentValue(Module.ToString());
  236. if (_persistentValue == null)
  237. {
  238. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Persistent Value Object is not exist");
  239. }
  240. _metalItem = MetalItemManager.Instance.GetMetalItem(Module.ToString());
  241. _reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  242. _reservoirDevice = DEVICE.GetDevice<StandardHotReservoirDevice>($"{_reservoirName}");
  243. }
  244. /// <summary>
  245. /// 初始化Routine
  246. /// </summary>
  247. private void InitializeRoutine()
  248. {
  249. _compactEmbranceInitializeRoutine = new CompactEmbranceInitializeRoutine(Module.ToString());
  250. _standardHotInitializeRoutine = new StandardHotInitializeRoutine(Module.ToString());
  251. _compactEmbranceRunRecipeRoutine = new CompactEmbranceRunRecipeRoutine(Module.ToString());
  252. _standardHotRunRecipeRoutine = new StandardHotRunRecipeRoutine(Module.ToString());
  253. _currentShortTestRoutine = new CurrentShortTestRoutine(Module.ToString());
  254. }
  255. /// <summary>
  256. /// 初始化操作
  257. /// </summary>
  258. private void InitializeOperation()
  259. {
  260. OP.Subscribe($"{Module}.InitializeAll", (cmd, args) => { return CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Initialize); });
  261. OP.Subscribe($"{Module}.CycleManualProcessRecipe", (cmd, args) =>
  262. {
  263. DepRecipe recipe = RecipeFileManager.Instance.LoadGenericityRecipe<DepRecipe>(args[0].ToString());
  264. if (recipe == null)
  265. {
  266. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{args[0]} recipe is null");
  267. return false;
  268. }
  269. object[] objects = new object[args.Length];
  270. objects[0] = recipe;
  271. for (int i = 1; i < args.Length; i++)
  272. {
  273. objects[i] = args[i];
  274. }
  275. return CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.RunRecipe, objects);
  276. });
  277. OP.Subscribe($"{Module}.CurrentShortTest", (cmd, args) => { return CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.CurrentShortTest); });
  278. OP.Subscribe($"{Module}.UpdateMetalUsage", UpdateMetalUsageAction);
  279. OP.Subscribe($"{Module}.Abort", (cmd, args) => { return CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Abort); });
  280. }
  281. /// <summary>
  282. /// EnterInit
  283. /// </summary>
  284. public void EnterInit()
  285. {
  286. if ((MetalState)fsm.State != MetalState.Idle) return;
  287. else
  288. {
  289. CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Init);
  290. }
  291. }
  292. /// 初始化状态机
  293. /// </summary>
  294. private void InitialFsm()
  295. {
  296. fsm = new StateMachine<MetalEntity>(Module.ToString(), (int)MetalState.Init, 20);
  297. fsm.EnableRepeatedMsg(true);
  298. AnyStateTransition(MetalMsg.Error, EnterError, MetalState.Error);
  299. //Initialize
  300. AnyStateTransition(MetalMsg.Initialize, InitializeAll, MetalState.Initializing);
  301. Transition(MetalState.Initializing, FSM_MSG.TIMER, InitializeAllMonitor, MetalState.Initialized);
  302. //直接进入Idle
  303. Transition(MetalState.Initialized, FSM_MSG.TIMER, NullFunc, MetalState.Idle);
  304. //RunRecipe
  305. Transition(MetalState.Idle, MetalMsg.RunRecipe, RunRecipe, MetalState.RunReciping);
  306. Transition(MetalState.WaitForRunRecipe, MetalMsg.RunRecipe, RunRecipe, MetalState.RunReciping);
  307. Transition(MetalState.RunReciping, FSM_MSG.TIMER, RunRecipeMonitor, MetalState.Idle);
  308. Transition(MetalState.RunReciping, MetalMsg.Abort, AbortRecipe, MetalState.Abort);
  309. //Current Short Test
  310. Transition(MetalState.Idle, MetalMsg.CurrentShortTest, CurrentShortTest, MetalState.CurrentShortTesting);
  311. Transition(MetalState.CurrentShortTesting, FSM_MSG.TIMER, CurrentShortTestMonitor, MetalState.WaitCloseFlow);
  312. Transition(MetalState.WaitCloseFlow, MetalMsg.CloseFlowValve, CloseFlowValve, MetalState.WaitOpenFlow);
  313. Transition(MetalState.WaitOpenFlow, MetalMsg.OpenFlowValve, OpenFlowValve, MetalState.WaitForRunRecipe);
  314. //Enter Init
  315. Transition(MetalState.Idle, MetalMsg.Init, NullFunc, MetalState.Init);
  316. EnumLoop<MetalState>.ForEach((item) => { fsm.MapState((int)item, item.ToString()); });
  317. EnumLoop<MetalMsg>.ForEach((item) => { fsm.MapMessage((int)item, item.ToString()); });
  318. }
  319. /// <summary>
  320. /// 初始化DATA
  321. /// </summary>
  322. private void InitializeDATA()
  323. {
  324. InitializeSVID();
  325. DATA.Subscribe($"{Module}.FsmState", () => ((MetalState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  326. DATA.Subscribe($"{Module}.WaferHolder", () => WaferHolderInfo, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  327. DATA.Subscribe($"{Module}.AchievedCycle", () => AchievedCycle, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  328. DATA.Subscribe($"{Module}.IsInit", () => IsInit, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  329. DATA.Subscribe($"{Module}.IsIdle", () => IsIdle, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  330. DATA.Subscribe($"{Module}.IsError", () => IsError, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  331. DATA.Subscribe($"{Module}.IsBusy", () => IsBusy, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  332. DATA.Subscribe($"{Module}.IsDisable", () => IsDisable, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  333. DATA.Subscribe($"{Module}.CurrentRecipe", () => _currentRecipe != null ? _currentRecipe.Ppid : "", SubscriptionAttribute.FLAG.IgnoreSaveDB);
  334. DATA.Subscribe($"{Module}.MetalUsage", () => MetalUsage, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  335. DATA.Subscribe($"{Module}.SubordinateReservoirName", () => _reservoirName, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  336. }
  337. /// <summary>
  338. /// 初始化SVID
  339. /// </summary>
  340. private void InitializeSVID()
  341. {
  342. DATA.Subscribe($"{Module}.State", () => ((MetalState)fsm.State).ToString(), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  343. DATA.Subscribe($"{Module}.LotID", () => WaferHolderInfo?.LotId , SubscriptionAttribute.FLAG.IgnoreSaveDB);
  344. DATA.Subscribe($"{Module}.WSID", () => WaferHolderInfo?.Id, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  345. DATA.Subscribe($"{Module}.LSAID", () => WaferHolderInfo?.CrsAId, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  346. DATA.Subscribe($"{Module}.LSBID", () => WaferHolderInfo?.CrsBId, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  347. DATA.Subscribe($"{Module}.ModuleRecipe", () => _currentRecipe?.Ppid, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  348. DATA.Subscribe($"{Module}.SequenceRecipe", () =>WaferHolderInfo?.SequenceId, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  349. DATA.Subscribe($"{Module}.WaferAID", () => WaferHolderInfo?.WaferAId, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  350. DATA.Subscribe($"{Module}.WaferBID", () => WaferHolderInfo?.WaferBId, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  351. DATA.Subscribe($"{Module}.TotalTime", () => _recipeTime, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  352. DATA.Subscribe($"{Module}.TimeRemain", () => _recipeTime != 0 && _currentRunRecipeRoutine != null ? (_recipeTime - Math.Round((double)_currentRunRecipeRoutine.ElapsedMilliseconds / 1000, 0)) : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  353. DATA.Subscribe($"{Module}.Task", () => WaferHolderInfo?.CurrentControlJobId, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  354. DATA.Subscribe($"{Module}.OperatingMode", () => _persistentValue != null ? _persistentValue.OperatingMode : "None", SubscriptionAttribute.FLAG.IgnoreSaveDB);
  355. DATA.Subscribe($"{Module}.TotalUsage", () => MetalUsage != null ? MetalUsage.TotalUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  356. DATA.Subscribe($"{Module}.TotalUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  357. DATA.Subscribe($"{Module}.TotalUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  358. DATA.Subscribe($"{Module}.AnodeAUsage", () => MetalUsage != null ? MetalUsage.AnodeAUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  359. DATA.Subscribe($"{Module}.AnodeAUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  360. DATA.Subscribe($"{Module}.AnodeAUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  361. DATA.Subscribe($"{Module}.AnodeBUsage", () => MetalUsage != null ? MetalUsage.AnodeBUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  362. DATA.Subscribe($"{Module}.AnodeBUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  363. DATA.Subscribe($"{Module}.AnodeBUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  364. DATA.Subscribe($"{Module}.MembranceAUsage", () => MetalUsage != null ? MetalUsage.MembranceAUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  365. DATA.Subscribe($"{Module}.MembranceAUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  366. DATA.Subscribe($"{Module}.MembranceAUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  367. DATA.Subscribe($"{Module}.MembranceBUsage", () => MetalUsage != null ? MetalUsage.MembranceBUsage : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  368. DATA.Subscribe($"{Module}.MembranceBUsage.WarningLimit", () => SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  369. DATA.Subscribe($"{Module}.MembranceBUsage.FaultLimit", () => SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  370. DATA.Subscribe($"{Module}.TotalWafers", () => MetalUsage != null ? MetalUsage.TotalWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  371. DATA.Subscribe($"{Module}.TotalWafers.WarningLimit", () => SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  372. DATA.Subscribe($"{Module}.TotalWafers.FaultLimit", () => SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  373. DATA.Subscribe($"{Module}.AnodeAWafers", () => MetalUsage != null ? MetalUsage.AnodeAWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  374. DATA.Subscribe($"{Module}.AnodeAWafers.WarningLimit", () => SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  375. DATA.Subscribe($"{Module}.AnodeAWafers.FaultLimit", () => SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  376. DATA.Subscribe($"{Module}.AnodeBWafers", () => MetalUsage != null ? MetalUsage.AnodeBWafers : 0, SubscriptionAttribute.FLAG.IgnoreSaveDB);
  377. DATA.Subscribe($"{Module}.AnodeBWafers.WarningLimit", () => SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  378. DATA.Subscribe($"{Module}.AnodeBWafers.FaultLimit", () => SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit"), SubscriptionAttribute.FLAG.IgnoreSaveDB);
  379. }
  380. /// <summary>
  381. /// 进入错误状态
  382. /// </summary>
  383. /// <param name="args"></param>
  384. /// <returns></returns>
  385. private bool EnterError(object[] args)
  386. {
  387. if (State == (int)MetalState.RunReciping)
  388. {
  389. if (_metalItem.SubType == STRATUS)
  390. {
  391. _standardHotRunRecipeRoutine.Abort();
  392. }
  393. else
  394. {
  395. _compactEmbranceRunRecipeRoutine.Abort();
  396. }
  397. }
  398. return true;
  399. }
  400. /// <summary>
  401. /// UpdateMetalUsageAction
  402. /// </summary>
  403. /// <param name="cmd"></param>
  404. /// <param name="param"></param>
  405. /// <returns></returns>
  406. private bool UpdateMetalUsageAction(string cmd, object[] args)
  407. {
  408. if (args.Length > 2)
  409. {
  410. MetalUsageManager.Instance.UpdateMetalUsageByManualOperation(args[0].ToString(), args[1].ToString(), args[2].ToString());
  411. LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"New {args[1].ToString()} value {args[2].ToString()} was input");
  412. }
  413. return true;
  414. }
  415. #region Initialize All
  416. /// <summary>
  417. /// 初始化
  418. /// </summary>
  419. /// <param name="param"></param>
  420. /// <returns></returns>
  421. private bool InitializeAll(object[] param)
  422. {
  423. if (fsm.State == (int)MetalState.Initializing)
  424. {
  425. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), "state is Initializing,cannot do initialize");
  426. return false;
  427. }
  428. if (!CheckReservoirInitialized())
  429. {
  430. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not initialized");
  431. return false;
  432. }
  433. if (!MetalUsageMointor(Module.ToString()))
  434. {
  435. return false;
  436. }
  437. if ("Auto".Equals(_persistentValue.OperatingMode))
  438. {
  439. if (!CheckReservoirIsAuto())
  440. {
  441. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not in Auto OperationMode");
  442. return false;
  443. }
  444. }
  445. if (_metalItem.SubType == STRATUS)
  446. {
  447. return _standardHotInitializeRoutine.Start(_persistentValue) == RState.Running;
  448. }
  449. else
  450. {
  451. return _compactEmbranceInitializeRoutine.Start(_persistentValue) == RState.Running;
  452. }
  453. }
  454. /// <summary>
  455. /// 检验Reservoir是否Initialized
  456. /// </summary>
  457. /// <returns></returns>
  458. private bool CheckReservoirInitialized()
  459. {
  460. string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  461. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(reservoir);
  462. if (reservoirEntity != null)
  463. {
  464. return reservoirEntity.IsInitialized;
  465. }
  466. return false;
  467. }
  468. /// <summary>
  469. /// 检验Reservoir是否Auto
  470. /// </summary>
  471. /// <returns></returns>
  472. private bool CheckReservoirIsAuto()
  473. {
  474. string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  475. ReservoirsPersistentValue reservoirsPersistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(reservoir);
  476. if ("Auto".Equals(reservoirsPersistentValue.OperatingMode))
  477. {
  478. return true;
  479. }
  480. return false;
  481. }
  482. /// <summary>
  483. /// 初始化监控
  484. /// </summary>
  485. /// <param name="param"></param>
  486. /// <returns></returns>
  487. private bool InitializeAllMonitor(object[] param)
  488. {
  489. RState rsstate = RState.Running;
  490. if (_metalItem.SubType == STRATUS)
  491. {
  492. rsstate = _standardHotInitializeRoutine.Monitor();
  493. }
  494. else
  495. {
  496. rsstate = _compactEmbranceInitializeRoutine.Monitor();
  497. }
  498. if (rsstate == RState.End)
  499. {
  500. return true;
  501. }
  502. else if (rsstate == RState.Failed || rsstate == RState.Timeout)
  503. {
  504. PostMsg(MetalMsg.Error);
  505. return false;
  506. }
  507. return false;
  508. }
  509. #endregion
  510. #region RunRecipe
  511. /// <summary>
  512. /// Run Recipe
  513. /// </summary>
  514. /// <param name="param"></param>
  515. /// <returns></returns>
  516. private bool RunRecipe(object[] param)
  517. {
  518. MetalUsageMointor(); //Metal run recipe前检查PMCounter消耗
  519. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  520. if (_metalItem.SubType == STRATUS)
  521. {
  522. StandardHotReservoirDevice resDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
  523. resDevice.ReservoirUsageMonitor();
  524. }
  525. DepRecipe recipe = param[0] as DepRecipe;
  526. _recipeSide = param[1].ToString();
  527. _cycle = (int)param[2];
  528. _runrecipeElapsedTime = 0;
  529. bool result = false;
  530. if (_metalItem.SubType == STRATUS)
  531. {
  532. _currentRunRecipeRoutine = _standardHotRunRecipeRoutine;
  533. result = _standardHotRunRecipeRoutine.Start(recipe, _recipeSide,_cycle) == RState.Running;
  534. }
  535. else
  536. {
  537. _currentRunRecipeRoutine = _compactEmbranceRunRecipeRoutine;
  538. result = _compactEmbranceRunRecipeRoutine.Start(recipe, _recipeSide, _cycle) == RState.Running;
  539. }
  540. if (result)
  541. {
  542. if (WaferHolderInfo != null)
  543. {
  544. WaferHolderInfo.MetalModuleName = Module;
  545. }
  546. _recipeTime = (recipe.CalculateRecipeTotalTime())*_cycle;
  547. _currentRecipe = recipe;
  548. if (WaferHolderInfo != null && WaferHolderInfo.SchedulerModules != null && WaferHolderInfo.SchedulerModules.Count != 0)
  549. {
  550. LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"{WaferHolderInfo?.Id} {string.Join(",", WaferHolderInfo.SchedulerModules)}");
  551. }
  552. _runRecipeStartTime = DateTime.Now;
  553. if (WaferHolderInfo != null && _currentRecipe != null)
  554. {
  555. FaModuleNotifier.Instance.NotifyWaferShuttleRecipeStart(WaferHolderInfo, _currentRecipe.Ppid);
  556. }
  557. }
  558. return result;
  559. }
  560. /// <summary>
  561. /// RunRecipe监控
  562. /// </summary>
  563. /// <param name="param"></param>
  564. /// <returns></returns>
  565. private bool RunRecipeMonitor(object[] param)
  566. {
  567. RState rsstate = RState.Running;
  568. if (_metalItem.SubType == STRATUS)
  569. {
  570. rsstate = _standardHotRunRecipeRoutine.Monitor();
  571. if (rsstate == RState.Running)
  572. {
  573. StandardHotMetalDevice _standardHotMetalDevice = DEVICE.GetDevice<StandardHotMetalDevice>(Module.ToString());
  574. if (_standardHotMetalDevice.MetalDeviceData.CellFlow <= 0)
  575. {
  576. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir metal cell flow is 0");
  577. rsstate = RState.Failed;
  578. }
  579. }
  580. _achievedCycle = _standardHotRunRecipeRoutine.GetCurrentCycle();
  581. }
  582. else
  583. {
  584. rsstate = _compactEmbranceRunRecipeRoutine.Monitor();
  585. if (rsstate == RState.Running)
  586. {
  587. CompactMembranMetalDevice _compactMembranMetalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(Module.ToString());
  588. if (_compactMembranMetalDevice.MetalDeviceData.CellFlow <= 0)
  589. {
  590. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir metal cell flow is 0");
  591. rsstate = RState.Failed;
  592. }
  593. if (_compactMembranMetalDevice.ANACellFlow.CounterValue <= 0) //检查hold flow
  594. {
  595. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir AnodeA flow is 0");
  596. rsstate = RState.Failed;
  597. }
  598. if (_compactMembranMetalDevice.ANBCellFlow.CounterValue <= 0)
  599. {
  600. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir AnodeB flow is 0");
  601. rsstate = RState.Failed;
  602. }
  603. }
  604. }
  605. if (Singleton<RouteManager>.Instance.IsAutoRunning && _runrecipeElapsedTime != TimeToReady)
  606. {
  607. _runrecipeElapsedTime = TimeToReady;
  608. LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"{WaferHolderInfo?.Id} {Module} RunRecipe TimeToReady {TimeToReady}s.");
  609. }
  610. if (rsstate == RState.End)
  611. {
  612. _recipeTime = 0;
  613. if (WaferHolderInfo != null)
  614. {
  615. double anodeAUsage = GetAnodeAUsage();
  616. double anodeBUsage = GetAnodeBUsage();
  617. MetalUsageManager.Instance.UpdateMetalUsage(Module.ToString(), _recipeSide, anodeAUsage, anodeBUsage);
  618. MetalUsageMointor(); //检查PMCounter消耗
  619. //CMM Usage
  620. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  621. if (_metalItem.SubType == STRATUS)
  622. {
  623. StandardHotReservoirDevice resDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
  624. resDevice.ReservoirUsageMonitor();
  625. resDevice.SetExportCMMUsage();
  626. }
  627. WaferHolderInfo.LastMetalRecipeCompleteTime = DateTime.Now;
  628. }
  629. _runrecipeElapsedTime = 0;
  630. //记录LotTrack
  631. _runRecipeCompleteTime = DateTime.Now;
  632. int timeLength = (int)(_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds;
  633. if (_metalItem.SubType == STRATUS)
  634. {
  635. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  636. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _standardHotRunRecipeRoutine.MetalLotTrackDatas,
  637. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  638. }
  639. else
  640. {
  641. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  642. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas,
  643. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  644. }
  645. if (WaferHolderInfo != null && _currentRecipe != null)
  646. {
  647. FaModuleNotifier.Instance.NotifyWaferShuttleRecipeEnd(WaferHolderInfo, _currentRecipe.Ppid, timeLength);
  648. }
  649. return true;
  650. }
  651. else if (rsstate == RState.Failed || rsstate == RState.Timeout)
  652. {
  653. _recipeTime = 0;
  654. if (WaferHolderInfo != null)
  655. {
  656. double anodeAUsage = GetAnodeAUsage();
  657. double anodeBUsage = GetAnodeBUsage();
  658. MetalUsageManager.Instance.UpdateMetalUsage(Module.ToString(), _recipeSide, anodeAUsage, anodeBUsage);
  659. MetalUsageMointor(); //失败了也要检查PMCounter消耗
  660. //CMMUsage
  661. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  662. if (_metalItem.SubType == STRATUS)
  663. {
  664. StandardHotReservoirDevice resDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
  665. resDevice.ReservoirUsageMonitor();
  666. resDevice.SetExportCMMUsage();
  667. }
  668. }
  669. _runrecipeElapsedTime = 0;
  670. if (WaferHolderInfo != null && _currentRecipe != null)
  671. {
  672. WaferHolderInfo.LastMetalRecipeCompleteTime = DateTime.Now;
  673. }
  674. PostMsg(MetalMsg.Error);
  675. //记录LotTrack
  676. _runRecipeCompleteTime = DateTime.Now;
  677. if (_metalItem.SubType == STRATUS)
  678. {
  679. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  680. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _standardHotRunRecipeRoutine.MetalLotTrackDatas,
  681. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  682. }
  683. else
  684. {
  685. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  686. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas,
  687. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  688. }
  689. if (WaferHolderInfo != null && _currentRecipe != null)
  690. {
  691. FaModuleNotifier.Instance.NotifyWaferShuttleRecipeFailed(WaferHolderInfo, _currentRecipe.Ppid);
  692. }
  693. return false;
  694. }
  695. return false;
  696. }
  697. /// <summary>
  698. /// 监控 PM Counter Metal用量
  699. /// </summary>
  700. private void MetalUsageMointor()
  701. {
  702. MetalUsage metalUsage = MetalUsageManager.Instance.GetMetalUsage(Module.ToString());
  703. if (metalUsage != null)
  704. {
  705. //TotalAUsage
  706. if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit") != 0)
  707. {
  708. if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit"))
  709. {
  710. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}");
  711. PostMsg(MetalMsg.Error);
  712. AlarmListManager.Instance.AddDataError(Module.ToString(),
  713. $"{Module.ToString()}.metalUsage.TotalUsage",
  714. $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}");
  715. }
  716. else
  717. {
  718. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}");
  719. AlarmListManager.Instance.AddWarn(Module.ToString(),
  720. $"{Module.ToString()}.metalUsage.TotalUsage",
  721. $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}");
  722. }
  723. }
  724. //AnodeAUsage
  725. if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit") != 0)
  726. {
  727. if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit"))
  728. {
  729. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}");
  730. PostMsg(MetalMsg.Error);
  731. AlarmListManager.Instance.AddDataError(Module.ToString(),
  732. $"{Module.ToString()}.metalUsage.AnodeAUsage",
  733. $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}");
  734. }
  735. else
  736. {
  737. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}");
  738. AlarmListManager.Instance.AddWarn(Module.ToString(),
  739. $"{Module.ToString()}.metalUsage.AnodeAUsage",
  740. $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}");
  741. }
  742. }
  743. //AnodeBUsage
  744. if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit") != 0)
  745. {
  746. if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit"))
  747. {
  748. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}");
  749. PostMsg(MetalMsg.Error);
  750. AlarmListManager.Instance.AddDataError(Module.ToString(),
  751. $"{Module.ToString()}.metalUsage.AnodeBUsage",
  752. $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}");
  753. }
  754. else
  755. {
  756. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}");
  757. AlarmListManager.Instance.AddWarn(Module.ToString(),
  758. $"{Module.ToString()}.metalUsage.AnodeBUsage",
  759. $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}");
  760. }
  761. }
  762. //MembraneAUsage
  763. if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit") != 0)
  764. {
  765. if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit"))
  766. {
  767. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}");
  768. PostMsg(MetalMsg.Error);
  769. AlarmListManager.Instance.AddDataError(Module.ToString(),
  770. $"{Module.ToString()}.metalUsage.MembraneAUsage",
  771. $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}");
  772. }
  773. else
  774. {
  775. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}");
  776. AlarmListManager.Instance.AddWarn(Module.ToString(),
  777. $"{Module.ToString()}.metalUsage.MembraneAUsage",
  778. $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}");
  779. }
  780. }
  781. //MembraneBUsage
  782. if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit") != 0)
  783. {
  784. if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit"))
  785. {
  786. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}");
  787. PostMsg(MetalMsg.Error);
  788. AlarmListManager.Instance.AddDataError(Module.ToString(),
  789. $"{Module.ToString()}.metalUsage.MembraneBUsage",
  790. $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}");
  791. }
  792. else
  793. {
  794. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}");
  795. AlarmListManager.Instance.AddWarn(Module.ToString(),
  796. $"{Module.ToString()}.metalUsage.MembraneBUsage",
  797. $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}");
  798. }
  799. }
  800. //TotalWafer
  801. if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit") != 0)
  802. {
  803. if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit"))
  804. {
  805. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit")}");
  806. PostMsg(MetalMsg.Error);
  807. AlarmListManager.Instance.AddDataError(Module.ToString(),
  808. $"{Module.ToString()}.metalUsage.TotalWafers",
  809. $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit")}");
  810. }
  811. else
  812. {
  813. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit")}");
  814. AlarmListManager.Instance.AddWarn(Module.ToString(),
  815. $"{Module.ToString()}.metalUsage.TotalWafers",
  816. $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit")}");
  817. }
  818. }
  819. //AnodeAWafer
  820. if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit") != 0)
  821. {
  822. if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit"))
  823. {
  824. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit")}");
  825. PostMsg(MetalMsg.Error);
  826. AlarmListManager.Instance.AddDataError(Module.ToString(),
  827. $"{Module.ToString()}.metalUsage.AnodeAWafers",
  828. $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit")}");
  829. }
  830. else
  831. {
  832. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit")}");
  833. AlarmListManager.Instance.AddWarn(Module.ToString(),
  834. $"{Module.ToString()}.metalUsage.AnodeAWafers",
  835. $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit")}");
  836. }
  837. }
  838. //AnodeBWafer
  839. if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit") != 0)
  840. {
  841. if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit"))
  842. {
  843. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}");
  844. PostMsg(MetalMsg.Error);
  845. AlarmListManager.Instance.AddDataError(Module.ToString(),
  846. $"{Module.ToString()}.metalUsage.AnodeBWafers",
  847. $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}");
  848. }
  849. else
  850. {
  851. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}");
  852. AlarmListManager.Instance.AddWarn(Module.ToString(),
  853. $"{Module.ToString()}.metalUsage.AnodeBWafers",
  854. $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}");
  855. }
  856. }
  857. //AnodeAbathUsage
  858. if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit") != 0)
  859. {
  860. if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit"))
  861. {
  862. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}");
  863. PostMsg(MetalMsg.Error);
  864. AlarmListManager.Instance.AddDataError(Module.ToString(),
  865. $"{Module.ToString()}.metalUsage.AnodeABathUsage",
  866. $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}");
  867. }
  868. else
  869. {
  870. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}");
  871. AlarmListManager.Instance.AddWarn(Module.ToString(),
  872. $"{Module.ToString()}.metalUsage.AnodeABathUsage",
  873. $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}");
  874. }
  875. }
  876. //AnodeBbathUsage
  877. if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit") != 0)
  878. {
  879. if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit"))
  880. {
  881. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}");
  882. PostMsg(MetalMsg.Error);
  883. AlarmListManager.Instance.AddDataError(Module.ToString(),
  884. $"{Module.ToString()}.metalUsage.AnodeBBathUsage",
  885. $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}");
  886. }
  887. else
  888. {
  889. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}");
  890. AlarmListManager.Instance.AddWarn(Module.ToString(),
  891. $"{Module.ToString()}.metalUsage.AnodeBBathUsage",
  892. $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}");
  893. }
  894. }
  895. }
  896. }
  897. /// <summary>
  898. /// 获取A面使用的电量
  899. /// </summary>
  900. /// <returns></returns>
  901. private double GetAnodeAUsage()
  902. {
  903. if (_metalItem.SubType == STRATUS)
  904. {
  905. return Math.Round(_standardHotRunRecipeRoutine.AnodeAUsage, 3);
  906. }
  907. else
  908. {
  909. return Math.Round(_compactEmbranceRunRecipeRoutine.AnodeAUsage, 3);
  910. }
  911. }
  912. /// <summary>
  913. /// 获取B面使用的电量
  914. /// </summary>
  915. /// <returns></returns>
  916. private double GetAnodeBUsage()
  917. {
  918. if (_metalItem.SubType == STRATUS)
  919. {
  920. return Math.Round(_standardHotRunRecipeRoutine.AnodeBUsage, 3);
  921. }
  922. else
  923. {
  924. return Math.Round(_compactEmbranceRunRecipeRoutine.AnodeBUsage, 3);
  925. }
  926. }
  927. /// <summary>
  928. /// Abort Recipe
  929. /// </summary>
  930. /// <param name="param"></param>
  931. /// <returns></returns>
  932. public bool AbortRecipe(object[] param)
  933. {
  934. _runRecipeCompleteTime = DateTime.Now;
  935. if (_metalItem.SubType == STRATUS)
  936. {
  937. _standardHotRunRecipeRoutine.Abort();
  938. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  939. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _standardHotRunRecipeRoutine.MetalLotTrackDatas,
  940. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  941. }
  942. else
  943. {
  944. _compactEmbranceRunRecipeRoutine.Abort();
  945. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  946. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas,
  947. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  948. }
  949. return true;
  950. }
  951. #endregion
  952. #region Current Short Test
  953. /// <summary>
  954. /// Current Short Test
  955. /// </summary>
  956. /// <param name="param"></param>
  957. /// <returns></returns>
  958. private bool CurrentShortTest(object[] param)
  959. {
  960. return _currentShortTestRoutine.Start() == RState.Running;
  961. }
  962. /// <summary>
  963. /// Current Short test监控
  964. /// </summary>
  965. /// <param name="param"></param>
  966. /// <returns></returns>
  967. private bool CurrentShortTestMonitor(object[] param)
  968. {
  969. RState rsstate = _currentShortTestRoutine.Monitor();
  970. if (rsstate == RState.End)
  971. {
  972. return true;
  973. }
  974. else if (rsstate == RState.Failed || rsstate == RState.Timeout)
  975. {
  976. PostMsg(MetalMsg.Error);
  977. return false;
  978. }
  979. return false;
  980. }
  981. #endregion
  982. #region Close Flow Valve
  983. /// <summary>
  984. /// 关闭Flow Valve
  985. /// </summary>
  986. /// <param name="param"></param>
  987. /// <returns></returns>
  988. private bool CloseFlowValve(object[] param)
  989. {
  990. if (_metalItem.SubType == STRATUS)
  991. {
  992. StandardHotMetalDevice device = DEVICE.GetDevice<StandardHotMetalDevice>(Module.ToString());
  993. if (device != null)
  994. {
  995. return device.SwitchToBypass("", null);
  996. }
  997. return false;
  998. }
  999. else
  1000. {
  1001. CompactMembranMetalDevice device = DEVICE.GetDevice<CompactMembranMetalDevice>(Module.ToString());
  1002. if (device != null)
  1003. {
  1004. string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  1005. CompactMembranReservoirDevice reservoirDevice = DEVICE.GetDevice<CompactMembranReservoirDevice>(reservoir);
  1006. if (reservoirDevice != null)
  1007. {
  1008. bool result = reservoirDevice.CAByPassOn("", null);
  1009. if (result)
  1010. {
  1011. return device.CellFlowValveOff("", null);
  1012. }
  1013. }
  1014. }
  1015. return false;
  1016. }
  1017. }
  1018. #endregion
  1019. #region Open Flow Valve
  1020. /// <summary>
  1021. /// 打开Flow Valve
  1022. /// </summary>
  1023. /// <param name="param"></param>
  1024. /// <returns></returns>
  1025. private bool OpenFlowValve(object[] param)
  1026. {
  1027. if (_metalItem.SubType == STRATUS)
  1028. {
  1029. StandardHotMetalDevice device = DEVICE.GetDevice<StandardHotMetalDevice>(Module.ToString());
  1030. if (device != null)
  1031. {
  1032. bool result = device.SwitchToFlow("", null);
  1033. if (result)
  1034. {
  1035. return device.OpenPump("", null);
  1036. }
  1037. }
  1038. return false;
  1039. }
  1040. else
  1041. {
  1042. CompactMembranMetalDevice device = DEVICE.GetDevice<CompactMembranMetalDevice>(Module.ToString());
  1043. if (device != null)
  1044. {
  1045. string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  1046. CompactMembranReservoirDevice reservoirDevice = DEVICE.GetDevice<CompactMembranReservoirDevice>(reservoir);
  1047. if (reservoirDevice != null)
  1048. {
  1049. bool result = reservoirDevice.CAByPassOff("", null);
  1050. if (result)
  1051. {
  1052. return device.CellFlowValveOn("", null);
  1053. }
  1054. }
  1055. }
  1056. return false;
  1057. }
  1058. }
  1059. #endregion
  1060. public bool Check(int msg, out string reason, params object[] args)
  1061. {
  1062. reason = "";
  1063. return true;
  1064. }
  1065. public bool CheckAcked(int msg)
  1066. {
  1067. return true;
  1068. }
  1069. public int Invoke(string function, params object[] args)
  1070. {
  1071. switch (function)
  1072. {
  1073. case "HomeAll":
  1074. if (IsIdle)
  1075. {
  1076. return (int)FSM_MSG.NONE;
  1077. }
  1078. if (CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Initialize))
  1079. {
  1080. return (int)MetalMsg.Initialize;
  1081. }
  1082. else
  1083. {
  1084. return (int)FSM_MSG.NONE;
  1085. }
  1086. }
  1087. return (int)FSM_MSG.NONE;
  1088. }
  1089. /// <summary>
  1090. /// 监控 PM Counter Metal用量
  1091. /// </summary>
  1092. private bool MetalUsageMointor(string Module)
  1093. {
  1094. MetalUsage metalUsage = MetalUsageManager.Instance.GetMetalUsage(Module);
  1095. if (metalUsage != null)
  1096. {
  1097. //TotalAUsage
  1098. if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit") != 0)
  1099. {
  1100. if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit"))
  1101. {
  1102. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}");
  1103. return false;
  1104. }
  1105. else
  1106. {
  1107. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}");
  1108. }
  1109. }
  1110. //AnodeAUsage
  1111. if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit") != 0)
  1112. {
  1113. if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit"))
  1114. {
  1115. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}");
  1116. return false;
  1117. }
  1118. else
  1119. {
  1120. LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}");
  1121. }
  1122. }
  1123. //AnodeBUsage
  1124. if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit") != 0)
  1125. {
  1126. if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit"))
  1127. {
  1128. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}");
  1129. return false;
  1130. }
  1131. else
  1132. {
  1133. LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}");
  1134. }
  1135. }
  1136. //MembraneAUsage
  1137. if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit") != 0)
  1138. {
  1139. if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit"))
  1140. {
  1141. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}");
  1142. return false;
  1143. }
  1144. else
  1145. {
  1146. LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}");
  1147. }
  1148. }
  1149. //MembraneBUsage
  1150. if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit") != 0)
  1151. {
  1152. if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit"))
  1153. {
  1154. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}");
  1155. }
  1156. else
  1157. {
  1158. LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}");
  1159. }
  1160. }
  1161. //TotalWafer
  1162. if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit") != 0)
  1163. {
  1164. if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit"))
  1165. {
  1166. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit")}");
  1167. return false;
  1168. }
  1169. else
  1170. {
  1171. LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit")}");
  1172. }
  1173. }
  1174. //AnodeAWafer
  1175. if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit") != 0)
  1176. {
  1177. if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit"))
  1178. {
  1179. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit")}");
  1180. return false;
  1181. }
  1182. else
  1183. {
  1184. LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit")}");
  1185. }
  1186. }
  1187. //AnodeBWafer
  1188. if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit") != 0)
  1189. {
  1190. if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit"))
  1191. {
  1192. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}");
  1193. return false;
  1194. }
  1195. else
  1196. {
  1197. LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}");
  1198. }
  1199. }
  1200. //AnodeAbathUsage
  1201. if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit") != 0)
  1202. {
  1203. if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit"))
  1204. {
  1205. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}");
  1206. return false;
  1207. }
  1208. else
  1209. {
  1210. LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}");
  1211. }
  1212. }
  1213. //AnodeBbathUsage
  1214. if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit") != 0)
  1215. {
  1216. if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit"))
  1217. {
  1218. LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}");
  1219. return false;
  1220. }
  1221. else
  1222. {
  1223. LOG.WriteLog(eEvent.WARN_METAL, Module, $"{Module} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}");
  1224. }
  1225. }
  1226. }
  1227. return true;
  1228. }
  1229. }
  1230. public enum MetalMsg
  1231. {
  1232. NONE,
  1233. Error,
  1234. ResumeError,
  1235. Initialize,
  1236. Manual,
  1237. Auto,
  1238. CurrentShortTest,
  1239. CloseFlowValve,
  1240. OpenFlowValve,
  1241. RunRecipe,
  1242. Abort,
  1243. Init
  1244. }
  1245. }