FaHost.cs 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading.Tasks;
  4. using System.Xml;
  5. using Aitex.Common.Util;
  6. using Aitex.Core.Account;
  7. using Aitex.Core.RT.Event;
  8. using Aitex.Core.RT.Log;
  9. using Aitex.Core.RT.RecipeCenter;
  10. using Aitex.Core.RT.SCCore;
  11. using Aitex.Core.Util;
  12. using Aitex.Triton160.RT.Module;
  13. using FabConnect.SecsGemInterface.Common;
  14. using FabConnect.SecsGemInterface.Common.ToolModel;
  15. using FabConnect.SecsGemInterface.GemModel;
  16. namespace Aitex.RT.FactoryAutomation
  17. {
  18. public class FaHost : IFaHost
  19. {
  20. public string FaCommunicationState
  21. {
  22. get { return _gem.CommunicationState.ToString(); }
  23. }
  24. public string FaControlState
  25. {
  26. get { return _gem.ControlState.ToString(); }
  27. }
  28. public string FaControlSubState
  29. {
  30. get
  31. {
  32. return _gem.ControlRemoteSwitch.ToString();
  33. }
  34. }
  35. public bool IsConnected
  36. {
  37. get { return _gem.CommunicationState == CommunicationState.EnabledCommunicating; }
  38. }
  39. public int SpoolingState
  40. {
  41. get
  42. {
  43. return (int)_gem.SpoolingState;
  44. }
  45. }
  46. public string SpoolingActual
  47. {
  48. get
  49. {
  50. return
  51. _gem.GetAttribute(GEMVariables.SpoolCountActual, AttributeType.SV)
  52. ;
  53. }
  54. }
  55. public string SpoolingTotal
  56. {
  57. get { return _gem.GetAttribute(GEMVariables.SpoolCountTotal, AttributeType.SV); }
  58. }
  59. public string SpoolingFullTime
  60. {
  61. get { return _gem.GetAttribute(GEMVariables.SpoolFullTime, AttributeType.SV); }
  62. }
  63. public string SpoolingStartTime
  64. {
  65. get { return _gem.GetAttribute(GEMVariables.SpoolStartTime, AttributeType.SV); }
  66. }
  67. public bool IsSpoolingEnable
  68. {
  69. get { return Convert.ToBoolean(_gem.GetAttribute(GEMVariables.SpoolEnabled, AttributeType.EC)); }
  70. }
  71. private readonly GEMController _gem = new GEMController();
  72. public IHostCallback _equipment;
  73. private HashSet<string> _systemBuildInEc = new HashSet<string>();
  74. private HashSet<string> _systemBuildInVariables = new HashSet<string>();
  75. private PeriodicJob _faMonitorThread;
  76. private FixSizeQueue<FaEventItem> _lstEvent = new FixSizeQueue<FaEventItem>(300);
  77. FALogFileCleaner _logCleaner = new FALogFileCleaner();
  78. private ControlState _state = ControlState.Unknown;
  79. private const string EventTerminalMessage = "TerminalMessage";
  80. public void Initialize(IHostCallback equipment, string modelFile)
  81. {
  82. _equipment = equipment;
  83. _gem.CommunicationStateChanged += OnCommunicationStateChanged;
  84. _gem.RemoteCommandS2F49In += _gem_RemoteCommandS2F49In; ;
  85. _gem.PrimaryMessageIn += _gem_PrimaryMessageIn;
  86. _gem.ControlStateChanged += _gem_ControlStateChanged;
  87. _gem.ShowTrialMessageBox = false;
  88. _gem.AutoPPDataReply = false;
  89. _gem.Initialize(modelFile, PathManager.GetLogDir());
  90. _gem.EquipmentModel.GemConnection.HSMS.localIPAddress = SC.GetSCString("System_FaLocalIPAddress").Value;
  91. _gem.ReInitialize();
  92. //get system build in ec
  93. _systemBuildInEc = new HashSet<string>();
  94. _systemBuildInEc.Add("EstablishCommunicationsTimeout");
  95. _systemBuildInEc.Add("MaxSpoolTransmit");
  96. _systemBuildInEc.Add("OverWriteSpool");
  97. _systemBuildInEc.Add("MaxSpoolCapacity");
  98. _systemBuildInEc.Add("SpoolEnabled");
  99. _systemBuildInEc.Add("TimeFormat");
  100. //initial system build in variable
  101. _systemBuildInVariables.Add("AlarmsEnabled");
  102. _systemBuildInVariables.Add("AlarmsSet");
  103. _systemBuildInVariables.Add("Clock");
  104. _systemBuildInVariables.Add("ControlState");
  105. _systemBuildInVariables.Add("EventsEnabled");
  106. _systemBuildInVariables.Add("PPExecName");
  107. _systemBuildInVariables.Add("PreviousProcessState");
  108. _systemBuildInVariables.Add("ProcessState");
  109. _systemBuildInVariables.Add("SpoolCountActual");
  110. _systemBuildInVariables.Add("SpoolCountTotal");
  111. _systemBuildInVariables.Add("SpoolFullTime");
  112. _systemBuildInVariables.Add("SpoolStartTime");
  113. _systemBuildInVariables.Add("SpoolState");
  114. _systemBuildInVariables.Add("SpoolSubstate");
  115. _logCleaner.Run();
  116. _faMonitorThread = new PeriodicJob(200, MonitorFaTask, "Monitor FA Thread", true);
  117. EV.Subscribe(new EventItem("Host", EventTerminalMessage, "{0}", EventLevel.Warning, EventType.EventUI_Notify));
  118. }
  119. private void _gem_ControlStateChanged(object sender, SECsEventArgs e)
  120. {
  121. if (_state != _gem.ControlState)
  122. {
  123. _state = _gem.ControlState;
  124. if (_state == ControlState.OnlineRemote)
  125. {
  126. EV.PostInfoLog("FA", Aitex.RT.Properties.Resources.HostControlModeChangeTo_stateNotifySystemChangeToAutoMode);
  127. Singleton<PMEntity>.Instance.PostMsg((int)PMEntity.MSG.SetAutoMode);
  128. }
  129. }
  130. }
  131. public void Invoke(string method, object[] args)
  132. {
  133. switch (method)
  134. {
  135. case "FAEnable":
  136. _gem.SetEnable();
  137. break;
  138. case "FADisable":
  139. _gem.SetDisable();
  140. break;
  141. case "FAOnline":
  142. _gem.SetOnline();
  143. break;
  144. case "FAOffline":
  145. _gem.SetOffline();
  146. break;
  147. case "FALocal":
  148. _gem.SetLocal();
  149. break;
  150. case "FARemote":
  151. _gem.SetRemote();
  152. break;
  153. case "FAEnableSpooling":
  154. SetEnableSpooling();
  155. break;
  156. case "FADisableSpooling":
  157. SetDisableSpooling();
  158. break;
  159. }
  160. }
  161. private bool _gem_RemoteCommandS2F41In(SECsTransaction trans)
  162. {
  163. try
  164. {
  165. bool ret = true;
  166. string reason = string.Empty;
  167. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(2, 42, false);
  168. reply.DataItem.AddList();
  169. if (ret)
  170. {
  171. reply.DataItem[0].Add("HCACK", 0, SECsFormat.Binary);
  172. }
  173. _gem.SendReply(reply, trans.Id);
  174. }
  175. catch (Exception ex)
  176. {
  177. LOG.Write(string.Format("Handle_S2F41 Exception: {0}", ex.Message));
  178. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(2, 42, false);
  179. reply.DataItem.AddList();
  180. reply.DataItem[0].Add("HCACK", 3/*At least one parameter is invalid*/, SECsFormat.Binary);
  181. reply.DataItem[0].AddList();
  182. reply.DataItem[0][1].AddList();
  183. reply.DataItem[0][1].Add("CPVALUE", ex.Message, SECsFormat.Ascii);
  184. _gem.SendReply(reply, trans.Id);
  185. }
  186. return true;
  187. }
  188. private bool _gem_RemoteCommandS2F49In(SECsTransaction trans)
  189. {
  190. try
  191. {
  192. bool ret = true;
  193. string reason = string.Empty;
  194. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(2, 50, false);
  195. string remoteCommandName = trans.Primary.DataItem[0][2].ToString();
  196. switch (remoteCommandName.ToUpper())
  197. {
  198. case "GOREMOTE":
  199. break;
  200. case "PP-SELECT":
  201. {
  202. if (trans.Primary.DataItem[0][3][0][0].ToString() != "RecipeId" ||
  203. trans.Primary.DataItem[0][3][1][0].ToString() != "LotId" )
  204. throw new Exception("PP-SELECT Command Format Not Correct");
  205. string recipeName = trans.Primary.DataItem[0][3][0][1].ToString();
  206. string lotId = trans.Primary.DataItem[0][3][1][1].ToString();
  207. string jobId = "";
  208. if (trans.Primary.DataItem[0][3][2][0].ToString() == "JobId")
  209. {
  210. jobId = trans.Primary.DataItem[0][3][2][1].ToString();
  211. }
  212. ret = _equipment.RunRecipe(lotId, jobId, recipeName, out reason);
  213. }
  214. break;
  215. }
  216. reply.DataItem.AddList();
  217. if (ret)
  218. {
  219. reply.DataItem[0].Add("HCACK", 0, SECsFormat.Binary);
  220. }
  221. else
  222. {
  223. reply.DataItem[0].Add("HCACK", 3, SECsFormat.Binary);
  224. reply.DataItem[0].Add("CPVALUE", reason, SECsFormat.Ascii);
  225. }
  226. _gem.SendReply(reply, trans.Id);
  227. }
  228. catch (Exception ex)
  229. {
  230. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(2, 50, false);
  231. reply.DataItem.AddList();
  232. reply.DataItem[0].Add("HCACK", 3/*At least one parameter is invalid*/, SECsFormat.Binary);
  233. reply.DataItem[0].AddList();
  234. reply.DataItem[0][1].AddList();
  235. reply.DataItem[0][1].Add("CPVALUE", ex.Message, SECsFormat.Ascii);
  236. _gem.SendReply(reply, trans.Id);
  237. }
  238. return true;
  239. }
  240. private void _gem_PrimaryMessageIn(object sender, SECsPrimaryInEventArgs e)
  241. {
  242. string SF = "S" + e.Inputs.Stream.ToString() + "F" + e.Inputs.Function.ToString();
  243. switch (SF)
  244. {
  245. case "S7F1":
  246. Handle_S7F1(e);
  247. break;
  248. case "S7F5":
  249. Handle_S7F5(e);
  250. break;
  251. case "S7F3"://down load recipe
  252. Handle_S7F3(e); //Host must send S7F1/F2 and equipment application must either grant the host requests.
  253. break;
  254. case "S7F17":
  255. Handle_S7F17(e);
  256. break;
  257. case "S7F19":
  258. Handle_S7F19(e);
  259. break;
  260. case "S7F25":
  261. Handle_S7F25(e);
  262. break;
  263. case "S10F3"://Single terminal message
  264. Handle_S10F3(e);
  265. break;
  266. case "S10F5"://Multiple terminal message
  267. Handle_S10F5(e);
  268. break;
  269. }
  270. switch (e.EventId)
  271. {
  272. case PrimaryEventType.ProcessProgramLoadInquire: //S7F1
  273. break;
  274. }
  275. }
  276. /// <summary>
  277. /// Host requests the equipment to delete the Process Program
  278. /// L,n (Number of process programs to be deleted)
  279. /// 1. <PPID1>
  280. /// .
  281. /// .
  282. /// n. <PPIDn>
  283. /// Exception: If n=0, then delete all.
  284. /// </summary>
  285. /// <param name="e"></param>
  286. private void Handle_S7F17(SECsPrimaryInEventArgs e)
  287. {
  288. try
  289. {
  290. string reason = string.Empty;
  291. if (e.Inputs.DataItem[0].Count == 0)
  292. {
  293. LOG.Write("Handle_S7F17, delete all recipes");
  294. DeleteAllRecipes(out reason);
  295. }
  296. else // Delete the list of selected Process Program
  297. {
  298. List<string> deleteRecipes = new List<string>();
  299. for (int i = 0; i < e.Inputs.DataItem[0].Count; i++)
  300. {
  301. string ppid = e.Inputs.DataItem[0][i].ToString();
  302. deleteRecipes.Add(ppid);
  303. LOG.Write("Handle_S7F17, delete recipe:" + ppid);
  304. }
  305. DeleteRecipe(deleteRecipes, out reason);
  306. }
  307. //give reply to host
  308. SECsMessage messageToReply = _gem.Services.ProcessProgram.DeleteProcessProgramAcknowledge(0);
  309. _gem.SendReply(messageToReply, e.TransactionID);
  310. }
  311. catch (Exception ex)
  312. {
  313. LOG.Write("Handle_S7F17 Exception: " + ex.Message);
  314. //give reply to host
  315. SECsMessage messageToReply = _gem.Services.ProcessProgram.DeleteProcessProgramAcknowledge(4/*error*/);
  316. _gem.SendReply(messageToReply, e.TransactionID);
  317. }
  318. }
  319. protected void DeleteAllRecipes(out string reason)
  320. {
  321. reason = string.Empty;
  322. var recipes = RecipeFileManager.Instance.GetSequenceNameList();
  323. foreach (var name in recipes)
  324. {
  325. if (!RecipeFileManager.Instance.DeleteSequence(name))
  326. {
  327. EV.PostWarningLog("System", $"Can not delete {name}, delete all failed.");
  328. return;
  329. }
  330. }
  331. EV.PostInfoLog("System", "All recipe deleted");
  332. }
  333. protected void DeleteRecipe(List<string> recipeFiles, out string reason)
  334. {
  335. reason = string.Empty;
  336. foreach (var name in recipeFiles)
  337. {
  338. if (!RecipeFileManager.Instance.DeleteSequence(name))
  339. {
  340. EV.PostWarningLog("System", $"Can not delete {name}.");
  341. return;
  342. }
  343. else
  344. {
  345. EV.PostWarningLog("System", $"Delete recipe {name}.");
  346. }
  347. }
  348. }
  349. private void Handle_S7F3(SECsPrimaryInEventArgs e)
  350. {
  351. try
  352. {
  353. LOG.Write("Handle_S7F4, Request down load recipe");
  354. string ppid = e.Inputs.DataItem[0][0].Value.ToString();
  355. string reason = string.Empty;
  356. // Get the format of PPBODY
  357. SECsFormat bodyType = e.Inputs.DataItem[0][1].Format;
  358. bool recipeSuccess = false;
  359. if (bodyType == SECsFormat.Binary)
  360. {
  361. recipeSuccess = DownLoadRecipeInByte(ppid, (byte[])e.Inputs.DataItem[0][1].Value, out reason);
  362. }
  363. else
  364. {
  365. recipeSuccess = DownLoadRecipe(ppid, e.Inputs.DataItem[0][1].ToString(), out reason);
  366. }
  367. if (recipeSuccess)
  368. {
  369. SECsMessage acknowledge = _gem.Services.ProcessProgram.ProcessProgramAcknowledge(0);
  370. _gem.SendReply(acknowledge, e.TransactionID);
  371. }
  372. else
  373. {
  374. //1:download recipe body fail:Permission Not Granted
  375. //2:download recipe body fail:Length Error
  376. //3:download recipe body fail:Matrix Overflow
  377. //4:download recipe body fail:PPID Not Found
  378. //5:download recipe body fail:Mode Unsupported
  379. SECsMessage acknowledge = _gem.Services.ProcessProgram.ProcessProgramAcknowledge(5);
  380. _gem.SendReply(acknowledge, e.TransactionID);
  381. }
  382. }
  383. catch (Exception ex)
  384. {
  385. LOG.Write("Handle_S7F4 exception:" + ex.Message);
  386. SECsMessage acknowledge = _gem.Services.ProcessProgram.ProcessProgramAcknowledge(1);
  387. _gem.SendReply(acknowledge, e.TransactionID);
  388. }
  389. }
  390. protected bool DownLoadRecipe(string name, string content, out string reason)
  391. {
  392. bool ret = false;
  393. reason = string.Empty;
  394. ret = RecipeFileManager.Instance.SaveSequence(name, content, false);
  395. if (!ret)
  396. {
  397. reason = string.Format("save recipe content failed,recipeName:{0}", name);
  398. LOG.Write(reason);
  399. }
  400. return ret;
  401. }
  402. protected bool DownLoadRecipeInByte(string name, byte[] content, out string reason)
  403. {
  404. bool ret = false;
  405. reason = string.Empty;
  406. ret = RecipeFileManager.Instance.SaveSequence(name, System.Text.Encoding.UTF8.GetString(content), false);
  407. if (!ret)
  408. {
  409. reason = string.Format("save recipe content failed,recipeName:{0}", name);
  410. LOG.Write(reason);
  411. }
  412. return ret;
  413. }
  414. /// <summary>
  415. /* 0 = OK
  416. 1 = Already have
  417. 2 = No space
  418. 3 = Invalid PPID
  419. 4 = Busy, try later
  420. 5 = Will not accept
  421. >5 = Other error
  422. 6-63 Reserved
  423. */
  424. ///</summary>
  425. /// <param name="e"></param>
  426. private void Handle_S7F1(SECsPrimaryInEventArgs e)
  427. {
  428. try
  429. {
  430. LOG.Write("Handle_S7F1, Process Program Load Inquire");
  431. string ppid = e.Inputs.DataItem[0][0].Value.ToString();
  432. var recipeList = RecipeFileManager.Instance.GetSequenceNameList();
  433. int ppGrant = 0;
  434. if (!recipeList.Contains(ppid))
  435. ppGrant = 3;
  436. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(7, 2, false);
  437. reply.DataItem.Add("PPGNT", ppGrant, SECsFormat.Binary);
  438. _gem.SendReply(reply, e.TransactionID);
  439. }
  440. catch (Exception ex)
  441. {
  442. LOG.Write("Handle_S7F1 exception:" + ex.Message);
  443. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(7, 0, false);
  444. _gem.SendReply(reply, e.TransactionID);
  445. }
  446. }
  447. private void Handle_S7F5(SECsPrimaryInEventArgs e)
  448. {
  449. try
  450. {
  451. LOG.Write("Handle_S7F5,Used to request the transfer of a process program");
  452. string ppid = e.Inputs.DataItem[0].ToString();
  453. string reason = string.Empty;
  454. string data = RecipeFileManager.Instance.GetSequence(ppid, false);
  455. if (!string.IsNullOrEmpty(data))
  456. {
  457. byte[] ppbody = System.Text.Encoding.UTF8.GetBytes(data);
  458. SECsMessage recipetToReply = _gem.Services.ProcessProgram.ProcessProgramData(ppid, ppbody);
  459. _gem.SendReply(recipetToReply, e.TransactionID);
  460. }
  461. else
  462. {
  463. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(7, 6, false);
  464. reply.DataItem.AddList();
  465. reply.DataItem[0].Add("RVIACK", 0x01/*abnormal*/, SECsFormat.Binary);
  466. reply.DataItem[0].Add("CPVALUE", reason, SECsFormat.Ascii);
  467. _gem.SendReply(reply, e.TransactionID);
  468. }
  469. }
  470. catch (Exception ex)
  471. {
  472. LOG.Write("Handle_S7F6 exception:" + ex.Message);
  473. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(7, 6, false);
  474. reply.DataItem.AddList();
  475. _gem.SendReply(reply, e.TransactionID);
  476. }
  477. }
  478. private void Handle_S7F19(SECsPrimaryInEventArgs e)
  479. {
  480. try
  481. {
  482. string reason = string.Empty;
  483. LOG.Write("Handle_S7F19, Request the transmission of the current equipment process program directory");
  484. var recipeList = RecipeFileManager.Instance.GetSequenceNameList();
  485. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(7, 20, false);
  486. reply.DataItem.AddList();
  487. for (int rNum = 0; rNum < recipeList.Count; rNum++)
  488. {
  489. reply.DataItem[0].Add("PPID", recipeList[rNum], SECsFormat.Ascii);
  490. }
  491. _gem.SendReply(reply, e.TransactionID);
  492. }
  493. catch (Exception ex)
  494. {
  495. LOG.Write("Handle_S7F19 exception:" + ex.Message);
  496. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(7, 0, false);
  497. _gem.SendReply(reply, e.TransactionID);
  498. }
  499. }
  500. private void Handle_S7F25(SECsPrimaryInEventArgs e)
  501. {
  502. try
  503. {
  504. var ppid = e.Inputs.DataItem[0].Value.ToString();
  505. LOG.Write("Handle_S7F25, request a particular process program from the other");
  506. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(7, 26, false);
  507. reply.DataItem.AddList();
  508. var parameters = GetRecipe(ppid, out string reason);
  509. if (parameters != null)
  510. {
  511. reply.DataItem[0].Add("PPID", ppid, SECsFormat.Ascii);
  512. reply.DataItem[0].Add("MDLN", _gem.EquipmentModel.Nameable.model, SECsFormat.Ascii);
  513. reply.DataItem[0].Add("SOFTREV", _gem.EquipmentModel.Nameable.softwareRev, SECsFormat.Ascii);
  514. reply.DataItem[0].AddList();
  515. reply.DataItem[0][3].AddList();
  516. reply.DataItem[0][3][0].Add("CCODE", 1, SECsFormat.U1);
  517. reply.DataItem[0][3][0].AddList();
  518. for (int i = 0; i < parameters.Count; i++)
  519. {
  520. reply.DataItem[0][3][0][1].Add($"PPARM{i + 1}", parameters[i], SECsFormat.Ascii);
  521. }
  522. }
  523. else
  524. {
  525. EV.PostWarningLog("FA", $"Request {ppid} failed, {reason}");
  526. }
  527. _gem.SendReply(reply, e.TransactionID);
  528. }
  529. catch (Exception ex)
  530. {
  531. LOG.Write("Handle_S7F25 exception:" + ex.Message);
  532. SECsMessage reply = _gem.Services.CustomMessage.CreateMessage(7, 0, false);
  533. _gem.SendReply(reply, e.TransactionID);
  534. }
  535. }
  536. public List<string> GetRecipe(string pathName, out string reason)
  537. {
  538. List<string> result = new List<string>();
  539. reason = string.Empty;
  540. try
  541. {
  542. string content = string.Empty;
  543. if (RecipeFileManager.Instance.CheckSequenceFileExist(pathName))
  544. content = RecipeFileManager.Instance.GetSequence(pathName, false);
  545. if (string.IsNullOrEmpty(content))
  546. {
  547. if (pathName.StartsWith("PMA") && !pathName.StartsWith("PMA\\Process") &&
  548. !pathName.StartsWith("PMA\\Clean"))
  549. pathName = pathName.Replace("PMA", "PMA\\Process");
  550. if (pathName.StartsWith("PMB") && !pathName.StartsWith("PMB\\Process") &&
  551. !pathName.StartsWith("PMB\\Clean"))
  552. pathName = pathName.Replace("PMB", "PMB\\Process");
  553. content = RecipeFileManager.Instance.LoadRecipe("", pathName, false);
  554. }
  555. result.Add(content);
  556. }
  557. catch (Exception ex)
  558. {
  559. LOG.Write(ex);
  560. reason = ex.Message;
  561. }
  562. return result;
  563. }
  564. public List<string> GetFormattedSequence(string sequenceName, out string reason)
  565. {
  566. List<string> result = new List<string>();
  567. try
  568. {
  569. string sequenceData = RecipeFileManager.Instance.GetSequence(sequenceName, false);
  570. XmlDocument recipeDoc = new XmlDocument();
  571. recipeDoc.LoadXml(sequenceData);
  572. XmlNodeList stepNodeList = recipeDoc.SelectNodes("/Aitex/TableSequenceData/Step");
  573. for (int i = 0; i < stepNodeList.Count; i++)
  574. {
  575. XmlElement stepNode = stepNodeList[i] as XmlElement;
  576. Dictionary<string, string> dic = new Dictionary<string, string>();
  577. //遍历Step节点
  578. foreach (XmlAttribute att in stepNode.Attributes)
  579. {
  580. result.Add($"STEP{i + 1}/{att.Name}:{att.Value}");
  581. }
  582. }
  583. reason = string.Empty;
  584. }
  585. catch (Exception ex)
  586. {
  587. LOG.Write(ex);
  588. reason = ex.Message;
  589. }
  590. return result;
  591. }
  592. public List<string> GetFormattedRecipe(string recipeName, out string reason)
  593. {
  594. List<string> result = new List<string>();
  595. try
  596. {
  597. string sequenceData = RecipeFileManager.Instance.LoadRecipe("", recipeName, false);
  598. XmlDocument recipeDoc = new XmlDocument();
  599. recipeDoc.LoadXml(sequenceData);
  600. XmlNodeList stepNodeList = recipeDoc.SelectNodes("/TableRecipeData/Step");
  601. for (int i = 0; i < stepNodeList.Count; i++)
  602. {
  603. XmlElement stepNode = stepNodeList[i] as XmlElement;
  604. Dictionary<string, string> dic = new Dictionary<string, string>();
  605. //遍历Step节点
  606. foreach (XmlAttribute att in stepNode.Attributes)
  607. {
  608. result.Add($"STEP{i + 1}/{att.Name}:{att.Value}");
  609. }
  610. //遍历Step子节点中所有的attribute属性节点
  611. foreach (XmlElement subStepNode in stepNode.ChildNodes)
  612. {
  613. foreach (XmlAttribute att in subStepNode.Attributes)
  614. {
  615. result.Add($"STEP{i + 1}/{subStepNode.Name}/{att.Name}:{att.Value}");
  616. }
  617. //遍历Step子节点的子节点中所有的attribute属性节点
  618. foreach (XmlElement subsubStepNode in subStepNode.ChildNodes)
  619. {
  620. foreach (XmlAttribute att in subsubStepNode.Attributes)
  621. {
  622. result.Add($"STEP{i + 1}/{subStepNode.Name}/{subsubStepNode.Name}/{att.Name}:{att.Value}");
  623. }
  624. }
  625. }
  626. }
  627. reason = string.Empty;
  628. }
  629. catch (Exception ex)
  630. {
  631. LOG.Write(ex);
  632. reason = ex.Message;
  633. }
  634. return result;
  635. }
  636. /// <summary>
  637. /// Single terminal message process
  638. /// S10F3 Format
  639. /// L,2
  640. /// 1. <TID>
  641. /// 2. <TEXT>
  642. /// </summary>
  643. /// <param name="e"></param>
  644. private void Handle_S10F3(SECsPrimaryInEventArgs e)
  645. {
  646. try
  647. {
  648. LOG.Write("Process host single terminal message");
  649. string terminalMessage = e.Inputs.DataItem["Ln"]["TEXT"].ToString();
  650. // notify equipment to show terminal message
  651. OnReceivedSingleTerminalMessage(terminalMessage);
  652. // acknowledge Host
  653. SECsMessage reply = _gem.Services.TerminalDisplay.TerminalDisplayAcknowledge(0);
  654. reply.Function = 4;
  655. _gem.SendReply(reply, e.TransactionID);
  656. }
  657. catch (Exception ex)
  658. {
  659. LOG.Write("Handle_S10F3 Exception: " + ex.Message);
  660. SECsMessage reply = _gem.Services.TerminalDisplay.TerminalDisplayAcknowledge(1/*will not display*/);
  661. reply.Function = 4;
  662. _gem.SendReply(reply, e.TransactionID);
  663. }
  664. }
  665. /// <summary>
  666. /// Multiple terminal message process
  667. /// S10F5 Format
  668. /// L,2
  669. /// 1. <TID>
  670. /// 2. L,N
  671. /// 1. <TEXT1>
  672. /// .
  673. /// .
  674. /// n.<TEXTn>
  675. /// </summary>
  676. /// <param name="e"></param>
  677. private void Handle_S10F5(SECsPrimaryInEventArgs e)
  678. {
  679. try
  680. {
  681. LOG.Write("Process host multiple terminal message");
  682. List<string> receivedMultipleMessages = new List<string>();
  683. string message = string.Empty;
  684. for (int i = 0; i < e.Inputs.DataItem[0][1].Count; i++)
  685. {
  686. receivedMultipleMessages.Add((string)e.Inputs.DataItem[0][1][i].Value);
  687. }
  688. // notify equipment to show terminal message
  689. OnReceivedMultipleTerminalMessage(receivedMultipleMessages);
  690. // acknowledge Host
  691. SECsMessage reply = _gem.Services.TerminalDisplay.TerminalDisplayAcknowledge(0);
  692. reply.Function = 6;
  693. _gem.SendReply(reply, e.TransactionID);
  694. }
  695. catch (Exception ex)
  696. {
  697. LOG.Write("Handle_S10F5 Exception: " + ex.Message);
  698. SECsMessage reply = _gem.Services.TerminalDisplay.TerminalDisplayAcknowledge(1/*will not display*/);
  699. reply.Function = 6;
  700. _gem.SendReply(reply, e.TransactionID);
  701. }
  702. }
  703. /// <summary>
  704. /// On single terminal message received
  705. /// </summary>
  706. /// <param name="terminalMessage"></param>
  707. protected virtual void OnReceivedSingleTerminalMessage(string terminalMessage)
  708. {
  709. EV.Notify("Host", EventTerminalMessage, terminalMessage);
  710. }
  711. /// <summary>
  712. /// On multiple terminal message received
  713. /// </summary>
  714. /// <param name="terminalMessage"></param>
  715. protected virtual void OnReceivedMultipleTerminalMessage(List<string> terminalMessage)
  716. {
  717. foreach (var message in terminalMessage)
  718. {
  719. EV.Notify("Host", EventTerminalMessage, message);
  720. }
  721. }
  722. public void Terminate()
  723. {
  724. _faMonitorThread.Stop();
  725. _logCleaner.Stop();
  726. }
  727. public void Enable()
  728. {
  729. _gem.SetEnable();
  730. }
  731. public void Disable()
  732. {
  733. _gem.SetDisable();
  734. }
  735. public void NotifyEvent(string eventName, Dictionary<string, string> dvid, Dictionary<string, object> objDvid)
  736. {
  737. _lstEvent.Enqueue(new FaEventItem() { dvid = dvid, objDvid = objDvid, EventName = eventName, IsAlarm = false });
  738. }
  739. public void NotifyAlarm(string alarmName, Dictionary<string, string> dvid, Dictionary<string, object> objDvid, string text)
  740. {
  741. _lstEvent.Enqueue(new FaEventItem() { dvid = dvid, objDvid = objDvid, EventName = alarmName, IsAlarm = true, Text = text});
  742. }
  743. public void NotifyEvent(string eventName, Dictionary<string, string> dvid)
  744. {
  745. _lstEvent.Enqueue(new FaEventItem(){dvid = dvid,EventName = eventName,IsAlarm = false});
  746. }
  747. public void NotifyAlarm(string alarmName, Dictionary<string, string> dvid, string text)
  748. {
  749. _lstEvent.Enqueue(new FaEventItem() { dvid = dvid, EventName = alarmName, IsAlarm = true, Text = text});
  750. }
  751. public void SetLocalControl()
  752. {
  753. Task.Factory.StartNew(() =>
  754. {
  755. _gem.SetLocal();
  756. });
  757. }
  758. public void SetRemoteControl()
  759. {
  760. Task.Factory.StartNew(() =>
  761. {
  762. _gem.SetRemote();
  763. });
  764. }
  765. public void SetEnableSpooling()
  766. {
  767. Task.Factory.StartNew(() =>
  768. {
  769. _gem .SetAttribute(GEMVariables.SpoolEnabled, AttributeType.EC, "true");
  770. });
  771. }
  772. public void SetDisableSpooling()
  773. {
  774. Task.Factory.StartNew(() =>
  775. {
  776. _gem .SetAttribute(GEMVariables.SpoolEnabled, AttributeType.EC, "false");
  777. });
  778. }
  779. public bool MonitorFaTask()
  780. {
  781. try
  782. {
  783. SynchronizeSVIDValue();
  784. FaEventItem ev;
  785. while (_lstEvent.TryDequeue(out ev))
  786. {
  787. if (ev.dvid != null)
  788. {
  789. foreach (var dvid in ev.dvid)
  790. {
  791. SetDVIDValue(dvid.Key, dvid.Value);
  792. }
  793. }
  794. if (ev.objDvid != null)
  795. {
  796. foreach (var dvid in ev.objDvid)
  797. {
  798. SetDVIDValue(dvid.Key, dvid.Value);
  799. }
  800. }
  801. SetDVIDValue(DVIDName.EventName, ev.EventName);
  802. if (ev.IsAlarm)
  803. {
  804. SetAlarm(ev.EventName, ev.Text);
  805. }
  806. else
  807. {
  808. SendEvent(ev.EventName);
  809. }
  810. //Thread.Sleep(500);
  811. }
  812. }
  813. catch (Exception ex)
  814. {
  815. System.Diagnostics.Trace.WriteLine(ex);
  816. }
  817. return true;
  818. }
  819. private void OnCommunicationStateChanged(object sender, SECsEventArgs e)
  820. {
  821. if (_gem.CommunicationState == CommunicationState.EnabledCommunicating)
  822. {
  823. _gem.SetOnline();
  824. _gem.SetRemote();
  825. }
  826. }
  827. /// <summary>
  828. /// Send terminal message to host
  829. /// </summary>
  830. /// <param name="message"></param>
  831. public void SendTerminalMessageToHost(string message)
  832. {
  833. if (!_gem.IsConnected || _gem.CommunicationState == CommunicationState.Disabled
  834. || _gem.CommunicationState == CommunicationState.WaitDelay
  835. || _gem.CommunicationState == CommunicationState.EnabledNotCommunicating)
  836. {
  837. EV.PostWarningLog("FA", "Host not connected, send terminal message failed.");
  838. return;
  839. }
  840. LOG.Write("Send terminal message to host:" + message);
  841. Task.Factory.StartNew(() =>
  842. {
  843. SECsMessage secsMsg = _gem.Services.TerminalDisplay.TerminalRequest(message);
  844. _gem.Send(secsMsg);
  845. });
  846. }
  847. public void SynchronizeSVIDValue()
  848. {
  849. try
  850. {
  851. foreach (SVID sv in _gem.EquipmentModel.StatusVariables.SVIDCollection)
  852. {
  853. if (sv != null && !_systemBuildInVariables.Contains(sv.logicalName))
  854. {
  855. if (sv.valueType == SECSFormats.List)
  856. {
  857. List<string> svData = _equipment.GetListSvidValue(sv.logicalName);
  858. if (svData != null && svData.Count > 0)
  859. {
  860. SECsDataItem data = new SECsDataItem(SECsFormat.List);
  861. foreach (var item in svData)
  862. {
  863. data.Add(item, item);
  864. }
  865. _gem.SetListAttribute(sv.logicalName, AttributeType.SV, data);
  866. }
  867. else
  868. {
  869. SECsDataItem data = new SECsDataItem(SECsFormat.List);
  870. data.Clear();
  871. _gem.SetListAttribute(sv.logicalName, AttributeType.SV, data);
  872. }
  873. }
  874. else
  875. {
  876. string svDataValue = _equipment.GetSvidValue(sv.logicalName);
  877. if (!string.IsNullOrEmpty(svDataValue))
  878. {
  879. if (sv.valueType == SECSFormats.Boolean) svDataValue = ConvertToBoolean(svDataValue).ToString();
  880. _gem.SetAttribute(sv.logicalName, AttributeType.SV, svDataValue);
  881. }
  882. }
  883. }
  884. }
  885. }
  886. catch (Exception ex)
  887. {
  888. LOG.Write("Synchronize FA Model Data exception:" + ex.Message);
  889. }
  890. }
  891. private bool SetDVIDValue(string localName, string value)
  892. {
  893. if (value == null) return false;
  894. //if (!string.IsNullOrEmpty(value))
  895. //{
  896. if (_gem.EquipmentModel == null || !_gem.EquipmentModel.DataVariables.DVIDCollection.IsExistLogicalName(localName))
  897. return false;
  898. foreach (VariableType dv in _gem.EquipmentModel.DataVariables.DVIDCollection)
  899. {
  900. if (dv.logicalName == localName)
  901. {
  902. if (dv.valueType == SECSFormats.Boolean)
  903. {
  904. value = ConvertToBoolean(value).ToString();
  905. }
  906. break;
  907. }
  908. }
  909. _gem.SetAttribute(localName, AttributeType.DV, value);
  910. //}
  911. return true;
  912. }
  913. private bool ConvertToBoolean(string value)
  914. {
  915. if (value == "0" || value.ToLower() == "false") return false;
  916. else return true;
  917. }
  918. private void SendEvent(string eventName)
  919. {
  920. try
  921. {
  922. if (_gem.EquipmentModel != null)
  923. {
  924. var allEvents = _gem.GetAllEnabledEvents();
  925. if (allEvents.Contains(eventName))
  926. {
  927. _gem.SendCollectionEvent(eventName);
  928. }
  929. else
  930. {
  931. //LOG.Write(string.Format("sendEvent failed,not find:", eventName));
  932. }
  933. //LOG.Write(string.Format("【FA2SendEvent--{0}】", eventName));
  934. }
  935. }
  936. catch (Exception ex)
  937. {
  938. LOG.Write("SendEvent Error:" + ex.Message);
  939. }
  940. }
  941. public void SetAlarm(string alarmTag, string text)
  942. {
  943. Task.Factory.StartNew(() =>
  944. {
  945. //if (_gem.IsAlarmSet(alarmTag))
  946. //{
  947. // _gem.ClearAlarm(alarmTag);
  948. //}
  949. var allAlarms = _gem.GetAllEnabledAlarms();
  950. if (allAlarms.Contains(alarmTag))
  951. {
  952. _gem.EquipmentModel.Alarms[alarmTag].description = text;
  953. _gem.SetAlarm(alarmTag);
  954. }
  955. else
  956. {
  957. //WriteLog(string.Format("sendAlarm failed,not find:", alarmTag));
  958. }
  959. //WriteLog(string.Format("【FA3SetAlarm--{0}】", alarmTag));
  960. });
  961. }
  962. private bool SetDVIDValue(string localName, object value)
  963. {
  964. if (value == null) return false;
  965. if (_gem.EquipmentModel == null || !_gem.EquipmentModel.DataVariables.DVIDCollection.IsExistLogicalName(localName))
  966. return false;
  967. foreach (VariableType dv in _gem.EquipmentModel.DataVariables.DVIDCollection)
  968. {
  969. if (dv.logicalName == localName)
  970. {
  971. if (dv.valueType == SECSFormats.Boolean)
  972. {
  973. value = ConvertToBoolean(Convert.ToString(value)).ToString();
  974. }
  975. break;
  976. }
  977. }
  978. _gem.SetAttribute(localName, AttributeType.DV, Convert.ToString(value));
  979. return true;
  980. }
  981. public void ClearAlarm(string alarmTag)
  982. {
  983. try
  984. {
  985. var allsetalarms = _gem.GetAllSetAlarms();
  986. if (allsetalarms != null && allsetalarms.Count > 0 && allsetalarms.Contains(alarmTag))
  987. _gem.ClearAlarm(alarmTag);
  988. if (string.IsNullOrEmpty(alarmTag))
  989. {
  990. foreach (var allsetalarm in allsetalarms)
  991. {
  992. _gem.ClearAlarm(allsetalarm.ToString());
  993. }
  994. }
  995. }
  996. catch (Exception ex)
  997. {
  998. LOG.Write($"Clear Alarm Error : {ex.Message}");
  999. }
  1000. }
  1001. }
  1002. }