EfemDevice.cs 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264
  1. using Aitex.Core.Common;
  2. using Aitex.Core.Common.DeviceData;
  3. using Aitex.Core.RT.DataCenter;
  4. using Aitex.Core.RT.Device;
  5. using Aitex.Core.RT.Event;
  6. using Aitex.Core.RT.Log;
  7. using Aitex.Core.RT.OperationCenter;
  8. using Aitex.Core.RT.SCCore;
  9. using Aitex.Core.Util;
  10. using Aitex.Sorter.Common;
  11. using MECF.Framework.Common.Equipment;
  12. using MECF.Framework.Common.SubstrateTrackings;
  13. using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Robot;
  14. using System;
  15. using System.Collections;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.Linq;
  19. using System.Threading;
  20. using System.Xml;
  21. using VirgoCommon;
  22. using VirgoRT.Devices;
  23. using VirgoRT.Devices.YASKAWA;
  24. using VirgoRT.HostWrapper;
  25. using VirgoRT.Modules;
  26. namespace VirgoRT.Device
  27. {
  28. class EfemCommunicationBase
  29. {
  30. protected readonly AsyncSocket _socket = new AsyncSocket("");
  31. protected EfemCommunicationBase(string sIP)
  32. {
  33. string ip_address = sIP;
  34. if (SC.GetValue<bool>("System.IsSimulatorMode"))
  35. {
  36. ip_address = "127.0.0.1:13001";
  37. }
  38. _socket.Connect(ip_address);
  39. _socket.OnDataChanged += Hardware_OnDataChanged;
  40. _socket.OnErrorHappened += Hardware_OnErrorHappened;
  41. //if (!_socket.IsConnected)
  42. //{
  43. // EV.PostAlarmLog(ModuleName.EFEM.ToString(), "Cannot connect to EFEM");
  44. //}
  45. }
  46. private void Hardware_OnDataChanged(string message)
  47. {
  48. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.RecHwMsg, message);
  49. }
  50. private void Hardware_OnErrorHappened(ErrorEventArgs args)
  51. {
  52. }
  53. public virtual void SendTo(string str) { }
  54. public virtual void SendTo(IEfemMessage yas_msg) { }
  55. }
  56. class EfemBase : BaseDevice, IDevice
  57. {
  58. // Fields
  59. //
  60. protected volatile LinkedList<ActionBase> _actions = new LinkedList<ActionBase>();
  61. protected EfemCommunicationBase _comm;
  62. protected IMessageHandler _msgHandler;
  63. public virtual ILoadport this[ModuleName mod]
  64. {
  65. get { throw new ApplicationException(); }
  66. }
  67. // Properties
  68. //
  69. public new ModuleName Module { get; set; }
  70. public OnlineFlag OnlineFlag { get; set; }
  71. public bool CommunicationConnected { get; protected set; }
  72. public DeviceState Status { get; set; }
  73. public bool HasActions
  74. {
  75. get
  76. {
  77. lock (_lockerAction)
  78. {
  79. return _actions.Any(x => x.Status == ActionStatus.Pending);
  80. }
  81. }
  82. }
  83. public EfemCommunicationBase Comm => _comm;
  84. public IMessageHandler MsgHandler => _msgHandler;
  85. protected object _lockerAction = new object();
  86. public string GripStateBlade1
  87. {
  88. get;
  89. set;
  90. }
  91. public string GripStateBlade2
  92. {
  93. get;
  94. set;
  95. }
  96. protected EfemBase(XmlElement xmlNode = null)
  97. {
  98. }
  99. public bool Initialize()
  100. {
  101. return true;
  102. }
  103. public void Monitor()
  104. {
  105. throw new NotImplementedException();
  106. }
  107. public void Terminate()
  108. {
  109. throw new NotImplementedException();
  110. }
  111. public void Reset()
  112. {
  113. throw new NotImplementedException();
  114. }
  115. // Methods
  116. //
  117. public void ExecuteAction()
  118. {
  119. lock (_lockerAction)
  120. {
  121. if (!_actions.Any())
  122. {
  123. LOG.Write("No Action in the EFEM Queue");
  124. return;
  125. }
  126. if (_actions.All(x => x.Status != ActionStatus.Pending))
  127. {
  128. LOG.Write("NO pending Action in EFEM Queue");
  129. //System.Diagnostics.Trace.Assert(false);
  130. return;
  131. }
  132. var nextAction = _actions.First(a => a.Status == ActionStatus.Pending);
  133. if (nextAction != null)
  134. {
  135. LOG.Write($"found pending action : efem action [{nextAction.GetType().Name}] [{nextAction.ID}] 开始执行");
  136. nextAction.Execute();
  137. }
  138. }
  139. }
  140. public void ClearActions()
  141. {
  142. lock (_lockerAction)
  143. {
  144. _actions?.Clear();
  145. LOG.Write($"clear all efem action");
  146. }
  147. }
  148. public void AddAction(ActionBase cmd)
  149. {
  150. lock (_lockerAction)
  151. {
  152. _actions.AddLast(cmd);
  153. LOG.Write($"efem action [{cmd.GetType().Name}] [{cmd.ID}] add to queue");
  154. if (cmd.IsBackground)
  155. {
  156. LOG.Write($"background, efem action [{cmd.GetType().Name}] [{cmd.ID}] 开始执行");
  157. cmd.Execute();
  158. }
  159. if (cmd is LedAction)
  160. {
  161. Thread.Sleep(50);
  162. }
  163. }
  164. }
  165. public void UpdateStatus(ushort Id, ActionStatus st)
  166. {
  167. lock (_lockerAction)
  168. {
  169. var cur = _actions.First(x => x.ID == Id);
  170. if (null == cur)
  171. {
  172. LOG.Write($"NO {Id} action in the queue");
  173. return;
  174. }
  175. cur.Status = st;
  176. if (st == ActionStatus.Completed)
  177. {
  178. cur.OnPostWork();
  179. _actions.Remove(cur);
  180. LOG.Write($"efem action [{cur.GetType().Name}] [{cur.ID}] removed from queue");
  181. }
  182. }
  183. }
  184. public virtual void ReceiveMessage(string sRec) { throw new NotImplementedException(); }
  185. public void SetOnline(bool online)
  186. {
  187. this.OnlineFlag = online ? OnlineFlag.Online : OnlineFlag.Offline;
  188. }
  189. public virtual void SetOnline(ModuleName mod, bool online) { }
  190. public virtual void SetBusy(ModuleName mod, bool online) { }
  191. }
  192. }
  193. namespace VirgoRT.Device.YASKAWA
  194. {
  195. sealed class MessageHandler : IMessageHandler
  196. {
  197. // Fields
  198. //
  199. private readonly IList<EfemMessage> _msgQueue = new List<EfemMessage>();
  200. private readonly EfemBase _efem;
  201. // Properties
  202. //
  203. public bool IsCompleted
  204. {
  205. get
  206. {
  207. if (_msgQueue.Count <= 0) return false;
  208. return EfemMessage.MsgHead.INF == _msgQueue[_msgQueue.Count - 1].Head;
  209. }
  210. }
  211. public event EventHandler<EfemActionArgs> CommandUpdated;
  212. public event EventHandler<EfemEventArgs> EventUpdated;
  213. public event EventHandler<EfemErrorArgs> ErrorOccurred;
  214. // Constructor
  215. //
  216. public MessageHandler(EfemBase device)
  217. {
  218. _efem = device;
  219. }
  220. public void Send(IEfemMessage msg)
  221. {
  222. _efem.Comm.SendTo(msg);
  223. _msgQueue.Add(msg as EfemMessage);
  224. }
  225. public void ReceiveMessage(string sRec)
  226. {
  227. string[] msgs = sRec.Split('\r');
  228. foreach (var msg in msgs)
  229. {
  230. if (string.IsNullOrWhiteSpace(msg)) continue;
  231. EfemMessage rec_msg = msg.ToMessage();
  232. switch (rec_msg.Head)
  233. {
  234. case EfemMessage.MsgHead.ACK:
  235. _msgQueue.Add(rec_msg);
  236. OnCommandUpdated(new EfemActionArgs
  237. {
  238. Module = rec_msg.Port,
  239. CommandType = rec_msg.Operation,
  240. Status = ActionStatus.RecACK
  241. });
  242. break;
  243. case EfemMessage.MsgHead.INF:
  244. OnCommandUpdated(new EfemActionArgs
  245. {
  246. Module = rec_msg.Port,
  247. CommandType = rec_msg.Operation,
  248. Status = ActionStatus.RecINF
  249. });
  250. // 收到INF之后发送ACK确认
  251. string strACK = rec_msg.RawString.Replace("INF", "ACK");
  252. _efem.Comm.SendTo(strACK);
  253. EfemMessage ack_msg = strACK.ToMessage();
  254. ack_msg.Direct = MsgDirection.To;
  255. _msgQueue.Add(ack_msg);
  256. OnCommandUpdated(new EfemActionArgs
  257. {
  258. Module = rec_msg.Port,
  259. CommandType = rec_msg.Operation,
  260. Status = ActionStatus.Completed,
  261. Data = rec_msg.Data.Count > 0 ? rec_msg.Data.First() : string.Empty
  262. });
  263. break;
  264. case EfemMessage.MsgHead.EVT:
  265. OnEventUpdated(new EfemEventArgs
  266. {
  267. EvtStr = rec_msg.ToParamString(),
  268. Module = rec_msg.Port,
  269. CommandType = rec_msg.Operation,
  270. DataList = rec_msg.Data
  271. });
  272. break;
  273. case EfemMessage.MsgHead.NAK:
  274. OnErrorOccurred(new EfemErrorArgs
  275. {
  276. Factor = rec_msg.Factor,
  277. Description = Constant.FactorString.ContainsKey(rec_msg.Factor) ? Constant.FactorString[rec_msg.Factor] : rec_msg.Factor,
  278. });
  279. break;
  280. case EfemMessage.MsgHead.CAN:
  281. OnErrorOccurred(new EfemErrorArgs
  282. {
  283. Factor = rec_msg.Factor,
  284. Description = Constant.FactorString.ContainsKey(rec_msg.Factor) ? Constant.FactorString[rec_msg.Factor] : rec_msg.Factor,
  285. Message = rec_msg.Data[0]
  286. });
  287. break;
  288. case EfemMessage.MsgHead.ABS:
  289. OnErrorOccurred(new EfemErrorArgs
  290. {
  291. Factor = rec_msg.Factor,
  292. Description = $"{rec_msg.Data[0]}, {rec_msg.Data[1]}"
  293. });
  294. break;
  295. }
  296. }
  297. }
  298. private void OnCommandUpdated(EfemActionArgs args)
  299. {
  300. CommandUpdated?.Invoke(this, args);
  301. }
  302. private void OnEventUpdated(EfemEventArgs args)
  303. {
  304. EventUpdated?.Invoke(this, args);
  305. }
  306. private void OnErrorOccurred(EfemErrorArgs args)
  307. {
  308. ErrorOccurred?.Invoke(this, args);
  309. }
  310. }
  311. sealed class EfemComm : EfemCommunicationBase
  312. {
  313. public EfemComm() : base(SC.GetStringValue("EFEM.IPAddress"))
  314. {
  315. }
  316. public override void SendTo(string str) { _socket.Write(str + '\r'); }
  317. public override void SendTo(IEfemMessage msg)
  318. {
  319. if (msg is EfemMessage yas_msg)
  320. {
  321. //string str = EfemParser.Instance.TranslateBack(yas_msg);
  322. string str = yas_msg.ToString();
  323. if (string.IsNullOrEmpty(str))
  324. throw new ApplicationException("Yaskawa message translation error");
  325. yas_msg.RawString = str;
  326. SendTo(str);
  327. }
  328. }
  329. }
  330. /// <summary>
  331. /// EFEM object class
  332. /// </summary>
  333. sealed class Efem : EfemBase, IEfem
  334. {
  335. //---------------------------------Fields----------------------------------------
  336. //
  337. private readonly JetPM[] _pm = new JetPM[2];
  338. private readonly Loadport[] _LPMs = new Loadport[2];
  339. private readonly SignalTower _signalT = new SignalTower();
  340. //private readonly CoolingStage[] _aligner = new CoolingStage[2];
  341. private string _robotMoveAction;
  342. private LidState _CassetteDoor;
  343. private LidState _SideDoor;
  344. private RD_TRIG _bSysVacPressure1 = new RD_TRIG(); //Bit[0] System vacuum source pressure 1
  345. private RD_TRIG _bIonizerCompressedAir = new RD_TRIG(); //Bit[1] Ionizer compressed air
  346. private RD_TRIG _bSysCompressedAirPressure = new RD_TRIG(); //Bit[2] System compressed air pressure 1
  347. private RD_TRIG _bFlowGaugeSensor = new RD_TRIG(); //Bit[4] Flow gauge sensor
  348. private RD_TRIG _bLeakageSensor = new RD_TRIG(); //Bit[5] Leakage sensor
  349. private RD_TRIG _bDiffPressureSensorSetting1 = new RD_TRIG(); //Bit[8] Differential pressure sensor setting 1
  350. private RD_TRIG _bDiffPressureSensorSetting2 = new RD_TRIG(); //Bit[9] Differential pressure sensor setting 2
  351. private RD_TRIG _bIonizerAlarm = new RD_TRIG(); //Bit[10] Ionizer alarm
  352. private RD_TRIG _bFFuAlarm = new RD_TRIG();
  353. private RD_TRIG _bAreaSensor = new RD_TRIG();
  354. private RD_TRIG _bModeSwitch = new RD_TRIG();
  355. private RD_TRIG _bCassetteDoorTrig = new RD_TRIG();
  356. private RD_TRIG _bSideDoorTrig = new RD_TRIG();
  357. public override ILoadport this[ModuleName mod]
  358. {
  359. get
  360. {
  361. if (!ModuleHelper.IsLoadPort(mod))
  362. throw new ApplicationException($"{mod} is NOT Loadport");
  363. return _LPMs[mod - ModuleName.LP1];
  364. }
  365. }
  366. //---------------------------------Properties------------------------------------
  367. //
  368. public LidState CassetteDoor
  369. {
  370. get => _CassetteDoor;
  371. set
  372. {
  373. _CassetteDoor = value;
  374. _bCassetteDoorTrig.CLK = _CassetteDoor == LidState.Close;
  375. if (_bCassetteDoorTrig.T)
  376. {
  377. EV.Notify(CassetteDoorOpen);
  378. EV.PostWarningLog(Module.ToString(), "Cassette door opened");
  379. }
  380. if (_bCassetteDoorTrig.R)
  381. {
  382. EV.Notify(CassetteDoorClose);
  383. EV.PostInfoLog(Module.ToString(), "Cassette door closed");
  384. }
  385. }
  386. }
  387. public LidState DoorSwitch
  388. {
  389. get => _SideDoor;
  390. set
  391. {
  392. _SideDoor = value;
  393. _bSideDoorTrig.CLK = _SideDoor == LidState.Close;
  394. if (_bSideDoorTrig.T)
  395. {
  396. EV.PostAlarmLog(Module.ToString(), "EFEM Side door open");
  397. }
  398. if (_bSideDoorTrig.R)
  399. {
  400. EV.PostInfoLog(Module.ToString(), "EFEM Side door close");
  401. }
  402. }
  403. }
  404. private string CassetteDoorOpen = "CassetteDoorOpen";
  405. private string CassetteDoorClose = "CassetteDoorClose";
  406. // Constructor
  407. //
  408. public Efem()
  409. {
  410. Module = ModuleName.EfemRobot;
  411. _pm[0] = DEVICE.GetDevice<JetPM>(ModuleName.PMA.ToString());
  412. _pm[1] = DEVICE.GetDevice<JetPM>(ModuleName.PMB.ToString());
  413. _comm = new EfemComm();
  414. _LPMs[0] = new Loadport(ModuleName.LP1, this);
  415. _LPMs[1] = new Loadport(ModuleName.LP2, this);
  416. _msgHandler = new MessageHandler(this);
  417. _msgHandler.CommandUpdated += MsgOnCommandUpdated;
  418. _msgHandler.EventUpdated += MsgOnEventUpdated;
  419. _msgHandler.ErrorOccurred += MsgOnErrorOccurred;
  420. CarrierManager.Instance.SubscribeLocation(ModuleName.LP1.ToString(), 1);
  421. CarrierManager.Instance.SubscribeLocation(ModuleName.LP2.ToString(), 1);
  422. WaferManager.Instance.SubscribeLocation(ModuleName.EfemRobot, 2);
  423. WaferManager.Instance.SubscribeLocation(ModuleName.Aligner1, 1);
  424. WaferManager.Instance.SubscribeLocation(ModuleName.Aligner2, 1);
  425. WaferManager.Instance.SubscribeLocation(ModuleName.Cooling1, 1);
  426. WaferManager.Instance.SubscribeLocation(ModuleName.Cooling2, 1);
  427. WaferManager.Instance.SubscribeLocation(ModuleName.LP1, 25);
  428. WaferManager.Instance.SubscribeLocation(ModuleName.LP2, 25);
  429. DATA.Subscribe("EfemRobot.RobotMoveAction", () => _robotMoveAction);
  430. DATA.Subscribe("LP1.WaferSize", () => _LPMs[0].WaferSize.ToString());
  431. DATA.Subscribe("LP1.CassetteState", () => _LPMs[0].HasCassette ? LoadportCassetteState.Normal : LoadportCassetteState.Absent);
  432. DATA.Subscribe("LP1.CassettePresent", () => _LPMs[0].HasCassette ? 1 : 0);
  433. DATA.Subscribe("LP1.SlotMap", () => _LPMs[0].SlotMap);
  434. DATA.Subscribe("LP1.IsWaferProtrude", () => _LPMs[0].Protrusion ? 1 : 0);
  435. DATA.Subscribe("LP1.JobDone", () =>
  436. {
  437. return _LPMs[0].JobDone;
  438. });
  439. DATA.Subscribe("LP1.NotifyJobDone", () =>
  440. {
  441. if (!_LPMs[0].JobDone || !_LPMs[0].HasCassette)
  442. return false;
  443. if (SC.GetValue<int>("System.Job.BuzzerTimeWhenJobDone") >= 0
  444. && _LPMs[0].TimerNotifyJobDone.ElapsedMilliseconds > SC.GetValue<int>("System.Job.BuzzerTimeWhenJobDone") * 1000)
  445. return false;
  446. return _LPMs[0].JobDone;
  447. });
  448. DATA.Subscribe("LP2.WaferSize", () => _LPMs[1].WaferSize.ToString());
  449. DATA.Subscribe("LP2.CassetteState", () => _LPMs[1].HasCassette ? LoadportCassetteState.Normal : LoadportCassetteState.Absent);
  450. DATA.Subscribe("LP2.CassettePresent", () => _LPMs[1].HasCassette ? 1 : 0);
  451. DATA.Subscribe("LP2.SlotMap", () => _LPMs[1].SlotMap);
  452. DATA.Subscribe("LP2.IsWaferProtrude", () => _LPMs[1].Protrusion ? 1 : 0);
  453. DATA.Subscribe("LP2.JobDone", () =>
  454. {
  455. return _LPMs[1].JobDone;
  456. });
  457. DATA.Subscribe("LP2.NotifyJobDone", () =>
  458. {
  459. if (!_LPMs[1].JobDone || !_LPMs[1].HasCassette)
  460. return false;
  461. if (SC.GetValue<int>("System.Job.BuzzerTimeWhenJobDone") >= 0
  462. && _LPMs[1].TimerNotifyJobDone.ElapsedMilliseconds > SC.GetValue<int>("System.Job.BuzzerTimeWhenJobDone") * 1000)
  463. return false;
  464. return _LPMs[1].JobDone;
  465. });
  466. DATA.Subscribe("Aligner1.WaferSize", () => WaferManager.Instance.GetWafer(ModuleName.Aligner1, 0).Size.ToString());
  467. DATA.Subscribe("Aligner2.WaferSize", () => WaferManager.Instance.GetWafer(ModuleName.Aligner2, 0).Size.ToString());
  468. DATA.Subscribe("Cooling1.WaferSize", () => WaferManager.Instance.GetWafer(ModuleName.Cooling1, 0).Size.ToString());
  469. DATA.Subscribe("Cooling2.WaferSize", () => WaferManager.Instance.GetWafer(ModuleName.Cooling2, 0).Size.ToString());
  470. DATA.Subscribe("EfemRobot.WaferSize", () => WaferManager.Instance.GetWafer(ModuleName.EfemRobot, 0).Size.ToString());
  471. DATA.Subscribe("EFEM.CassetteDoor", () => CassetteDoor);
  472. DATA.Subscribe("EfemRobot.GripStateBlade1", () => GripStateBlade1);
  473. DATA.Subscribe("EfemRobot.GripStateBlade2", () => GripStateBlade2);
  474. GripStateBlade1 = "Unknown";
  475. GripStateBlade2 = "Unknown";
  476. _bCassetteDoorTrig.CLK = true;
  477. _bSideDoorTrig.CLK = true;
  478. EV.Subscribe(new EventItem("Event", CassetteDoorOpen, "Cassette Door Open"));
  479. EV.Subscribe(new EventItem("Event", CassetteDoorClose, "Cassette Door Close"));
  480. }
  481. // Methods
  482. //
  483. public bool HomeAll()
  484. {
  485. AddAction(new HomeAllAction(this, ModuleName.EFEM));
  486. AddAction(new OrgshAction(this, ModuleName.EFEM));
  487. return true;
  488. }
  489. public bool Home(ModuleName mod)
  490. {
  491. AddAction(new HomeModuleAction(this, mod));
  492. return true;
  493. }
  494. public bool ClearError()
  495. {
  496. AddAction(new ClearErrorAction(this));
  497. return true;
  498. }
  499. public void AbortRobot()
  500. {
  501. AddAction(new AbortAction(this));
  502. }
  503. public bool Pick(MoveParam mp)
  504. {
  505. if (!WaferManager.Instance.CheckWafer(mp.SrcModule, mp.SrcSlot, WaferStatus.Normal))
  506. {
  507. EV.PostAlarmLog("System", $"{mp.SrcModule} slot {mp.SrcSlot + 1} wafer is not normal");
  508. return false;
  509. }
  510. if (ModuleHelper.IsPm(mp.SrcModule))
  511. {
  512. JetPM pM = GetPM(mp.SrcModule);
  513. if (pM.IsSlitDoorClosed)
  514. {
  515. EV.PostAlarmLog(pM.Module.ToString(), "Slit 门必须打开");
  516. return false;
  517. }
  518. AddAction(new PinAction(mp.SrcModule, pM, MovementPosition.Up, false, mp.Arm, true));
  519. AddAction(new ExtendAction(this, new ExtendParam { Module = mp.SrcModule, Arm = mp.Arm, Pos = ExtendPos.GB }));
  520. _robotMoveAction = string.Format($"{mp.SrcModule}.Picking");
  521. AddAction(new PinAction(mp.SrcModule, pM, MovementPosition.Down, true, mp.Arm, true));
  522. AddAction(new ExtendAction(this, new ExtendParam { Module = mp.SrcModule, Arm = mp.Arm, Pos = ExtendPos.G4 }));
  523. }
  524. else
  525. {
  526. _robotMoveAction = string.Format($"{mp.SrcModule}.Picking");
  527. AddAction(new PickAction(this, mp));
  528. }
  529. return true;
  530. }
  531. public bool Place(MoveParam mp)
  532. {
  533. if (ModuleHelper.IsPm(mp.DestModule))
  534. {
  535. JetPM pM = GetPM(mp.DestModule);
  536. if (pM.IsSlitDoorClosed)
  537. {
  538. EV.PostAlarmLog(pM.Module.ToString(), "Slit 门必须打开");
  539. return false;
  540. }
  541. AddAction(new ExtendAction(this, new ExtendParam { Module = mp.DestModule, Arm = mp.Arm, Pos = ExtendPos.PB }));
  542. _robotMoveAction = string.Format($"{mp.DestModule}.Placing");
  543. AddAction(new PinAction(mp.DestModule, pM, MovementPosition.Up, true, mp.Arm, false));
  544. AddAction(new ExtendAction(this, new ExtendParam { Module = mp.DestModule, Arm = mp.Arm, Pos = ExtendPos.P4 }));
  545. AddAction(new PinAction(mp.DestModule, pM, MovementPosition.Down, false, mp.Arm, false));
  546. }
  547. else
  548. {
  549. _robotMoveAction = string.Format($"{mp.DestModule}.Placing");
  550. AddAction(new PlaceAction(this, mp));
  551. }
  552. return true;
  553. }
  554. public void PickAndPlace(MoveParam pickParam, MoveParam placeParam)
  555. {
  556. if (!WaferManager.Instance.CheckWafer(pickParam.SrcModule, pickParam.SrcSlot, WaferStatus.Normal))
  557. {
  558. EV.PostAlarmLog("System", $"{pickParam.SrcModule} slot {pickParam.SrcSlot + 1} wafer is not normal");
  559. return;
  560. }
  561. if (ModuleHelper.IsPm(pickParam.SrcModule))
  562. {
  563. JetPM pM = GetPM(pickParam.SrcModule);
  564. if (pM.IsSlitDoorClosed)
  565. {
  566. EV.PostAlarmLog(pM.Module.ToString(), "Slit 门必须打开");
  567. return;
  568. }
  569. AddAction(new PinAction(pickParam.SrcModule, pM, MovementPosition.Up, false, pickParam.Arm, true));
  570. AddAction(new ExtendAction(this, new ExtendParam { Module = pickParam.SrcModule, Arm = pickParam.Arm, Pos = ExtendPos.GB }));
  571. _robotMoveAction = string.Format($"{pickParam.SrcModule}.Picking");
  572. AddAction(new PinAction(pickParam.SrcModule, pM, MovementPosition.Down, true, pickParam.Arm, true));
  573. AddAction(new ExtendAction(this, new ExtendParam { Module = pickParam.SrcModule, Arm = pickParam.Arm, Pos = ExtendPos.G4 }));
  574. AddAction(new ExtendAction(this, new ExtendParam { Module = placeParam.DestModule, Arm = placeParam.Arm, Pos = ExtendPos.PB }));
  575. _robotMoveAction = string.Format($"{placeParam.DestModule}.Placing");
  576. AddAction(new PinAction(placeParam.DestModule, pM, MovementPosition.Up, true, placeParam.Arm,false));
  577. AddAction(new ExtendAction(this, new ExtendParam { Module = placeParam.DestModule, Arm = placeParam.Arm, Pos = ExtendPos.P4 }));
  578. AddAction(new PinAction(placeParam.DestModule, pM, MovementPosition.Down, false, placeParam.Arm, false));
  579. }
  580. else
  581. {
  582. _robotMoveAction = string.Format($"{pickParam.SrcModule}.Picking");
  583. AddAction(new PickAction(this, pickParam));
  584. _robotMoveAction = string.Format($"{placeParam.DestModule}.Placing");
  585. AddAction(new PlaceAction(this, placeParam));
  586. }
  587. }
  588. public bool Extend(ExtendParam ep)
  589. {
  590. AddAction(new ExtendAction(this, ep));
  591. return true;
  592. }
  593. public void Goto(MoveParam ep)
  594. {
  595. //_robotMoveAction = string.Format($"{ep.SrcModule}.Goto");
  596. AddAction(new GotoAction(this, ep));
  597. }
  598. public bool Retract(ExtendParam ep)
  599. {
  600. AddAction(new ExtendAction(this, ep));
  601. return true;
  602. }
  603. public bool Map(ModuleName mod)
  604. {
  605. if (_LPMs[mod - ModuleName.LP1].Protrusion)
  606. {
  607. EV.PostAlarmLog(mod.ToString(), $"{mod} wafer protrusion, can not do Map");
  608. return false;
  609. }
  610. _LPMs[mod - ModuleName.LP1].Map();
  611. return true;
  612. }
  613. public bool Grip(Hand blade, bool isGrip)
  614. {
  615. AddAction(new GripAction(this, blade, isGrip));
  616. return true;
  617. }
  618. public bool SetPinUp(ModuleName mod)
  619. {
  620. AddAction(new LiftAction(this, mod));
  621. return true;
  622. }
  623. public bool Align(ModuleName mod, float delayTime, WaferSize size)
  624. {
  625. AddAction(new AlignAction(this, mod, size));
  626. return true;
  627. }
  628. public bool SetLamp(LightType light, LightStatus status)
  629. {
  630. AddAction(new LedAction(this, light, status));
  631. return true;
  632. }
  633. public void TurnOffBuzzer()
  634. {
  635. AddAction(new LedAction(this, LightType.BUZZER1, LightStatus.OFF));
  636. }
  637. //public void SwitchOnBuzzerAndRed()
  638. //{
  639. // AddAction(new LedAction(this, LightType.RED, LightStatus.ON));
  640. // AddAction(new LedAction(this, LightType.YELLOW, LightStatus.OFF));
  641. // AddAction(new LedAction(this, LightType.GREEN, LightStatus.OFF));
  642. // AddAction(new LedAction(this, LightType.BUZZER1, LightStatus.ON));
  643. //}
  644. public override void ReceiveMessage(string sRec)
  645. {
  646. _msgHandler.ReceiveMessage(sRec);
  647. }
  648. public override void SetOnline(ModuleName mod, bool online)
  649. {
  650. this[mod].SetOnline(online);
  651. }
  652. public override void SetBusy(ModuleName mod, bool busy)
  653. {
  654. this[mod].Status = DeviceState.Busy;
  655. }
  656. //--------------------------------Constructor------------------------------------
  657. //
  658. private JetPM GetPM(ModuleName mod)
  659. {
  660. if (!ModuleHelper.IsPm(mod))
  661. throw new ArgumentException("Module argument error");
  662. return _pm[mod - ModuleName.PMA];
  663. }
  664. //----------------------------------Private Method-------------------------------
  665. //
  666. private void MsgOnEventUpdated(object sender, EventArgs e)
  667. {
  668. if (!(e is EfemEventArgs))
  669. return;
  670. EfemEventArgs eArg = e as EfemEventArgs;
  671. switch (eArg.CommandType)
  672. {
  673. case EfemOperation.SigStatus:
  674. // EVT:SIGSTAT/Parameter/DATA1/DATA2;
  675. string sParam = eArg.DataList[0]; // "SYSTEM" or "Pn"
  676. // DATA1 & DATA2
  677. int nData1 = Convert.ToInt32(eArg.DataList[1], 16);
  678. int nData2 = Convert.ToInt32(eArg.DataList[2], 16);
  679. BitArray baData1 = new BitArray(new int[] { nData1 });
  680. BitArray baData2 = new BitArray(new int[] { nData2 });
  681. if (0 == string.Compare(sParam, Constant.SYS, true))
  682. {
  683. // EVT:SIGSTAT/System/00000000/00000004;
  684. // DATA1
  685. _bSysVacPressure1.CLK = baData1[0]; // bit 0
  686. _bIonizerCompressedAir.CLK = baData1[1]; // bit 1
  687. _bSysCompressedAirPressure.CLK = baData1[2]; // bit 2
  688. _bFlowGaugeSensor.CLK = baData1[4]; // bit 4
  689. _bLeakageSensor.CLK = baData1[5]; // bit 5
  690. this.DoorSwitch = baData1[6] ? LidState.Close : LidState.Open; // bit 6
  691. //bDrivePower = baData1[7]; // bit 7
  692. _bDiffPressureSensorSetting1.CLK = baData1[8]; // bit 8
  693. _bDiffPressureSensorSetting2.CLK = baData1[9]; // bit 9
  694. _bIonizerAlarm.CLK = baData1[10]; // bit 10
  695. _bFFuAlarm.CLK = baData1[11]; // bit 11
  696. _bAreaSensor.CLK = baData1[12]; // bit 12
  697. _bModeSwitch.CLK = baData1[13]; // bit 13
  698. this.CassetteDoor = baData1[15] ? LidState.Close : LidState.Open; // bit 15
  699. // Post warning and alarm
  700. if (!baData1[0]) // Bit[0] ON=Normal, OFF=Abnormal
  701. {
  702. EV.PostAlarmLog(Module.ToString(), "EFEM System vacuum source pressure low");
  703. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
  704. }
  705. if (!baData1[1]) // Bit[1] ON=Normal, OFF=Abnormal
  706. {
  707. EV.PostAlarmLog(Module.ToString(), "EFEM Ionizer compressed air error");
  708. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
  709. }
  710. if (!baData1[2]) // Bit[2] ON=Normal, OFF=Abnormal
  711. {
  712. EV.PostAlarmLog(Module.ToString(), "EFEM System compressed air pressure low");
  713. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
  714. }
  715. if (!baData1[4]) // Bit[4] ON=Normal, OFF=Abnormal
  716. {
  717. EV.PostAlarmLog(Module.ToString(), "EFEM Flow gauge sensor error");
  718. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
  719. }
  720. if (!baData1[5]) // Bit[5] ON=Normal, OFF=Abnormal
  721. {
  722. EV.PostAlarmLog(Module.ToString(), "EFEM Leakage alarm");
  723. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
  724. }
  725. if (!baData1[10]) // Bit[10] ON=Normal, OFF=Abnormal
  726. {
  727. EV.PostAlarmLog(Module.ToString(), "EFEM Ionizer alarm");
  728. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
  729. }
  730. if (!baData1[11]) // Bit[11] ON=Normal, OFF=Abnormal
  731. {
  732. EV.PostAlarmLog(Module.ToString(), "FFU alarm");
  733. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
  734. }
  735. if (!baData1[13]) // Bit[13] ON=RUN, OFF=Maintain
  736. {
  737. EV.PostAlarmLog(Module.ToString(), "EFEM switch to Maintain mode, HomeAll to recover");
  738. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.ToInit);
  739. }
  740. // DATA2
  741. _signalT.ChangeLightStatus(LightType.RED, baData2[0] ? LightStatus.ON : baData2[5] ? LightStatus.BLINK : LightStatus.OFF);
  742. _signalT.ChangeLightStatus(LightType.GREEN, baData2[1] ? LightStatus.ON : baData2[6] ? LightStatus.BLINK : LightStatus.OFF);
  743. _signalT.ChangeLightStatus(LightType.YELLOW, baData2[2] ? LightStatus.ON : baData2[7] ? LightStatus.BLINK : LightStatus.OFF);
  744. _signalT.ChangeLightStatus(LightType.BLUE, baData2[3] ? LightStatus.ON : baData2[8] ? LightStatus.BLINK : LightStatus.OFF);
  745. _signalT.ChangeLightStatus(LightType.WHITE, baData2[4] ? LightStatus.ON : baData2[9] ? LightStatus.BLINK : LightStatus.OFF);
  746. _signalT.ChangeLightStatus(LightType.BUZZER1, baData2[10] ? LightStatus.ON : LightStatus.OFF);
  747. /* EFEM 程序中目前没有实现
  748. _RobotErr.CLK = baData2[27]; // bit 27
  749. bool bArmNotExtendLLA = baData2[30]; // bit 30
  750. bool bArmNotExtendLLB = baData2[31]; // bit 31
  751. */
  752. } // system event
  753. else
  754. {
  755. _LPMs[eArg.Module - ModuleName.LP1].HandleEvent(eArg);
  756. } // FOUP EVENT
  757. break;
  758. case EfemOperation.GetWaferInfo:
  759. _LPMs[eArg.Module - ModuleName.LP1].HandleEvent(eArg);
  760. break;
  761. default:
  762. break;
  763. }
  764. }
  765. private void MsgOnCommandUpdated(object sender, EventArgs e)
  766. {
  767. EfemActionArgs arg = e as EfemActionArgs;
  768. if (arg == null) throw new ArgumentNullException("Argument is Null");
  769. if (arg.CommandType == EfemOperation.Ready)
  770. {
  771. this.CommunicationConnected = true;
  772. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.CommReady);
  773. return;
  774. }
  775. EfemActionBase action = null;
  776. lock (_lockerAction)
  777. {
  778. foreach (var item in _actions)
  779. {
  780. if (item is EfemActionBase a1)
  781. {
  782. if (a1.Type == arg.CommandType && item.Status != ActionStatus.Completed)
  783. {
  784. action = a1;
  785. break;
  786. }
  787. }
  788. }
  789. if (action == null)
  790. {
  791. //EV.PostAlarmLog(arg.Module.ToString(), $"NO activated {arg.CommandType} in the queue");
  792. LOG.Write($"NO activated [{arg.ID}] [{arg.CommandType}] in the queue");
  793. return;
  794. }
  795. // 更新 action 状态
  796. action.Status = arg.Status;
  797. if (arg.Status == ActionStatus.Completed)
  798. {
  799. ModuleName mod = action.Module;
  800. // Map 命令比较特别, module 是LPX但是用robot做mapping
  801. if (mod == ModuleName.EFEM || mod == ModuleName.EfemRobot || ModuleHelper.IsAligner(mod) || ModuleHelper.IsCooling(mod) || arg.CommandType == EfemOperation.Map)
  802. {
  803. if (action.Type != EfemOperation.Light)
  804. {
  805. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.ActionDone, arg.CommandType);
  806. }
  807. }
  808. else if (ModuleHelper.IsLoadPort(mod))
  809. {
  810. Singleton<RouteManager>.Instance.EFEM.NotifyLP(mod, LoadportEntity.MSG.ActionDone);
  811. }
  812. _robotMoveAction = string.Format($"System.None");
  813. action.OnPostWork(arg.Data);
  814. LOG.Write($"efem action [{action.GetType().Name}] [{action.ID}][{action.Type}] removed from queue");
  815. _actions.Remove(action);
  816. }
  817. }
  818. }
  819. private void MsgOnErrorOccurred(object sender, EventArgs e)
  820. {
  821. if (e is EfemErrorArgs errArg)
  822. {
  823. this.Status = DeviceState.Error;
  824. lock (_lockerAction)
  825. {
  826. if (this._actions.Count > 0)
  827. {
  828. LOG.Write($"error occur, remove {_actions.Last.Value.ID} from queue");
  829. this._actions.RemoveLast();
  830. }
  831. }
  832. EV.PostAlarmLog(Module.ToString(), $"{errArg.Description}, [{errArg.Message}], [{errArg.Factor}]");
  833. }
  834. }
  835. }
  836. /// <summary>
  837. /// Load port object class
  838. /// </summary>
  839. sealed class Loadport : ILoadport
  840. {
  841. private readonly EfemBase _efem;
  842. //---------------------------------Properties------------------------------------
  843. //
  844. public OnlineFlag OnlineFlag { get; set; }
  845. public ModuleName Module { get; set; }
  846. public DeviceState Status { get; set; }
  847. public WaferSize WaferSize { get; set; }
  848. public WaferStatus[] WaferInfo { get; set; }
  849. public bool HasCassette { get; set; }
  850. public bool Protrusion { get; set; }
  851. public bool IsMapped { get; set; }
  852. public bool JobDone { get; set; }
  853. public Stopwatch TimerNotifyJobDone { get; set; }
  854. private string[] _slotMap = new string[25];
  855. public string SlotMap
  856. {
  857. get
  858. {
  859. for (int i = 0; i < 25; i++)
  860. {
  861. _slotMap[i] = ((int)WaferManager.Instance.GetWafer(Module, i).Status).ToString();
  862. }
  863. return string.Join("", _slotMap);
  864. }
  865. }
  866. private string Port1CassetteArrive = "Port1CassetteArrive";
  867. private string Port1CassetteRemoved = "Port1CassetteRemoved";
  868. private string Port1MappingComplete = "Port1MappingComplete";
  869. private string Port1MappingFailed = "Port1MappingFailed";
  870. private string Port2CassetteArrive = "Port2CassetteArrive";
  871. private string Port2CassetteRemoved = "Port2CassetteRemoved";
  872. private string Port2MappingComplete = "Port2MappingComplete";
  873. private string Port2MappingFailed = "Port2MappingFailed";
  874. // Constructor
  875. //
  876. public Loadport(ModuleName mod, EfemBase efem)
  877. {
  878. Module = mod;
  879. _efem = efem;
  880. TimerNotifyJobDone = new Stopwatch();
  881. EV.Subscribe(new EventItem("Event", Port1CassetteArrive, "Port1CassetteArrive"));
  882. EV.Subscribe(new EventItem("Event", Port1CassetteRemoved, "Port1CassetteRemoved"));
  883. EV.Subscribe(new EventItem("Event", Port1MappingComplete, "Port1MappingComplete"));
  884. EV.Subscribe(new EventItem("Event", Port1MappingFailed, "Port1MappingFailed"));
  885. EV.Subscribe(new EventItem("Event", Port2CassetteArrive, "Port2CassetteArrive"));
  886. EV.Subscribe(new EventItem("Event", Port2CassetteRemoved, "Port2CassetteRemoved"));
  887. EV.Subscribe(new EventItem("Event", Port2MappingComplete, "Port2MappingComplete"));
  888. EV.Subscribe(new EventItem("Event", Port2MappingFailed, "Port2MappingFailed"));
  889. }
  890. // Methods
  891. //
  892. public void Home()
  893. {
  894. _efem.AddAction(new HomeAllAction(_efem, Module));
  895. }
  896. public void NoteJobStart()
  897. {
  898. JobDone = false;
  899. }
  900. public void NoteJobComplete()
  901. {
  902. TimerNotifyJobDone.Restart();
  903. JobDone = true;
  904. }
  905. public void Map()
  906. {
  907. _efem.AddAction(new MapAction(_efem, Module));
  908. }
  909. public void HandleEvent(EfemEventArgs eArg)
  910. {
  911. switch (eArg.CommandType)
  912. {
  913. case EfemOperation.GetWaferInfo:
  914. string sWaferInfo = eArg.DataList[0];
  915. bool resultNormal = true;
  916. for (byte index = 0; index < sWaferInfo.Length; index++)
  917. {
  918. int waferState = int.Parse(sWaferInfo.Substring(index, 1));
  919. //合理的映射到内部支持的叠片/交叉片
  920. if (waferState >= 7) waferState = 7;
  921. else if (waferState >= 2) waferState = 3;
  922. WaferStatus st = (WaferStatus)waferState;
  923. WaferManager.Instance.UpdateWaferSize(this.Module, index, WaferSize);
  924. if (st != WaferStatus.Empty)
  925. {
  926. WaferManager.Instance.CreateWafer(this.Module, index, st);
  927. if (st == WaferStatus.Normal)
  928. {
  929. EV.PostInfoLog(this.Module.ToString(), $"Found Wafer on Slot {index + 1} {WaferSize}");
  930. }
  931. else
  932. {
  933. resultNormal = false;
  934. EV.PostWarningLog(this.Module.ToString(), $"Found {st} Wafer on Slot {index + 1} {WaferSize}");
  935. }
  936. }
  937. }
  938. var dvidMap = new SerializableDictionary<string, string>();
  939. dvidMap[DVIDName.SlotMap] = sWaferInfo;
  940. dvidMap[DVIDName.PortID] = Module == ModuleName.LP1 ? "1" : "2";
  941. if (resultNormal)
  942. {
  943. EV.Notify(Module == ModuleName.LP1 ? Port1MappingComplete : Port2MappingComplete, dvidMap);
  944. }
  945. else
  946. {
  947. EV.Notify(Module == ModuleName.LP1 ? Port1MappingFailed : Port2MappingFailed, dvidMap);
  948. }
  949. this.IsMapped = true;
  950. break;
  951. case EfemOperation.SigStatus:
  952. // EVT: SIGSTAT/P2/00000381/00000000;
  953. string sParam = eArg.DataList[0];
  954. ModuleName mod = sParam.ToModule();
  955. if (!ModuleHelper.IsLoadPort(mod))
  956. return;
  957. // DATA1 & DATA2
  958. int nData1 = Convert.ToInt32(eArg.DataList[1], 16);
  959. int nData2 = Convert.ToInt32(eArg.DataList[2], 16);
  960. BitArray baData1 = new BitArray(new int[] { nData1 });
  961. BitArray baData2 = new BitArray(new int[] { nData2 });
  962. // wafer size
  963. this.WaferSize = !baData1[6] ? WaferSize.WS3 :
  964. !baData1[7] ? WaferSize.WS4 :
  965. !baData1[8] ? WaferSize.WS6 : WaferSize.WS0;
  966. // placement & present
  967. bool bPlacement = baData1[0]; // bit 0
  968. bool bPresence = !baData1[1]; // bit 1
  969. bool bArrived = bPlacement && bPresence;
  970. if (HasCassette)
  971. {
  972. if (!bArrived)
  973. {
  974. this.HasCassette = false;
  975. this.IsMapped = false;
  976. EV.PostInfoLog(mod.ToString(), "Cassette removed");
  977. OP.DoOperation("System.CassetteLeave"); //For unload light control off afer job done
  978. CarrierManager.Instance.DeleteCarrier(Module.ToString());
  979. WaferManager.Instance.DeleteWafer(this.Module, 0, 25);
  980. SerializableDictionary<string, string> dvid = new SerializableDictionary<string, string>();
  981. dvid["PortID"] = mod == ModuleName.LP1 ? "1" : "2";
  982. EV.Notify(mod == ModuleName.LP1 ? Port1CassetteRemoved : Port2CassetteRemoved, dvid);
  983. JobDone = false;
  984. }
  985. }
  986. else
  987. {
  988. if (bArrived)
  989. {
  990. this.HasCassette = true;
  991. CarrierManager.Instance.CreateCarrier(Module.ToString());
  992. EV.PostInfoLog(mod.ToString(), $"Cassette {WaferSize} arrived");
  993. var dvid1 = new SerializableDictionary<string, string>();
  994. dvid1["PortID"] = mod == ModuleName.LP1 ? "1" : "2";
  995. EV.Notify(mod == ModuleName.LP1 ? Port1CassetteArrive : Port2CassetteArrive, dvid1);
  996. JobDone = false;
  997. }
  998. }
  999. this.Protrusion = !baData1[9];
  1000. if (Protrusion)
  1001. {
  1002. EV.PostAlarmLog(Module.ToString(), "发现 wafer 突出");
  1003. Singleton<RouteManager>.Instance.EFEM.PostMsg(EfemEntity.MSG.Error);
  1004. }
  1005. // DATA2, loadport上面的LED 灯, 暂时不需要用到
  1006. break;
  1007. default:
  1008. break;
  1009. }
  1010. }
  1011. public void SetOnline(bool online)
  1012. {
  1013. OnlineFlag = online ? OnlineFlag.Online : OnlineFlag.Offline;
  1014. }
  1015. }
  1016. sealed class SignalTower
  1017. {
  1018. // Fields
  1019. //
  1020. private readonly Dictionary<LightType, LightStatus> _lights = new Dictionary<LightType, LightStatus>(5);
  1021. public SignalTower()
  1022. {
  1023. _lights.Add(LightType.RED, LightStatus.OFF);
  1024. _lights.Add(LightType.YELLOW, LightStatus.OFF);
  1025. _lights.Add(LightType.BLUE, LightStatus.OFF);
  1026. _lights.Add(LightType.GREEN, LightStatus.OFF);
  1027. _lights.Add(LightType.WHITE, LightStatus.OFF);
  1028. _lights.Add(LightType.BUZZER1, LightStatus.OFF);
  1029. DATA.Subscribe($"{ModuleName.EFEM}.SignalTower", () =>
  1030. {
  1031. return new AITSignalTowerData
  1032. {
  1033. IsGreenLightOn = _lights[LightType.GREEN] == LightStatus.ON,
  1034. IsRedLightOn = _lights[LightType.RED] == LightStatus.ON,
  1035. IsYellowLightOn = _lights[LightType.YELLOW] == LightStatus.ON,
  1036. IsWhiteLightOn = _lights[LightType.WHITE] == LightStatus.ON,
  1037. IsBlueLightOn = _lights[LightType.BLUE] == LightStatus.ON,
  1038. IsBuzzerOn = _lights[LightType.BUZZER1] == LightStatus.ON,
  1039. };
  1040. });
  1041. }
  1042. // Methods
  1043. //
  1044. public void ChangeLightStatus(LightType light, LightStatus st)
  1045. {
  1046. if (!_lights.ContainsKey(light))
  1047. throw new ApplicationException($"NO {light} configured");
  1048. _lights[light] = st;
  1049. }
  1050. }
  1051. }