MetalEntity.cs 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  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}.subordinateReservoirPump", () => _reservoirDevice.ReservoirData.RegulatePumpSignalIn, 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 ("Auto".Equals(_persistentValue.OperatingMode))
  434. {
  435. if (!CheckReservoirIsAuto())
  436. {
  437. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), "Reservoir is not in Auto OperationMode");
  438. return false;
  439. }
  440. }
  441. if (_metalItem.SubType == STRATUS)
  442. {
  443. return _standardHotInitializeRoutine.Start(_persistentValue) == RState.Running;
  444. }
  445. else
  446. {
  447. return _compactEmbranceInitializeRoutine.Start(_persistentValue) == RState.Running;
  448. }
  449. }
  450. /// <summary>
  451. /// 检验Reservoir是否Initialized
  452. /// </summary>
  453. /// <returns></returns>
  454. private bool CheckReservoirInitialized()
  455. {
  456. string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  457. ReservoirEntity reservoirEntity = Singleton<RouteManager>.Instance.GetModule<ReservoirEntity>(reservoir);
  458. if (reservoirEntity != null)
  459. {
  460. return reservoirEntity.IsInitialized;
  461. }
  462. return false;
  463. }
  464. /// <summary>
  465. /// 检验Reservoir是否Auto
  466. /// </summary>
  467. /// <returns></returns>
  468. private bool CheckReservoirIsAuto()
  469. {
  470. string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  471. ReservoirsPersistentValue reservoirsPersistentValue = ReservoirsPersistentManager.Instance.GetReservoirsPersistentValue(reservoir);
  472. if ("Auto".Equals(reservoirsPersistentValue.OperatingMode))
  473. {
  474. return true;
  475. }
  476. return false;
  477. }
  478. /// <summary>
  479. /// 初始化监控
  480. /// </summary>
  481. /// <param name="param"></param>
  482. /// <returns></returns>
  483. private bool InitializeAllMonitor(object[] param)
  484. {
  485. RState rsstate = RState.Running;
  486. if (_metalItem.SubType == STRATUS)
  487. {
  488. rsstate = _standardHotInitializeRoutine.Monitor();
  489. }
  490. else
  491. {
  492. rsstate = _compactEmbranceInitializeRoutine.Monitor();
  493. }
  494. if (rsstate == RState.End)
  495. {
  496. return true;
  497. }
  498. else if (rsstate == RState.Failed || rsstate == RState.Timeout)
  499. {
  500. PostMsg(MetalMsg.Error);
  501. return false;
  502. }
  503. return false;
  504. }
  505. #endregion
  506. #region RunRecipe
  507. /// <summary>
  508. /// Run Recipe
  509. /// </summary>
  510. /// <param name="param"></param>
  511. /// <returns></returns>
  512. private bool RunRecipe(object[] param)
  513. {
  514. MetalUsageMointor(); //Metal run recipe前检查PMCounter消耗
  515. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  516. if (_metalItem.SubType == STRATUS)
  517. {
  518. StandardHotReservoirDevice resDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
  519. resDevice.ReservoirUsageMonitor();
  520. }
  521. DepRecipe recipe = param[0] as DepRecipe;
  522. _recipeSide = param[1].ToString();
  523. _cycle = (int)param[2];
  524. _runrecipeElapsedTime = 0;
  525. bool result = false;
  526. if (_metalItem.SubType == STRATUS)
  527. {
  528. _currentRunRecipeRoutine = _standardHotRunRecipeRoutine;
  529. result = _standardHotRunRecipeRoutine.Start(recipe, _recipeSide,_cycle) == RState.Running;
  530. }
  531. else
  532. {
  533. _currentRunRecipeRoutine = _compactEmbranceRunRecipeRoutine;
  534. result = _compactEmbranceRunRecipeRoutine.Start(recipe, _recipeSide, _cycle) == RState.Running;
  535. }
  536. if (result)
  537. {
  538. if (WaferHolderInfo != null)
  539. {
  540. WaferHolderInfo.MetalModuleName = Module;
  541. }
  542. _recipeTime = (recipe.CalculateRecipeTotalTime())*_cycle;
  543. _currentRecipe = recipe;
  544. if (WaferHolderInfo != null && WaferHolderInfo.SchedulerModules != null && WaferHolderInfo.SchedulerModules.Count != 0)
  545. {
  546. LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"{WaferHolderInfo?.Id} {string.Join(",", WaferHolderInfo.SchedulerModules)}");
  547. }
  548. _runRecipeStartTime = DateTime.Now;
  549. if (WaferHolderInfo != null && _currentRecipe != null)
  550. {
  551. FaModuleNotifier.Instance.NotifyWaferShuttleRecipeStart(WaferHolderInfo, _currentRecipe.Ppid);
  552. }
  553. }
  554. return result;
  555. }
  556. /// <summary>
  557. /// RunRecipe监控
  558. /// </summary>
  559. /// <param name="param"></param>
  560. /// <returns></returns>
  561. private bool RunRecipeMonitor(object[] param)
  562. {
  563. RState rsstate = RState.Running;
  564. if (_metalItem.SubType == STRATUS)
  565. {
  566. rsstate = _standardHotRunRecipeRoutine.Monitor();
  567. if (rsstate == RState.Running)
  568. {
  569. StandardHotMetalDevice _standardHotMetalDevice = DEVICE.GetDevice<StandardHotMetalDevice>(Module.ToString());
  570. if (_standardHotMetalDevice.MetalDeviceData.CellFlow <= 0)
  571. {
  572. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir metal cell flow is 0");
  573. rsstate = RState.Failed;
  574. }
  575. }
  576. _achievedCycle = _standardHotRunRecipeRoutine.GetCurrentCycle();
  577. }
  578. else
  579. {
  580. rsstate = _compactEmbranceRunRecipeRoutine.Monitor();
  581. if (rsstate == RState.Running)
  582. {
  583. CompactMembranMetalDevice _compactMembranMetalDevice = DEVICE.GetDevice<CompactMembranMetalDevice>(Module.ToString());
  584. if (_compactMembranMetalDevice.MetalDeviceData.CellFlow <= 0)
  585. {
  586. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir metal cell flow is 0");
  587. rsstate = RState.Failed;
  588. }
  589. if (_compactMembranMetalDevice.ANACellFlow.CounterValue <= 0) //检查hold flow
  590. {
  591. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir AnodeA flow is 0");
  592. rsstate = RState.Failed;
  593. }
  594. if (_compactMembranMetalDevice.ANBCellFlow.CounterValue <= 0)
  595. {
  596. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"reservoir AnodeB flow is 0");
  597. rsstate = RState.Failed;
  598. }
  599. }
  600. }
  601. if (Singleton<RouteManager>.Instance.IsAutoRunning && _runrecipeElapsedTime != TimeToReady)
  602. {
  603. _runrecipeElapsedTime = TimeToReady;
  604. LOG.WriteLog(eEvent.INFO_METAL, Module.ToString(), $"{WaferHolderInfo?.Id} {Module} RunRecipe TimeToReady {TimeToReady}s.");
  605. }
  606. if (rsstate == RState.End)
  607. {
  608. _recipeTime = 0;
  609. if (WaferHolderInfo != null)
  610. {
  611. double anodeAUsage = GetAnodeAUsage();
  612. double anodeBUsage = GetAnodeBUsage();
  613. MetalUsageManager.Instance.UpdateMetalUsage(Module.ToString(), _recipeSide, anodeAUsage, anodeBUsage);
  614. MetalUsageMointor(); //检查PMCounter消耗
  615. //CMM Usage
  616. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  617. if (_metalItem.SubType == STRATUS)
  618. {
  619. StandardHotReservoirDevice resDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
  620. resDevice.ReservoirUsageMonitor();
  621. resDevice.SetExportCMMUsage();
  622. }
  623. WaferHolderInfo.LastMetalRecipeCompleteTime = DateTime.Now;
  624. }
  625. _runrecipeElapsedTime = 0;
  626. //记录LotTrack
  627. _runRecipeCompleteTime = DateTime.Now;
  628. int timeLength = (int)(_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds;
  629. if (_metalItem.SubType == STRATUS)
  630. {
  631. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  632. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _standardHotRunRecipeRoutine.MetalLotTrackDatas,
  633. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  634. }
  635. else
  636. {
  637. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  638. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas,
  639. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  640. }
  641. if (WaferHolderInfo != null && _currentRecipe != null)
  642. {
  643. FaModuleNotifier.Instance.NotifyWaferShuttleRecipeEnd(WaferHolderInfo, _currentRecipe.Ppid, timeLength);
  644. }
  645. return true;
  646. }
  647. else if (rsstate == RState.Failed || rsstate == RState.Timeout)
  648. {
  649. _recipeTime = 0;
  650. if (WaferHolderInfo != null)
  651. {
  652. double anodeAUsage = GetAnodeAUsage();
  653. double anodeBUsage = GetAnodeBUsage();
  654. MetalUsageManager.Instance.UpdateMetalUsage(Module.ToString(), _recipeSide, anodeAUsage, anodeBUsage);
  655. MetalUsageMointor(); //失败了也要检查PMCounter消耗
  656. //CMMUsage
  657. string reservoirName = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  658. if (_metalItem.SubType == STRATUS)
  659. {
  660. StandardHotReservoirDevice resDevice = DEVICE.GetDevice<StandardHotReservoirDevice>(reservoirName);
  661. resDevice.ReservoirUsageMonitor();
  662. resDevice.SetExportCMMUsage();
  663. }
  664. }
  665. _runrecipeElapsedTime = 0;
  666. if (WaferHolderInfo != null && _currentRecipe != null)
  667. {
  668. WaferHolderInfo.LastMetalRecipeCompleteTime = DateTime.Now;
  669. }
  670. PostMsg(MetalMsg.Error);
  671. //记录LotTrack
  672. _runRecipeCompleteTime = DateTime.Now;
  673. if (_metalItem.SubType == STRATUS)
  674. {
  675. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  676. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _standardHotRunRecipeRoutine.MetalLotTrackDatas,
  677. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  678. }
  679. else
  680. {
  681. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  682. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas,
  683. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  684. }
  685. if (WaferHolderInfo != null && _currentRecipe != null)
  686. {
  687. FaModuleNotifier.Instance.NotifyWaferShuttleRecipeFailed(WaferHolderInfo, _currentRecipe.Ppid);
  688. }
  689. return false;
  690. }
  691. return false;
  692. }
  693. /// <summary>
  694. /// 监控 PM Counter Metal用量
  695. /// </summary>
  696. private void MetalUsageMointor()
  697. {
  698. MetalUsage metalUsage = MetalUsageManager.Instance.GetMetalUsage(Module.ToString());
  699. if (metalUsage != null)
  700. {
  701. //TotalAUsage
  702. if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit") != 0)
  703. {
  704. if (metalUsage.TotalUsage > SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit"))
  705. {
  706. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}");
  707. PostMsg(MetalMsg.Error);
  708. AlarmListManager.Instance.AddDataError(Module.ToString(),
  709. $"{Module.ToString()}.metalUsage.TotalUsage",
  710. $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursFaultLimit")}");
  711. }
  712. else
  713. {
  714. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}");
  715. AlarmListManager.Instance.AddWarn(Module.ToString(),
  716. $"{Module.ToString()}.metalUsage.TotalUsage",
  717. $"{Module.ToString()} usage:{metalUsage.TotalUsage} is exceed MetalTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MetalTotalAmpHoursWarningLimit")}");
  718. }
  719. }
  720. //AnodeAUsage
  721. if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit") != 0)
  722. {
  723. if (metalUsage.AnodeAUsage > SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit"))
  724. {
  725. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}");
  726. PostMsg(MetalMsg.Error);
  727. AlarmListManager.Instance.AddDataError(Module.ToString(),
  728. $"{Module.ToString()}.metalUsage.AnodeAUsage",
  729. $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursFaultLimit")}");
  730. }
  731. else
  732. {
  733. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}");
  734. AlarmListManager.Instance.AddWarn(Module.ToString(),
  735. $"{Module.ToString()}.metalUsage.AnodeAUsage",
  736. $"{Module.ToString()} usage:{metalUsage.AnodeAUsage} is exceed AnodeATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeATotalAmpHoursWarningLimit")}");
  737. }
  738. }
  739. //AnodeBUsage
  740. if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit") != 0)
  741. {
  742. if (metalUsage.AnodeBUsage > SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit"))
  743. {
  744. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}");
  745. PostMsg(MetalMsg.Error);
  746. AlarmListManager.Instance.AddDataError(Module.ToString(),
  747. $"{Module.ToString()}.metalUsage.AnodeBUsage",
  748. $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursFaultLimit")}");
  749. }
  750. else
  751. {
  752. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}");
  753. AlarmListManager.Instance.AddWarn(Module.ToString(),
  754. $"{Module.ToString()}.metalUsage.AnodeBUsage",
  755. $"{Module.ToString()} usage:{metalUsage.AnodeBUsage} is exceed AnodeBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.AnodeBTotalAmpHoursWarningLimit")}");
  756. }
  757. }
  758. //MembraneAUsage
  759. if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit") != 0)
  760. {
  761. if (metalUsage.MembranceAUsage > SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit"))
  762. {
  763. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}");
  764. PostMsg(MetalMsg.Error);
  765. AlarmListManager.Instance.AddDataError(Module.ToString(),
  766. $"{Module.ToString()}.metalUsage.MembraneAUsage",
  767. $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursFaultLimit")}");
  768. }
  769. else
  770. {
  771. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}");
  772. AlarmListManager.Instance.AddWarn(Module.ToString(),
  773. $"{Module.ToString()}.metalUsage.MembraneAUsage",
  774. $"{Module.ToString()} usage:{metalUsage.MembranceAUsage} is exceed MembraneATotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneATotalAmpHoursWarningLimit")}");
  775. }
  776. }
  777. //MembraneBUsage
  778. if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit") != 0 && SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit") != 0)
  779. {
  780. if (metalUsage.MembranceBUsage > SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit"))
  781. {
  782. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}");
  783. PostMsg(MetalMsg.Error);
  784. AlarmListManager.Instance.AddDataError(Module.ToString(),
  785. $"{Module.ToString()}.metalUsage.MembraneBUsage",
  786. $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursFaultLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursFaultLimit")}");
  787. }
  788. else
  789. {
  790. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}");
  791. AlarmListManager.Instance.AddWarn(Module.ToString(),
  792. $"{Module.ToString()}.metalUsage.MembraneBUsage",
  793. $"{Module.ToString()} usage:{metalUsage.MembranceBUsage} is exceed MembraneBTotalAmpHoursWarningLimit:{SC.GetValue<double>($"Metal.{Module}.MembraneBTotalAmpHoursWarningLimit")}");
  794. }
  795. }
  796. //TotalWafer
  797. if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit") != 0)
  798. {
  799. if (metalUsage.TotalWafers > SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit"))
  800. {
  801. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit")}");
  802. PostMsg(MetalMsg.Error);
  803. AlarmListManager.Instance.AddDataError(Module.ToString(),
  804. $"{Module.ToString()}.metalUsage.TotalWafers",
  805. $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersFaultLimit")}");
  806. }
  807. else
  808. {
  809. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit")}");
  810. AlarmListManager.Instance.AddWarn(Module.ToString(),
  811. $"{Module.ToString()}.metalUsage.TotalWafers",
  812. $"{Module.ToString()} usage:{metalUsage.TotalWafers} is exceed MetalTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.MetalTotalWafersWarningLimit")}");
  813. }
  814. }
  815. //AnodeAWafer
  816. if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit") != 0)
  817. {
  818. if (metalUsage.AnodeAWafers > SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit"))
  819. {
  820. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit")}");
  821. PostMsg(MetalMsg.Error);
  822. AlarmListManager.Instance.AddDataError(Module.ToString(),
  823. $"{Module.ToString()}.metalUsage.AnodeAWafers",
  824. $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersFaultLimit")}");
  825. }
  826. else
  827. {
  828. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit")}");
  829. AlarmListManager.Instance.AddWarn(Module.ToString(),
  830. $"{Module.ToString()}.metalUsage.AnodeAWafers",
  831. $"{Module.ToString()} usage:{metalUsage.AnodeAWafers} is exceed AnodeATotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeATotalWafersWarningLimit")}");
  832. }
  833. }
  834. //AnodeBWafer
  835. if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit") != 0)
  836. {
  837. if (metalUsage.AnodeBWafers > SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit"))
  838. {
  839. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}");
  840. PostMsg(MetalMsg.Error);
  841. AlarmListManager.Instance.AddDataError(Module.ToString(),
  842. $"{Module.ToString()}.metalUsage.AnodeBWafers",
  843. $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersFaultLimit")}");
  844. }
  845. else
  846. {
  847. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}");
  848. AlarmListManager.Instance.AddWarn(Module.ToString(),
  849. $"{Module.ToString()}.metalUsage.AnodeBWafers",
  850. $"{Module.ToString()} usage:{metalUsage.AnodeBWafers} is exceed AnodeBTotalWafersWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBTotalWafersWarningLimit")}");
  851. }
  852. }
  853. //AnodeAbathUsage
  854. if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit") != 0)
  855. {
  856. if (metalUsage.AnodeABathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit"))
  857. {
  858. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}");
  859. PostMsg(MetalMsg.Error);
  860. AlarmListManager.Instance.AddDataError(Module.ToString(),
  861. $"{Module.ToString()}.metalUsage.AnodeABathUsage",
  862. $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysFaultLimit")}");
  863. }
  864. else
  865. {
  866. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}");
  867. AlarmListManager.Instance.AddWarn(Module.ToString(),
  868. $"{Module.ToString()}.metalUsage.AnodeABathUsage",
  869. $"{Module.ToString()} usage:{metalUsage.AnodeABathUsage} is exceed AnodeABathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeABathTotalUsageDaysWarningLimit")}");
  870. }
  871. }
  872. //AnodeBbathUsage
  873. if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit") != 0 && SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit") != 0)
  874. {
  875. if (metalUsage.AnodeBBathUsage > SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit"))
  876. {
  877. LOG.WriteLog(eEvent.ERR_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}");
  878. PostMsg(MetalMsg.Error);
  879. AlarmListManager.Instance.AddDataError(Module.ToString(),
  880. $"{Module.ToString()}.metalUsage.AnodeBBathUsage",
  881. $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysFaultLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysFaultLimit")}");
  882. }
  883. else
  884. {
  885. LOG.WriteLog(eEvent.WARN_METAL, Module.ToString(), $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}");
  886. AlarmListManager.Instance.AddWarn(Module.ToString(),
  887. $"{Module.ToString()}.metalUsage.AnodeBBathUsage",
  888. $"{Module.ToString()} usage:{metalUsage.AnodeBBathUsage} is exceed AnodeBBathTotalUsageDaysWarningLimit:{SC.GetValue<int>($"Metal.{Module}.AnodeBBathTotalUsageDaysWarningLimit")}");
  889. }
  890. }
  891. }
  892. }
  893. /// <summary>
  894. /// 获取A面使用的电量
  895. /// </summary>
  896. /// <returns></returns>
  897. private double GetAnodeAUsage()
  898. {
  899. if (_metalItem.SubType == STRATUS)
  900. {
  901. return Math.Round(_standardHotRunRecipeRoutine.AnodeAUsage, 3);
  902. }
  903. else
  904. {
  905. return Math.Round(_compactEmbranceRunRecipeRoutine.AnodeAUsage, 3);
  906. }
  907. }
  908. /// <summary>
  909. /// 获取B面使用的电量
  910. /// </summary>
  911. /// <returns></returns>
  912. private double GetAnodeBUsage()
  913. {
  914. if (_metalItem.SubType == STRATUS)
  915. {
  916. return Math.Round(_standardHotRunRecipeRoutine.AnodeBUsage, 3);
  917. }
  918. else
  919. {
  920. return Math.Round(_compactEmbranceRunRecipeRoutine.AnodeBUsage, 3);
  921. }
  922. }
  923. /// <summary>
  924. /// Abort Recipe
  925. /// </summary>
  926. /// <param name="param"></param>
  927. /// <returns></returns>
  928. public bool AbortRecipe(object[] param)
  929. {
  930. _runRecipeCompleteTime = DateTime.Now;
  931. if (_metalItem.SubType == STRATUS)
  932. {
  933. _standardHotRunRecipeRoutine.Abort();
  934. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  935. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _standardHotRunRecipeRoutine.MetalLotTrackDatas,
  936. _standardHotRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  937. }
  938. else
  939. {
  940. _compactEmbranceRunRecipeRoutine.Abort();
  941. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas.ProcessTime = (_runRecipeCompleteTime - _runRecipeStartTime).TotalSeconds.ToString("F2");
  942. MetalLotTrackUtil.ExportMetalLotTrack(Module.ToString(), _compactEmbranceRunRecipeRoutine.MetalLotTrackDatas,
  943. _compactEmbranceRunRecipeRoutine.MetalLotTrackHeaderDatas, IsAuto, _currentRecipe, _metalItem.SubType);
  944. }
  945. return true;
  946. }
  947. #endregion
  948. #region Current Short Test
  949. /// <summary>
  950. /// Current Short Test
  951. /// </summary>
  952. /// <param name="param"></param>
  953. /// <returns></returns>
  954. private bool CurrentShortTest(object[] param)
  955. {
  956. return _currentShortTestRoutine.Start() == RState.Running;
  957. }
  958. /// <summary>
  959. /// Current Short test监控
  960. /// </summary>
  961. /// <param name="param"></param>
  962. /// <returns></returns>
  963. private bool CurrentShortTestMonitor(object[] param)
  964. {
  965. RState rsstate = _currentShortTestRoutine.Monitor();
  966. if (rsstate == RState.End)
  967. {
  968. return true;
  969. }
  970. else if (rsstate == RState.Failed || rsstate == RState.Timeout)
  971. {
  972. PostMsg(MetalMsg.Error);
  973. return false;
  974. }
  975. return false;
  976. }
  977. #endregion
  978. #region Close Flow Valve
  979. /// <summary>
  980. /// 关闭Flow Valve
  981. /// </summary>
  982. /// <param name="param"></param>
  983. /// <returns></returns>
  984. private bool CloseFlowValve(object[] param)
  985. {
  986. if (_metalItem.SubType == STRATUS)
  987. {
  988. StandardHotMetalDevice device = DEVICE.GetDevice<StandardHotMetalDevice>(Module.ToString());
  989. if (device != null)
  990. {
  991. return device.SwitchToBypass("", null);
  992. }
  993. return false;
  994. }
  995. else
  996. {
  997. CompactMembranMetalDevice device = DEVICE.GetDevice<CompactMembranMetalDevice>(Module.ToString());
  998. if (device != null)
  999. {
  1000. string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  1001. CompactMembranReservoirDevice reservoirDevice = DEVICE.GetDevice<CompactMembranReservoirDevice>(reservoir);
  1002. if (reservoirDevice != null)
  1003. {
  1004. bool result = reservoirDevice.CAByPassOn("", null);
  1005. if (result)
  1006. {
  1007. return device.CellFlowValveOff("", null);
  1008. }
  1009. }
  1010. }
  1011. return false;
  1012. }
  1013. }
  1014. #endregion
  1015. #region Open Flow Valve
  1016. /// <summary>
  1017. /// 打开Flow Valve
  1018. /// </summary>
  1019. /// <param name="param"></param>
  1020. /// <returns></returns>
  1021. private bool OpenFlowValve(object[] param)
  1022. {
  1023. if (_metalItem.SubType == STRATUS)
  1024. {
  1025. StandardHotMetalDevice device = DEVICE.GetDevice<StandardHotMetalDevice>(Module.ToString());
  1026. if (device != null)
  1027. {
  1028. bool result = device.SwitchToFlow("", null);
  1029. if (result)
  1030. {
  1031. return device.OpenPump("", null);
  1032. }
  1033. }
  1034. return false;
  1035. }
  1036. else
  1037. {
  1038. CompactMembranMetalDevice device = DEVICE.GetDevice<CompactMembranMetalDevice>(Module.ToString());
  1039. if (device != null)
  1040. {
  1041. string reservoir = ReservoirItemManager.Instance.GetReservoirByMetal(Module.ToString());
  1042. CompactMembranReservoirDevice reservoirDevice = DEVICE.GetDevice<CompactMembranReservoirDevice>(reservoir);
  1043. if (reservoirDevice != null)
  1044. {
  1045. bool result = reservoirDevice.CAByPassOff("", null);
  1046. if (result)
  1047. {
  1048. return device.CellFlowValveOn("", null);
  1049. }
  1050. }
  1051. }
  1052. return false;
  1053. }
  1054. }
  1055. #endregion
  1056. public bool Check(int msg, out string reason, params object[] args)
  1057. {
  1058. reason = "";
  1059. return true;
  1060. }
  1061. public bool CheckAcked(int msg)
  1062. {
  1063. return true;
  1064. }
  1065. public int Invoke(string function, params object[] args)
  1066. {
  1067. switch (function)
  1068. {
  1069. case "HomeAll":
  1070. if (IsIdle)
  1071. {
  1072. return (int)FSM_MSG.NONE;
  1073. }
  1074. if (CheckToPostMessage<MetalState, MetalMsg>(eEvent.ERR_METAL, Module.ToString(), (int)MetalMsg.Initialize))
  1075. {
  1076. return (int)MetalMsg.Initialize;
  1077. }
  1078. else
  1079. {
  1080. return (int)FSM_MSG.NONE;
  1081. }
  1082. }
  1083. return (int)FSM_MSG.NONE;
  1084. }
  1085. }
  1086. public enum MetalMsg
  1087. {
  1088. NONE,
  1089. Error,
  1090. ResumeError,
  1091. Initialize,
  1092. Manual,
  1093. Auto,
  1094. CurrentShortTest,
  1095. CloseFlowValve,
  1096. OpenFlowValve,
  1097. RunRecipe,
  1098. Abort,
  1099. Init
  1100. }
  1101. }