using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Windows.Forms; using System.Xml; using Aitex.Common.Util; using Aitex.Core.Properties; using Aitex.Core.RT.ConfigCenter; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.Util; namespace Aitex.Core.RT.SCCore { public class SCManager :ISCManager { private SCData _scData; private static object itemLocker = new object(); private Dictionary _items; public string ChamberName { get; set; } /// /// Get Variation name /// public string Path { get; set; } /// /// 反应腔系统参数配置类 /// public SCManager() { SC.Manager = this; } public bool Initialize() { _items = new Dictionary(); Path = PathManager.GetCfgDir(); //初始化系统配置 var cfgFInfo = new FileInfo(Path + "PmConfig.xml"); var cfgbakFInfo = new FileInfo(Path + "PmConfig.xml.bak"); try { if (!cfgFInfo.Exists && !cfgbakFInfo.Exists)/*如果PmConfig.xml文件不存在,则创建默认的配置文件*/ File.Copy(Path + "SCDefaultConfig.xml", Path + "PmConfig.xml"); if (!DoPmConfigFileMerge(Path + "SCDefaultConfig.xml", Path + "PmConfig.xml")) { if (!DoPmConfigFileMerge(Path + "SCDefaultConfig.xml", Path + "PmConfig.xml.bak")) { throw new Exception("合并反应腔参数配置文件Config\\PmConfig.xml发生异常"); } else { //对合并后的参数配置文件进行反序列化 _scData = DeserialFromXml(Path + "PmConfig.xml.bak"); } } else { _scData = DeserialFromXml(Path + "PmConfig.xml"); } //对合并后的参数配置文件进行反序列化 if (_scData == null) throw new Exception("反序列化配置文件Config\\PmConfig.xml(.bak)发生异常"); //调用Config对象的初始化方法 Init(); _items = GetItems(); foreach (var item in _items) { string sc = item.Key; CONFIG.Subscribe("", sc, () => { return GetItemValue(sc); }); } return true; } catch (Exception ex) { var errMsg = "读取系统配置文件发生错误"; LOG.Write(ex, errMsg); MessageBox.Show(ex.Message, errMsg, MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(0); } return false; } public void Terminate() { _bAlive = false; } public T GetItem(string name) where T :class { T item = null; lock (itemLocker) { if (_items.ContainsKey(name)) { item = _items[name] as T; } } if (item == null) { LOG.Warning(String.Format("SC find item is null, name is {0}\"", name)); } return item; } public SCString GetStringItem(string name) { SCString item = null; lock (itemLocker) { if (_items.ContainsKey(name)) { item = _items[name] as SCString; } } if (item == null) { LOG.Warning(String.Format("SC find item is null, name is {0}\"", name)); } return item; } public object GetItemValue(string name) { SCItem data = GetItem(name); if (data is SCItem) { return ((SCItem)(data)).Value; } else if (data is SCItem) { return ((SCItem)(data)).Value; } else if (data is SCItem) { return ((SCItem)(data)).Value; } else if (data is SCString) { return ((SCString)(data)).Value; } return null; } public void SetItemValue(string name, object value) { SCItem data = GetItem(name); if (data is SCItem) { double setpoint = Convert.ToDouble(value.ToString()); double min = ((SCItem) (data)).RangeLowLimit; double max = ((SCItem)(data)).RangeUpLimit; if ( (setpoint < min) || (setpoint > max)) { EV.PostMessage("System", EventEnum.DefaultWarning, string.Format(Resources.SCManager_SetItemValue_0SetpointShouldBeIn1And2SettingValue3IsNotValid, data.Description, min, max, setpoint)); return; } setpoint = Math.Min(setpoint, ((SCItem) (data)).RangeUpLimit); setpoint = Math.Max(setpoint, ((SCItem) (data)).RangeLowLimit); ((SCItem)(data)).Value = setpoint; } else if (data is SCItem) { ((SCItem)(data)).Value = Convert.ToBoolean(value.ToString()); } else if (data is SCItem) { int setpoint = Convert.ToInt32(value.ToString()); setpoint = Math.Min(setpoint, ((SCItem)(data)).RangeUpLimit); setpoint = Math.Max(setpoint, ((SCItem)(data)).RangeLowLimit); ((SCItem)(data)).Value = setpoint; } else if (data is SCString) { ((SCString)(data)).Value = (string)value; } } /// /// 启动参数保存线程 /// 保存的参数包括2类: /// 1. 静态参数,用户在界面直接设定后不会再次改变; /// 2. 动态参数,MO源使用量等,随着工艺程序运行,程序会自动改变其设定值 /// private void Init() { _cfgThread = new System.Threading.Thread(new System.Threading.ThreadStart(Pm_Config_Thread)); _cfgThread.IsBackground = true; _cfgThread.Priority = System.Threading.ThreadPriority.BelowNormal; // _cfgThread.Name = string.Format("{0} 参数保存线程", Reactor.PmName); _cfgThread.Name = string.Format("{0} 参数保存线程", "PM"); _cfgThread.Start(); // ActionLink.Attach(ActionType.AppQuit, (o1, o2, o3, o4) => _bAlive = false); //注册程序退出事件 // DataCenter.Subscribe(PmKeySet.Pm_Variation, () => Variation); } R_TRIG _autoSaveCfg = new R_TRIG(); DateTime _lastSaveCfgDt = DateTime.MinValue; bool _saveBackupFile = true; //指名当前保存哪个参数配置文件 System.Threading.Thread _cfgThread; //参数配置维护线程,用于定时存储当前配置参数到磁盘 bool _bAlive = true; /// /// PM参数保存线程 /// void Pm_Config_Thread() { while (_bAlive) { TaskRun(); System.Threading.Thread.Sleep(5000); } } /// /// 参数保存的任务线程实现 /// private void TaskRun() { try { //保存配置文件到备份文件 if (_saveBackupFile) { //System.Diagnostics.Debug.WriteLine("序列化 To Bak File"); if (ObjectSerializer.SerializeObjectToXmlFile(Path + "PmConfig.xml.bak", this._scData)) { _saveBackupFile = false; //System.Diagnostics.Debug.WriteLine("序列化 To Bak File - OK"); } } else { //System.Diagnostics.Debug.WriteLine("序列化 To Config File"); //延迟5秒钟后保存到备份文件,之所以不同时保存备份文件的原因是:计算机如果突然掉电,也可能导致2个配置文件同时损坏 System.IO.File.Copy(Path + "PmConfig.xml.bak", Path + "PmConfig.xml", true); _saveBackupFile = true; //System.Diagnostics.Debug.WriteLine("序列化 To Config File - OK"); } //每天自动保存PM的配置文件。每次PM程序启动自动保存当前配置文件 _autoSaveCfg.CLK = DateTime.Today != _lastSaveCfgDt; if (_autoSaveCfg.Q) { var autoSaveCfgPath = Path + "Bak\\"; System.IO.DirectoryInfo di = new DirectoryInfo(autoSaveCfgPath); if (!di.Exists) { di.Create(); } di.Attributes = FileAttributes.Hidden; System.IO.File.Copy(Path + "PmConfig.xml.bak", string.Format("{0}{1}.{2}", autoSaveCfgPath, DateTime.Now.ToString("yyyyMMdd_HHmmss"), "PmConfig.xml"), true); _lastSaveCfgDt = DateTime.Today; } } catch (Exception ex) { LOG.Write(ex, "参数保存出错"); } } string entryString = @" "; // string sectionString = @"
"; /// /// 以xml形式返回PM的配置数据 /// /// public string GetXmlConfig(string path) { try { FieldInfo[] datas = typeof(SCData).GetFields(); StringBuilder sb = new StringBuilder(); sb.Append(""); string headersb = ""; StringBuilder contentSb = new StringBuilder(); foreach (FieldInfo fi in datas) { FieldInfo[] FIfields = fi.FieldType.GetFields(); object fiValue = fi.GetValue(_scData); contentSb.Clear(); foreach (FieldInfo innerFI in FIfields) { ///确保类的格式和最开始定义的一致,只有一个string类型的为描述字段 if (innerFI.FieldType.Name == "String") headersb = (string.Format(@"
", fi.Name, innerFI.GetValue(fiValue))); else contentSb.Append(getXMLString(innerFI.GetValue(fiValue), innerFI.Name)); } sb.Append(headersb); sb.Append(contentSb.ToString()); sb.Append("
"); } sb.Append("
"); return sb.ToString(); } catch (Exception ex) { LOG.Write(ex); return ""; } } string getXMLString(T data, string fieldName) { if (data is SCItem) { return string.Format(entryString, fieldName, typeof(SCItem).GetField("Description").GetValue(data), "Double", typeof(SCItem).GetField("Unit").GetValue(data), typeof(SCItem).GetField("Value").GetValue(data), typeof(SCItem).GetField("Default").GetValue(data), typeof(SCItem).GetField("RangeLowLimit").GetValue(data), typeof(SCItem).GetField("RangeUpLimit").GetValue(data)); } else if (data is SCItem) { return string.Format(entryString, fieldName, typeof(SCItem).GetField("Description").GetValue(data), "Int32", "", (bool)typeof(SCItem).GetField("Value").GetValue(data) ? 1 : 0, (bool)typeof(SCItem).GetField("Default").GetValue(data) ? 1 : 0, 0, 1); } else if (data is SCItem) { return string.Format(entryString, fieldName, typeof(SCItem).GetField("Description").GetValue(data), "Int32", typeof(SCItem).GetField("Unit").GetValue(data), typeof(SCItem).GetField("Value").GetValue(data), typeof(SCItem).GetField("Default").GetValue(data), typeof(SCItem).GetField("RangeLowLimit").GetValue(data), typeof(SCItem).GetField("RangeUpLimit").GetValue(data)); } else if (data is SCString) { 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), "", ""); } else if (data is SCItem[]) { SCItem[] cfgList = data as SCItem[]; if (cfgList != null) { StringBuilder sb = new StringBuilder(); int i = 1; foreach (SCItem cDouble in cfgList) { sb.Append(string.Format(entryString, fieldName + (i++), typeof(SCItem).GetField("Description").GetValue(cDouble), "Double", typeof(SCItem).GetField("Unit").GetValue(cDouble), typeof(SCItem).GetField("Value").GetValue(cDouble), typeof(SCItem).GetField("Default").GetValue(cDouble), typeof(SCItem).GetField("RangeLowLimit").GetValue(cDouble), typeof(SCItem).GetField("RangeUpLimit").GetValue(cDouble))); } return sb.ToString(); } } return ""; } public bool UpdateConfiguration(string groupName, List lstEntry) { bool ret = true; try { foreach (ConfigEntry entry in lstEntry) { string error; if (!SaveConfig(groupName, entry.EntryName, entry.Value, out error)) { LOG.Error(string.Format("保存SC失败{0}.{1}, {2}", groupName, entry.EntryName, error)); ret =false; } } } catch (Exception ex) { LOG.Write(ex); return false; } return ret; } /// /// 修改反应腔参数 /// /// 参数组名 /// 参数元素名 /// 参数值 /// 如果操作失败,返回的失败原因 /// True:操作成功 | False:操作失败 public bool SaveConfig(string groupName, string elementName, string cfgValue, out string failReason) { try { XmlDocument xmlDom = new XmlDocument(); foreach (FieldInfo fi in typeof(SCData).GetFields()) { if (fi.Name == groupName) { object obj = fi.GetValue(_scData); foreach (FieldInfo infi in obj.GetType().GetFields()) { if (infi.Name == elementName) { object valueobj = infi.GetValue(obj); foreach (FieldInfo valueField in valueobj.GetType().GetFields()) { if (valueField.Name == "Value") { Type curType = valueField.FieldType; if (curType.Name.ToLower() == "boolean") { cfgValue = cfgValue == "0" ? "false" : "true"; } var convertedValue = Convert.ChangeType(cfgValue, curType); object oldvalue = valueField.GetValue(valueobj); if (oldvalue + "" != convertedValue + "") { valueField.SetValue(valueobj, convertedValue); //@AAA ActionLink.Notify(ActionType.ConfigurationChanged, Aitex.FlyWheel.Reactor.ChamId, groupName, elementName, convertedValue); } break; } } break; } } break; } } failReason = ""; return true; } catch (Exception ex) { failReason = string.Format("保存失败:{0}", ex.Message); return false; } } private Dictionary GetItems() { try { Dictionary items = new Dictionary(); FieldInfo[] datas = typeof(SCData).GetFields(); foreach (FieldInfo fiGroup in datas) { object objGroup = fiGroup.GetValue(_scData); foreach (FieldInfo fiItem in objGroup.GetType().GetFields()) { object item = fiItem.GetValue(objGroup); if (item is SCItem) { string name = String.Format("{0}_{1}", fiGroup.Name, fiItem.Name); if (items.ContainsKey(name)) { LOG.Warning("Find Confilct SC name {0}",name); continue; } items.Add(name, item); } } } return items; } catch (Exception ex) { LOG.Write(ex); throw(ex); } } /// /// 合并PM的配置文件 /// /// 标准的参数配置引用文件 /// 当前设备使用的参数配置文件 /// private bool DoPmConfigFileMerge(string referenceConfigFile, string currentConfigFile) { try { XmlDocument doc1 = new XmlDocument(); XmlDocument doc2 = new XmlDocument(); doc1.Load(currentConfigFile); doc2.Load(referenceConfigFile); foreach (XmlElement groupNode in doc2.DocumentElement.ChildNodes) { string groupName = groupNode.Name; foreach (XmlNode elementNode in groupNode.ChildNodes) { if (elementNode.NodeType != XmlNodeType.Element) continue; string elementName = elementNode.Name; string xpath = string.Format("/SCData/{0}/{1}/Value", groupName, elementName); var localValueNode = doc1.SelectSingleNode(xpath) as XmlElement; if (localValueNode == null || string.IsNullOrEmpty(localValueNode.InnerText)) continue; elementNode.SelectSingleNode("Value").InnerText = localValueNode.InnerText; } } doc2.Save(currentConfigFile); } catch (Exception ex) { LOG.Write(ex, string.Format("合并{0},{1}发生错误", referenceConfigFile, currentConfigFile)); return false; } return true; } /// /// 从XML文件反序列化重建设备模块 /// 1. 如果XML序列化文件不存在,则新生成XML序列化文件 /// 2. 如果反序列化文件失败,则自动反序列化该文件默认的备份文件 /// /// 对象类型 /// 对象序列化文件路径 /// 反序列化后的对象 public T DeserialFromXml(string filePath) { FileInfo fi = new FileInfo(filePath); FileInfo fiBakup = new FileInfo(filePath + ".bak"); T obj = default(T); if (!fi.Exists && !fiBakup.Exists) return default(T); try { obj = (T)ObjectSerializer.DeserializeObjectFromXmlFile(filePath); } catch (Exception ex) { LOG.Write(ex, string.Format("反序列化{0}出错", filePath)); try { obj = (T)ObjectSerializer.DeserializeObjectFromXmlFile(filePath + ".bak"); } catch (Exception ex2) { LOG.Write(ex2, string.Format("反序列化{0}出错", filePath + ".bak")); return default(T); } } return obj; } //help function public void GenerateEnumName() { string file = Path + @"_SCName.cs"; StringBuilder sb = new StringBuilder(); sb.AppendLine(string.Format("//文件根据{0}生成", "SCData.cs")); sb.AppendLine(string.Format("//生成时间:{0}", DateTime.Now.ToString())); sb.AppendLine(); sb.AppendLine(@" namespace Aitex.Common.Core { public class SCName {"); foreach (string name in _items.Keys) { sb.AppendLine(String.Format("\t\t\t public const string {0} = \"{0}\";", name.Replace('.','_'), name)); sb.AppendLine(); } sb.AppendLine(@" } }"); using (StreamWriter sw = new StreamWriter(file, false)) { sw.Write(sb.ToString()); sw.Close(); } } } }