SCManager.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Text;
  7. using System.Windows.Forms;
  8. using System.Xml;
  9. using Aitex.Common.Util;
  10. using Aitex.Core.Properties;
  11. using Aitex.Core.RT.ConfigCenter;
  12. using Aitex.Core.RT.Event;
  13. using Aitex.Core.RT.Log;
  14. using Aitex.Core.Util;
  15. namespace Aitex.Core.RT.SCCore
  16. {
  17. public class SCManager :ISCManager
  18. {
  19. private SCData _scData;
  20. private static object itemLocker = new object();
  21. private Dictionary<string, object> _items;
  22. public string ChamberName
  23. {
  24. get;
  25. set;
  26. }
  27. /// <summary>
  28. /// Get Variation name
  29. /// </summary>
  30. public string Path
  31. {
  32. get;
  33. set;
  34. }
  35. /// <summary>
  36. /// 反应腔系统参数配置类
  37. /// </summary>
  38. public SCManager()
  39. {
  40. SC.Manager = this;
  41. }
  42. public bool Initialize()
  43. {
  44. _items = new Dictionary<string, object>();
  45. Path = PathManager.GetCfgDir();
  46. //初始化系统配置
  47. var cfgFInfo = new FileInfo(Path + "PmConfig.xml");
  48. var cfgbakFInfo = new FileInfo(Path + "PmConfig.xml.bak");
  49. try
  50. {
  51. if (!cfgFInfo.Exists && !cfgbakFInfo.Exists)/*如果PmConfig.xml文件不存在,则创建默认的配置文件*/
  52. File.Copy(Path + "SCDefaultConfig.xml", Path + "PmConfig.xml");
  53. if (!DoPmConfigFileMerge(Path + "SCDefaultConfig.xml", Path + "PmConfig.xml"))
  54. {
  55. if (!DoPmConfigFileMerge(Path + "SCDefaultConfig.xml", Path + "PmConfig.xml.bak"))
  56. {
  57. throw new Exception("合并反应腔参数配置文件Config\\PmConfig.xml发生异常");
  58. }
  59. else
  60. {
  61. //对合并后的参数配置文件进行反序列化
  62. _scData = DeserialFromXml<SCData>(Path + "PmConfig.xml.bak");
  63. }
  64. }
  65. else
  66. {
  67. _scData = DeserialFromXml<SCData>(Path + "PmConfig.xml");
  68. }
  69. //对合并后的参数配置文件进行反序列化
  70. if (_scData == null)
  71. throw new Exception("反序列化配置文件Config\\PmConfig.xml(.bak)发生异常");
  72. //调用Config对象的初始化方法
  73. Init();
  74. _items = GetItems();
  75. foreach (var item in _items)
  76. {
  77. string sc = item.Key;
  78. CONFIG.Subscribe("", sc, () => { return GetItemValue(sc); });
  79. }
  80. return true;
  81. }
  82. catch (Exception ex)
  83. {
  84. var errMsg = "读取系统配置文件发生错误";
  85. LOG.Write(ex, errMsg);
  86. MessageBox.Show(ex.Message, errMsg, MessageBoxButtons.OK, MessageBoxIcon.Error);
  87. Environment.Exit(0);
  88. }
  89. return false;
  90. }
  91. public void Terminate()
  92. {
  93. _bAlive = false;
  94. }
  95. public T GetItem<T>(string name) where T :class
  96. {
  97. T item = null;
  98. lock (itemLocker)
  99. {
  100. if (_items.ContainsKey(name))
  101. {
  102. item = _items[name] as T;
  103. }
  104. }
  105. if (item == null)
  106. {
  107. LOG.Warning(String.Format("SC find item is null, name is {0}\"", name));
  108. }
  109. return item;
  110. }
  111. public SCString GetStringItem(string name)
  112. {
  113. SCString item = null;
  114. lock (itemLocker)
  115. {
  116. if (_items.ContainsKey(name))
  117. {
  118. item = _items[name] as SCString;
  119. }
  120. }
  121. if (item == null)
  122. {
  123. LOG.Warning(String.Format("SC find item is null, name is {0}\"", name));
  124. }
  125. return item;
  126. }
  127. public object GetItemValue(string name)
  128. {
  129. SCItem data = GetItem<SCItem>(name);
  130. if (data is SCItem<double>)
  131. {
  132. return ((SCItem<double>)(data)).Value;
  133. }
  134. else if (data is SCItem<bool>)
  135. {
  136. return ((SCItem<bool>)(data)).Value;
  137. }
  138. else if (data is SCItem<int>)
  139. {
  140. return ((SCItem<int>)(data)).Value;
  141. }
  142. else if (data is SCString)
  143. {
  144. return ((SCString)(data)).Value;
  145. }
  146. return null;
  147. }
  148. public void SetItemValue(string name, object value)
  149. {
  150. SCItem data = GetItem<SCItem>(name);
  151. if (data is SCItem<double>)
  152. {
  153. double setpoint = Convert.ToDouble(value.ToString());
  154. double min = ((SCItem<double>) (data)).RangeLowLimit;
  155. double max = ((SCItem<double>)(data)).RangeUpLimit;
  156. if ( (setpoint < min) || (setpoint > max))
  157. {
  158. EV.PostMessage("System", EventEnum.DefaultWarning, string.Format(Resources.SCManager_SetItemValue_0SetpointShouldBeIn1And2SettingValue3IsNotValid, data.Description, min, max, setpoint));
  159. return;
  160. }
  161. setpoint = Math.Min(setpoint, ((SCItem<double>) (data)).RangeUpLimit);
  162. setpoint = Math.Max(setpoint, ((SCItem<double>) (data)).RangeLowLimit);
  163. ((SCItem<double>)(data)).Value = setpoint;
  164. }
  165. else if (data is SCItem<bool>)
  166. {
  167. ((SCItem<bool>)(data)).Value = Convert.ToBoolean(value.ToString());
  168. }
  169. else if (data is SCItem<int>)
  170. {
  171. int setpoint = Convert.ToInt32(value.ToString());
  172. setpoint = Math.Min(setpoint, ((SCItem<int>)(data)).RangeUpLimit);
  173. setpoint = Math.Max(setpoint, ((SCItem<int>)(data)).RangeLowLimit);
  174. ((SCItem<int>)(data)).Value = setpoint;
  175. }
  176. else if (data is SCString)
  177. {
  178. ((SCString)(data)).Value = (string)value;
  179. }
  180. }
  181. /// <summary>
  182. /// 启动参数保存线程
  183. /// 保存的参数包括2类:
  184. /// 1. 静态参数,用户在界面直接设定后不会再次改变;
  185. /// 2. 动态参数,MO源使用量等,随着工艺程序运行,程序会自动改变其设定值
  186. /// </summary>
  187. private void Init()
  188. {
  189. _cfgThread = new System.Threading.Thread(new System.Threading.ThreadStart(Pm_Config_Thread));
  190. _cfgThread.IsBackground = true;
  191. _cfgThread.Priority = System.Threading.ThreadPriority.BelowNormal;
  192. // _cfgThread.Name = string.Format("{0} 参数保存线程", Reactor.PmName);
  193. _cfgThread.Name = string.Format("{0} 参数保存线程", "PM");
  194. _cfgThread.Start();
  195. // ActionLink.Attach(ActionType.AppQuit, (o1, o2, o3, o4) => _bAlive = false); //注册程序退出事件
  196. // DataCenter.Subscribe(PmKeySet.Pm_Variation, () => Variation);
  197. }
  198. R_TRIG _autoSaveCfg = new R_TRIG();
  199. DateTime _lastSaveCfgDt = DateTime.MinValue;
  200. bool _saveBackupFile = true; //指名当前保存哪个参数配置文件
  201. System.Threading.Thread _cfgThread; //参数配置维护线程,用于定时存储当前配置参数到磁盘
  202. bool _bAlive = true;
  203. /// <summary>
  204. /// PM参数保存线程
  205. /// </summary>
  206. void Pm_Config_Thread()
  207. {
  208. while (_bAlive)
  209. {
  210. TaskRun();
  211. System.Threading.Thread.Sleep(5000);
  212. }
  213. }
  214. /// <summary>
  215. /// 参数保存的任务线程实现
  216. /// </summary>
  217. private void TaskRun()
  218. {
  219. try
  220. {
  221. //保存配置文件到备份文件
  222. if (_saveBackupFile)
  223. {
  224. //System.Diagnostics.Debug.WriteLine("序列化 To Bak File");
  225. if (ObjectSerializer.SerializeObjectToXmlFile(Path + "PmConfig.xml.bak", this._scData))
  226. {
  227. _saveBackupFile = false;
  228. //System.Diagnostics.Debug.WriteLine("序列化 To Bak File - OK");
  229. }
  230. }
  231. else
  232. {
  233. //System.Diagnostics.Debug.WriteLine("序列化 To Config File");
  234. //延迟5秒钟后保存到备份文件,之所以不同时保存备份文件的原因是:计算机如果突然掉电,也可能导致2个配置文件同时损坏
  235. System.IO.File.Copy(Path + "PmConfig.xml.bak", Path + "PmConfig.xml", true);
  236. _saveBackupFile = true;
  237. //System.Diagnostics.Debug.WriteLine("序列化 To Config File - OK");
  238. }
  239. //每天自动保存PM的配置文件。每次PM程序启动自动保存当前配置文件
  240. _autoSaveCfg.CLK = DateTime.Today != _lastSaveCfgDt;
  241. if (_autoSaveCfg.Q)
  242. {
  243. var autoSaveCfgPath = Path + "Bak\\";
  244. System.IO.DirectoryInfo di = new DirectoryInfo(autoSaveCfgPath);
  245. if (!di.Exists)
  246. {
  247. di.Create();
  248. }
  249. di.Attributes = FileAttributes.Hidden;
  250. System.IO.File.Copy(Path + "PmConfig.xml.bak",
  251. string.Format("{0}{1}.{2}", autoSaveCfgPath, DateTime.Now.ToString("yyyyMMdd_HHmmss"), "PmConfig.xml"), true);
  252. _lastSaveCfgDt = DateTime.Today;
  253. }
  254. }
  255. catch (Exception ex)
  256. {
  257. LOG.Write(ex, "参数保存出错");
  258. }
  259. }
  260. string entryString = @" <Entry Name=""{0}"" Description=""{1}"" Type=""{2}"" Unit=""{3}"" Value=""{4}"" Default=""{5}"" RangeLowLimit=""{6}"" RangeUpLimit=""{7}"" />";
  261. // string sectionString = @" <Section Name=""{0}"" Description=""{1}"">";
  262. /// <summary>
  263. /// 以xml形式返回PM的配置数据
  264. /// </summary>
  265. /// <returns></returns>
  266. public string GetXmlConfig(string path)
  267. {
  268. try
  269. {
  270. FieldInfo[] datas = typeof(SCData).GetFields();
  271. StringBuilder sb = new StringBuilder();
  272. sb.Append("<?xml version=\"1.0\"?><SCData xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");
  273. string headersb = "";
  274. StringBuilder contentSb = new StringBuilder();
  275. foreach (FieldInfo fi in datas)
  276. {
  277. FieldInfo[] FIfields = fi.FieldType.GetFields();
  278. object fiValue = fi.GetValue(_scData);
  279. contentSb.Clear();
  280. foreach (FieldInfo innerFI in FIfields)
  281. {
  282. ///确保类的格式和最开始定义的一致,只有一个string类型的为描述字段
  283. if (innerFI.FieldType.Name == "String")
  284. headersb = (string.Format(@" <Section Name=""{0}"" Description=""{1}"">", fi.Name, innerFI.GetValue(fiValue)));
  285. else
  286. contentSb.Append(getXMLString(innerFI.GetValue(fiValue), innerFI.Name));
  287. }
  288. sb.Append(headersb);
  289. sb.Append(contentSb.ToString());
  290. sb.Append(" </Section>");
  291. }
  292. sb.Append("</SCData>");
  293. return sb.ToString();
  294. }
  295. catch (Exception ex)
  296. {
  297. LOG.Write(ex);
  298. return "";
  299. }
  300. }
  301. string getXMLString<T>(T data, string fieldName)
  302. {
  303. if (data is SCItem<double>)
  304. {
  305. return string.Format(entryString, fieldName, typeof(SCItem<double>).GetField("Description").GetValue(data), "Double", typeof(SCItem<double>).GetField("Unit").GetValue(data), typeof(SCItem<double>).GetField("Value").GetValue(data), typeof(SCItem<double>).GetField("Default").GetValue(data), typeof(SCItem<double>).GetField("RangeLowLimit").GetValue(data), typeof(SCItem<double>).GetField("RangeUpLimit").GetValue(data));
  306. }
  307. else if (data is SCItem<bool>)
  308. {
  309. return string.Format(entryString, fieldName, typeof(SCItem<bool>).GetField("Description").GetValue(data), "Int32", "", (bool)typeof(SCItem<bool>).GetField("Value").GetValue(data) ? 1 : 0, (bool)typeof(SCItem<bool>).GetField("Default").GetValue(data) ? 1 : 0, 0, 1);
  310. }
  311. else if (data is SCItem<int>)
  312. {
  313. return string.Format(entryString, fieldName, typeof(SCItem<int>).GetField("Description").GetValue(data), "Int32", typeof(SCItem<int>).GetField("Unit").GetValue(data), typeof(SCItem<int>).GetField("Value").GetValue(data), typeof(SCItem<int>).GetField("Default").GetValue(data), typeof(SCItem<int>).GetField("RangeLowLimit").GetValue(data), typeof(SCItem<int>).GetField("RangeUpLimit").GetValue(data));
  314. }
  315. else if (data is SCString)
  316. {
  317. return string.Format(entryString, fieldName, typeof(SCString).GetField("Description").GetValue(data), "String", typeof(SCString).GetField("Unit").GetValue(data), typeof(SCString).GetField("Value").GetValue(data), typeof(SCString).GetField("Default").GetValue(data), "", "");
  318. }
  319. else if (data is SCItem<double>[])
  320. {
  321. SCItem<double>[] cfgList = data as SCItem<double>[];
  322. if (cfgList != null)
  323. {
  324. StringBuilder sb = new StringBuilder();
  325. int i = 1;
  326. foreach (SCItem<double> cDouble in cfgList)
  327. {
  328. sb.Append(string.Format(entryString, fieldName + (i++), typeof(SCItem<double>).GetField("Description").GetValue(cDouble), "Double", typeof(SCItem<double>).GetField("Unit").GetValue(cDouble), typeof(SCItem<double>).GetField("Value").GetValue(cDouble), typeof(SCItem<double>).GetField("Default").GetValue(cDouble), typeof(SCItem<double>).GetField("RangeLowLimit").GetValue(cDouble), typeof(SCItem<double>).GetField("RangeUpLimit").GetValue(cDouble)));
  329. }
  330. return sb.ToString();
  331. }
  332. }
  333. return "";
  334. }
  335. public bool UpdateConfiguration(string groupName, List<ConfigEntry> lstEntry)
  336. {
  337. bool ret = true;
  338. try
  339. {
  340. foreach (ConfigEntry entry in lstEntry)
  341. {
  342. string error;
  343. if (!SaveConfig(groupName, entry.EntryName, entry.Value, out error))
  344. {
  345. LOG.Error(string.Format("保存SC失败{0}.{1}, {2}", groupName, entry.EntryName, error));
  346. ret =false;
  347. }
  348. }
  349. }
  350. catch (Exception ex)
  351. {
  352. LOG.Write(ex);
  353. return false;
  354. }
  355. return ret;
  356. }
  357. /// <summary>
  358. /// 修改反应腔参数
  359. /// </summary>
  360. /// <param name="groupName">参数组名</param>
  361. /// <param name="elementName">参数元素名</param>
  362. /// <param name="cfgValue">参数值</param>
  363. /// <param name="failReason">如果操作失败,返回的失败原因</param>
  364. /// <returns>True:操作成功 | False:操作失败</returns>
  365. public bool SaveConfig(string groupName, string elementName, string cfgValue, out string failReason)
  366. {
  367. try
  368. {
  369. XmlDocument xmlDom = new XmlDocument();
  370. foreach (FieldInfo fi in typeof(SCData).GetFields())
  371. {
  372. if (fi.Name == groupName)
  373. {
  374. object obj = fi.GetValue(_scData);
  375. foreach (FieldInfo infi in obj.GetType().GetFields())
  376. {
  377. if (infi.Name == elementName)
  378. {
  379. object valueobj = infi.GetValue(obj);
  380. foreach (FieldInfo valueField in valueobj.GetType().GetFields())
  381. {
  382. if (valueField.Name == "Value")
  383. {
  384. Type curType = valueField.FieldType;
  385. if (curType.Name.ToLower() == "boolean")
  386. {
  387. cfgValue = cfgValue == "0" ? "false" : "true";
  388. }
  389. var convertedValue = Convert.ChangeType(cfgValue, curType);
  390. object oldvalue = valueField.GetValue(valueobj);
  391. if (oldvalue + "" != convertedValue + "")
  392. {
  393. valueField.SetValue(valueobj, convertedValue);
  394. //@AAA ActionLink.Notify(ActionType.ConfigurationChanged, Aitex.FlyWheel.Reactor.ChamId, groupName, elementName, convertedValue);
  395. }
  396. break;
  397. }
  398. }
  399. break;
  400. }
  401. }
  402. break;
  403. }
  404. }
  405. failReason = "";
  406. return true;
  407. }
  408. catch (Exception ex)
  409. {
  410. failReason = string.Format("保存失败:{0}", ex.Message);
  411. return false;
  412. }
  413. }
  414. private Dictionary<string, object> GetItems()
  415. {
  416. try
  417. {
  418. Dictionary<string, object> items = new Dictionary<string, object>();
  419. FieldInfo[] datas = typeof(SCData).GetFields();
  420. foreach (FieldInfo fiGroup in datas)
  421. {
  422. object objGroup = fiGroup.GetValue(_scData);
  423. foreach (FieldInfo fiItem in objGroup.GetType().GetFields())
  424. {
  425. object item = fiItem.GetValue(objGroup);
  426. if (item is SCItem)
  427. {
  428. string name = String.Format("{0}_{1}", fiGroup.Name, fiItem.Name);
  429. if (items.ContainsKey(name))
  430. {
  431. LOG.Warning("Find Confilct SC name {0}",name);
  432. continue;
  433. }
  434. items.Add(name, item);
  435. }
  436. }
  437. }
  438. return items;
  439. }
  440. catch (Exception ex)
  441. {
  442. LOG.Write(ex);
  443. throw(ex);
  444. }
  445. }
  446. /// <summary>
  447. /// 合并PM的配置文件
  448. /// </summary>
  449. /// <param name="referenceConfigFile">标准的参数配置引用文件</param>
  450. /// <param name="currentConfigFile">当前设备使用的参数配置文件</param>
  451. /// <returns></returns>
  452. private bool DoPmConfigFileMerge(string referenceConfigFile, string currentConfigFile)
  453. {
  454. try
  455. {
  456. XmlDocument doc1 = new XmlDocument();
  457. XmlDocument doc2 = new XmlDocument();
  458. doc1.Load(currentConfigFile);
  459. doc2.Load(referenceConfigFile);
  460. foreach (XmlElement groupNode in doc2.DocumentElement.ChildNodes)
  461. {
  462. string groupName = groupNode.Name;
  463. foreach (XmlNode elementNode in groupNode.ChildNodes)
  464. {
  465. if (elementNode.NodeType != XmlNodeType.Element) continue;
  466. string elementName = elementNode.Name;
  467. string xpath = string.Format("/SCData/{0}/{1}/Value", groupName, elementName);
  468. var localValueNode = doc1.SelectSingleNode(xpath) as XmlElement;
  469. if (localValueNode == null || string.IsNullOrEmpty(localValueNode.InnerText))
  470. continue;
  471. elementNode.SelectSingleNode("Value").InnerText = localValueNode.InnerText;
  472. }
  473. }
  474. doc2.Save(currentConfigFile);
  475. }
  476. catch (Exception ex)
  477. {
  478. LOG.Write(ex, string.Format("合并{0},{1}发生错误", referenceConfigFile, currentConfigFile));
  479. return false;
  480. }
  481. return true;
  482. }
  483. /// <summary>
  484. /// 从XML文件反序列化重建设备模块
  485. /// 1. 如果XML序列化文件不存在,则新生成XML序列化文件
  486. /// 2. 如果反序列化文件失败,则自动反序列化该文件默认的备份文件
  487. /// </summary>
  488. /// <typeparam name="T">对象类型</typeparam>
  489. /// <param name="filePath">对象序列化文件路径</param>
  490. /// <returns>反序列化后的对象</returns>
  491. public T DeserialFromXml<T>(string filePath)
  492. {
  493. FileInfo fi = new FileInfo(filePath);
  494. FileInfo fiBakup = new FileInfo(filePath + ".bak");
  495. T obj = default(T);
  496. if (!fi.Exists && !fiBakup.Exists)
  497. return default(T);
  498. try
  499. {
  500. obj = (T)ObjectSerializer.DeserializeObjectFromXmlFile<T>(filePath);
  501. }
  502. catch (Exception ex)
  503. {
  504. LOG.Write(ex, string.Format("反序列化{0}出错", filePath));
  505. try
  506. {
  507. obj = (T)ObjectSerializer.DeserializeObjectFromXmlFile<T>(filePath + ".bak");
  508. }
  509. catch (Exception ex2)
  510. {
  511. LOG.Write(ex2, string.Format("反序列化{0}出错", filePath + ".bak"));
  512. return default(T);
  513. }
  514. }
  515. return obj;
  516. }
  517. //help function
  518. public void GenerateEnumName()
  519. {
  520. string file = Path + @"_SCName.cs";
  521. StringBuilder sb = new StringBuilder();
  522. sb.AppendLine(string.Format("//文件根据{0}生成", "SCData.cs"));
  523. sb.AppendLine(string.Format("//生成时间:{0}", DateTime.Now.ToString()));
  524. sb.AppendLine();
  525. sb.AppendLine(@"
  526. namespace Aitex.Common.Core
  527. {
  528. public class SCName
  529. {");
  530. foreach (string name in _items.Keys)
  531. {
  532. sb.AppendLine(String.Format("\t\t\t public const string {0} = \"{0}\";", name.Replace('.','_'), name));
  533. sb.AppendLine();
  534. }
  535. sb.AppendLine(@"
  536. }
  537. }");
  538. using (StreamWriter sw = new StreamWriter(file, false))
  539. {
  540. sw.Write(sb.ToString());
  541. sw.Close();
  542. }
  543. }
  544. }
  545. }