using System; using System.Collections.Generic; using System.Linq; using System.Text; using Npgsql; using System.Data; using Aitex.UI.Charting.Model; using Abt.Controls.SciChart; using System.Windows.Media; using System.Threading; using System.Text.RegularExpressions; using DataAnalysisControl.Core; using Aitex.DataAnalysis.Core; namespace Aitex.UI.Charting.ViewModel { public class ChartingBaseViewModel : BaseViewModel { #region put protected database operations here private static object _dbLocker = new object(); private static NpgsqlConnection _conn = null; public static string ServerName { get { string ip = RegEdit.ReadRegedit("Aitex", "Database_IP"); if (string.IsNullOrEmpty(ip)) { //创建默认注册表 RegEdit.WriteRegedit("Aitex", "Database_Ip", "127.0.0.1"); RegEdit.WriteRegedit("Aitex", "Database_Port", "5432"); RegEdit.WriteRegedit("Aitex", "Database_User", "postgres"); RegEdit.WriteRegedit("Aitex", "Database_Pwd", "123456"); RegEdit.WriteRegedit("Aitex", "Database_Name", "postgres"); } ip = RegEdit.ReadRegedit("Aitex", "Database_IP"); string port = RegEdit.ReadRegedit("Aitex", "Database_Port"); string user = RegEdit.ReadRegedit("Aitex", "Database_User"); string pwd = RegEdit.ReadRegedit("Aitex", "Database_Pwd"); string db = RegEdit.ReadRegedit("Aitex", "Database_Name"); return String.Format("Server={0};Port={1};User Id={2};Password={3};Database={4};Enlist=true;CommandTimeout=10;Timeout=10;", ip, port, user, pwd, db); //return CONTEXT.GetDBConnString(); } } /// /// 创建数据库连接 /// /// /// True:创建成功 False:创建失败 protected static bool CreateConnection(out string reason) { lock (_dbLocker) { CONTEXT.WriteLog("Charting工具开始创建Charting工具的数据库连接"); reason = string.Empty; if (_conn != null) { _conn.Close(); _conn = null; } string connectionString = ServerName; if (string.IsNullOrWhiteSpace(connectionString)) { throw new ArgumentNullException("ConnectionString"); } try { var conn = new NpgsqlConnection(connectionString); conn.Open(); _conn = conn; } catch (Exception ex) { reason = ex.Message; CONTEXT.WriteLog(ex, string.Format("Charting工具创建PostgreSQL数据库连接失败,连接字段: 【{0}】", connectionString)); return false; } return true; } } /// /// 执行无需返回的sql语句 /// /// public static void ExecuteNonQuery(string cmdText) { string reason; if (_conn == null && !CreateConnection(out reason)) return; lock (_dbLocker) { if (_conn.State != ConnectionState.Open) _conn.Open(); using (NpgsqlCommand command = new NpgsqlCommand(cmdText, _conn)) { command.ExecuteNonQuery(); } } } /// /// 执行SQL语句 /// /// /// /// public static DataSet ExecuteDataset(string cmdText, params object[] p) { DeviceTimer tm = new DeviceTimer(); tm.Start(0); string reason; if (_conn == null && !CreateConnection(out reason)) return null; DataSet ds = new DataSet(); lock (_dbLocker) { using (NpgsqlCommand command = new NpgsqlCommand()) { try { if (_conn.State != ConnectionState.Open) _conn.Open(); command.Parameters.Clear(); command.Connection = _conn; command.CommandText = cmdText; command.CommandType = CommandType.Text; if (p != null) { foreach (object parm in p) command.Parameters.AddWithValue(string.Empty, parm); } using (NpgsqlDataAdapter da = new NpgsqlDataAdapter(command)) { da.Fill(ds); } } catch (Exception ex) { //如果是Table不存在,则跳过该天的数据查询 if (ex is Npgsql.NpgsqlException && 0 == String.Compare((ex as Npgsql.NpgsqlException).Code, "42P01"/*未定义的表(UNDEFINED TABLE)*/, true)) { string errMsg = string.Format("执行SQL:【{0}】 发生Table不存在", cmdText); CONTEXT.WriteLog(errMsg); } else { CreateConnection(out reason); string errMsg = string.Format("执行SQL:【{0}】 发生异常,重新创建数据库连接", cmdText); CONTEXT.WriteLog(ex, errMsg); //throw new Exception(errMsg); } } } } return ds; } #endregion #region get recipe information /// /// 获取指定石墨盘的工艺程序运行每一步的时间信息+步骤名称 /// /// /// public List GetRecipeStepInfo(string recipeRunGuid) { var Ret = new List(); try { string sql = string.Format("SELECT * FROM \"SusceptorData\" where \"SusceptorId\"= '{0}' and \"ItemType\" = '{1}' order by \"Time\" asc;", recipeRunGuid, "RecipeStepStart"); Ret.Add(new RecipeSyncPoint() { StepTime = DateTime.MinValue, StepName = "NULL" }); var ds = ExecuteDataset(sql); if (ds != null && ds.Tables != null && ds.Tables.Count >= 0) { for (int i = 0; i < ds.Tables[0].Rows.Count; i++) { var row = ds.Tables[0].Rows[i]; var stepTime = Convert.ToDateTime(row["Time"].ToString()); var stepDesc = row["ItemRemark"].ToString(); if (stepDesc.StartsWith("工艺运行中:开始")) stepDesc = stepDesc.Replace("工艺运行中:开始", string.Empty); Ret.Add(new RecipeSyncPoint() { StepTime = stepTime, StepName = stepDesc }); } } } catch (Exception ex) { CONTEXT.WriteLog(ex, string.Format("获取工艺Run编号{0}的工艺处理数据发生异常", recipeRunGuid)); } return Ret; } #endregion #region get susceptor list /// /// 石墨盘数据模型 /// public class SusceptorDataModel { public string RecipeRunGuid { get; set; } public string SusceptorId { get; set; } public string UserDefinedId { get; set; } public string RecipeName { get; set; } /// /// 仅用于界面显示,em. 20131219131415_LED001-(2) 简化为 LED001-(2) /// public string RecipeShortName { get { if (!string.IsNullOrEmpty(RecipeName) && Regex.IsMatch(RecipeName, @"^\d\d\d\d\d\d\d\d\d\d\d\d\d\d_*") && RecipeName.Length > 15) return RecipeName.Substring(15); return RecipeName; } } //public string CreateTime { get; set; } //public string DeleteTime { get; set; } public string ProcessBeginTime { get; set; } public string ProcessEndTime { get; set; } public string ProcessIn { get; set; } public string SusceptorStatus { get; set; } public string WaferOnSusceptor { get; set; } public string Description { get; set; } } /// /// get susceptor list /// /// /// /// /// public List GetSusceptorList(DateTime begin, DateTime end, string processIn) { return GetSusceptorList(begin, end, processIn, "", "", ""); } /// /// get susceptor list /// /// /// /// /// /// /// /// public List GetSusceptorList(DateTime begin, DateTime end, string processIn, string recipeName, string description, string userDefinedId) { var ret = new List(); try { string sql = string.Format("SELECT * FROM \"RecipeRunHistory\" where \"ProcessBeginTime\" >= '{0}' and \"ProcessBeginTime\" <= '{1}' {2} {3} {4} {5} order by \"ProcessBeginTime\" asc;", begin.ToString("yyyy/MM/dd HH:mm:ss.fff"), end.ToString("yyyy/MM/dd HH:mm:ss.fff"), string.IsNullOrEmpty(processIn) ? "" : string.Format(" and \"ProcessIn\" = '{0}'", processIn), string.IsNullOrEmpty(recipeName) ? "" : string.Format(" and \"RecipeName\" = '{0}'", recipeName), string.IsNullOrEmpty(description) ? "" : string.Format(" and \"Description\" = '{0}'", description), string.IsNullOrEmpty(userDefinedId) ? "" : string.Format(" and \"UserDefinedId\" = '{0}'", userDefinedId)); using (var dataSet = ExecuteDataset(sql)) { for(int i = 0; i < dataSet.Tables[0].Rows.Count;i++) { var row = dataSet.Tables[0].Rows[i]; string susceptorStatusString = row["SusceptorStatus"].ToString(); //SusceptorStatus eSt; //bool isSucc = Enum.TryParse(susceptorStatusString, out eSt); //if (isSucc) susceptorStatusString = Common.Utilities.Converter.SusceptorStatus(eSt); ret.Add(new SusceptorDataModel() { RecipeRunGuid = row["RecipeRunGuid"].ToString(), //CreateTime = row["CreateTime"].ToString(), //DeleteTime = row["DeleteTime"].ToString(), Description = row["Description"].ToString(), ProcessBeginTime = row["ProcessBeginTime"].ToString(), ProcessEndTime = row["ProcessEndTime"].ToString(), ProcessIn = row["ProcessIn"].ToString(), RecipeName = row["RecipeName"].ToString(), SusceptorId = row["SusceptorId"].ToString(), UserDefinedId = row["UserDefinedId"].ToString(), SusceptorStatus = susceptorStatusString, WaferOnSusceptor = row["WafersOnSusceptor"].ToString() }); } } } catch (Exception ex) { CONTEXT.WriteLog(ex, string.Format("获取{0}~{1}期间,{2}处理,工艺程序为{3}的石墨盘记录发生错误", begin, end, processIn, recipeName)); } return ret; } #endregion #region get equipment data from database /// /// get data from PostgreSQL database /// /// /// /// /// /// /// public bool GetDbData(string chamId, DateTime from, DateTime to, IEnumerable dataIdList, out Dictionary returnDatas) { returnDatas = new Dictionary(); for (DateTime dfrom = new DateTime(from.Year, from.Month, from.Day); dfrom < to; dfrom += new TimeSpan(1, 0, 0, 0)) { DateTime begin = (dfrom.Year == from.Year && dfrom.Month == from.Month && dfrom.Day == from.Day) ? from : new DateTime(dfrom.Year, dfrom.Month, dfrom.Day, 0, 0, 0, 0); DateTime end = (dfrom.Date == to.Date) ? to : new DateTime(dfrom.Year, dfrom.Month, dfrom.Day, 23, 59, 59, 999); //if (begin.Date > DateTime.Today) // continue; try { string sql = "select time AS InternalTimeStamp"; foreach (var dataId in dataIdList) { if (!returnDatas.Keys.Contains(dataId) && !dataId.Contains("PM.VirtualDevice")) { returnDatas.Add(dataId, new DataItem() { DataName = dataId, RawData = new List(), TimeStamp = new List() }); sql += "," + string.Format("\"{0}\"", dataId); } } sql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc;", begin.ToString("yyyyMMdd") + "." + chamId.ToString(), begin.Ticks, end.Ticks); using (var dataSet = ExecuteDataset(sql)) { if (dataSet.Tables.Count == 0 || dataSet.Tables[0].Rows.Count == 0) continue; DateTime dt = new DateTime(); Dictionary colName = new Dictionary(); for (int colNo = 0; colNo < dataSet.Tables[0].Columns.Count; colNo++) colName.Add(colNo, dataSet.Tables[0].Columns[colNo].ColumnName); for(int rowNo = 0 ; rowNo < dataSet.Tables[0].Rows.Count; rowNo++) { var row = dataSet.Tables[0].Rows[rowNo]; for (int i = 0; i < dataSet.Tables[0].Columns.Count; i++) { if (i == 0) { long ticks = (long)row[i]; dt = new DateTime(ticks); } else { string dataId = colName[i]; if (row[i] is DBNull || row[i] == null) { returnDatas[dataId].RawData.Add(0);// ds.Data[].Add(new KeyValuePair(dt, 0)); returnDatas[dataId].TimeStamp.Add(dt); } else if (row[i] is bool) { //ds.Data[reader.GetName(i)].Add(new KeyValuePair(dt, (bool)reader[i] ? 1 : 0)); returnDatas[dataId].RawData.Add((bool)row[i] ? 1 : 0); returnDatas[dataId].TimeStamp.Add(dt); } else { //ds.Data[reader.GetName(i)].Add(new KeyValuePair(dt, float.Parse(reader[i].ToString()))); returnDatas[dataId].RawData.Add(float.Parse(row[i].ToString())); returnDatas[dataId].TimeStamp.Add(dt); } } } } dataSet.Clear(); GC.Collect(); } } catch (Exception ex) { CONTEXT.WriteLog(ex); return false; } } return true; } /// /// Read data name list from database /// /// /// /// /// public void ReadDbDataNameList(DateTime beginTime, string whichCham, out string reason, out List dataList, out Dictionary>> virtualDeviceList) { dataList = new List(); virtualDeviceList = new Dictionary>>(); reason = string.Empty; try { string tblName = beginTime.ToString("yyyyMMdd.") + whichCham; //query if table already exist? string sqlTblDefine = string.Format("select cols.column_name, (select pg_catalog.obj_description(oid) from pg_catalog.pg_class c where c.relname=cols.table_name) as table_comment ,(select pg_catalog.col_description(oid,cols.ordinal_position::int) from pg_catalog.pg_class c where c.relname=cols.table_name) as column_comment from information_schema.columns cols where cols.table_name='{0}';", tblName); using (var dataSet = ExecuteDataset(sqlTblDefine)) { for(int i= 0; i < dataSet.Tables[0].Rows.Count;i++) dataList.Add(dataSet.Tables[0].Rows[i]["column_name"].ToString()); } //if table exists, add virtual device datas if (dataList.Count > 0) { string sqlVirtualTblDefine = string.Format("SELECT \"DeviceName\", \"FunctionBlock\" FROM \"VirtualDevice\" where \"ChamberID\" = '{0}';", whichCham); bool isAny = false; using (var dataSet = ExecuteDataset(sqlVirtualTblDefine)) { for (int i = 0; i < dataSet.Tables[0].Rows.Count; i++) { var virtualDeviceName = "PM.VirtualDevice." + dataSet.Tables[0].Rows[i]["DeviceName"].ToString(); var functionBlock = dataSet.Tables[0].Rows[i]["FunctionBlock"].ToString(); var varList = new List(); var collection = Regex.Matches(functionBlock, @"PM(\.\w+)+"); foreach(var item in collection) { varList.Add(item.ToString()); } isAny = true; dataList.Add(virtualDeviceName); virtualDeviceList.Add(virtualDeviceName, new Tuple>(functionBlock, varList)); } } if (!isAny) { dataList.Add("PM.VirtualDevice"); } } } catch (Exception ex) { reason = ex.Message; CONTEXT.WriteLog(ex, string.Format("获取{0} {1}数据库变量名列表发生异常", whichCham, beginTime.ToString("yyyy/MM/dd HH:mm:ss"))); } } #region 获取wafer显示顺序 /// /// 获取wafer显示顺序 /// /// public string GetWaferDisplayIndex(DateTime startTime, string ProcessIn) { string result = string.Empty; try { string sql = string.Format("SELECT \"DisplayIndex\" FROM \"WaferDisplayIndex\" WHERE \"Id\" =( SELECT \"RecipeRunGuid\" FROM \"RecipeRunHistory\" where to_char(\"ProcessBeginTime\",'yyyy-MM-DD HH24:MI:SS') = '{0}' and \"ProcessIn\"='{1}');", startTime.ToString("yyyy-MM-dd HH:mm:ss"), ProcessIn); using (var dataSet = ExecuteDataset(sql)) { if (dataSet.Tables[0].Rows.Count > 0) { result = dataSet.Tables[0].Rows[0]["DisplayIndex"].ToString(); } } } catch (System.Exception ex) { CONTEXT.WriteLog(ex, "数据库读取wafer排序信息失败"); //result = "60,61,62,63,64,65,66,47,48,49,50,51,52,53,54,55,56,57,58,59,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26"; } return result; } /// /// 获取wafer映射表 /// public string WaferDisplayIndex { get; set; } #endregion #endregion } }