using HMI.Core.Util; using HMI.UI.Util; using HMI.Util; using Plugin.TestResult; using Plugin.TestResult.Util; using Plugin.TestResult_WPF.Model; using Plugin.TestResult_WPF.Util; using SuperSocket.SocketBase.Config; using SuperSocket.SocketBase.Protocol; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Net.WebSockets; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Timers; using System.Windows; using System.Windows.Controls; namespace Plugin.TestResult_WPF { /// /// DataTable.xaml 的交互逻辑 /// public partial class DataTable : UserControl, INotifyPropertyChanged { #region ... public event PropertyChangedEventHandler PropertyChanged; public virtual void RaisePropertyChanged(string name) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } public void RaiseAndSetIfchanged(ref T old, T @new, [CallerMemberName] string propertyName = null) { old = @new; if (propertyName != null) RaisePropertyChanged(propertyName); } #endregion private string _title; public string title { get { return _title; } set => RaiseAndSetIfchanged(ref _title, value); } private string _statusText; public string statusText { get { return _statusText; } set => RaiseAndSetIfchanged(ref _statusText, value); } private bool _isTesting; public bool IsTesting { get { return _isTesting; } set => RaiseAndSetIfchanged(ref _isTesting, value); } private string tcpServerStatus; public string TcpServerStatus { get { return tcpServerStatus; } set { RaiseAndSetIfchanged(ref tcpServerStatus, value); } } private string tcpServerInfo = LangUtil.Get("App.NotStarted"); public string TcpServerInfo { get { return tcpServerInfo; } set { RaiseAndSetIfchanged(ref tcpServerInfo, value); } } private static ICodeParser codeParser; private readonly int index; private readonly int cellCount; private readonly string chartTitle; private readonly TestResultView parent; private BaseConfig config; private Chart chart; private Chart multiChart; private SingleCell[] cells; private TcpServer tcpServer; private string CountIniPath; private DateTime? testStartTime; private Timer testTimeTimer; // 平均温度 public List tempratures = new List(); public Dictionary> detailTempratures = new Dictionary>(); public DataTable(TestResultView parent, int index, string title, string countIniPath, BaseConfig config) { this.CountIniPath = countIniPath; this.config = config; this.index = index; this.parent = parent; this.title = title; this.cellCount = config.PositionCount; this.cells = new SingleCell[cellCount]; this.chartTitle = config.MainChartTitle; DataContext = this; InitializeComponent(); mainGrid.Columns = config.PositionColumn; this.chart = new Chart(this.chartTitle, false, config.MaxSize, config.RefreshInterval); this.multiChart = new Chart(config.DetailChartTitle, true, config.MaxSize, config.RefreshInterval) { BorderThickness = new Thickness(0) }; this.grid.Children.Add(this.chart); Grid.SetRow(this.chart, 2); this.chart.MouseDoubleClick += chart_MouseDoubleClick; for (int i = 0; i < this.cellCount; i++) { var cellRow = (i / config.PositionColumn) + 1; var cellCol = (i % config.PositionColumn) + 1; var cellTitle = $"{title}-{cellRow}-{cellCol}"; var cell = new SingleCell(this, cellTitle, i, config.CellListMaxSize, countIniPath); mainGrid.Children.Add(cell); cells[i] = cell; } if (config.CodeParserType == "JK01") { codeParser = new JKCodeParser(); } else { codeParser = new CommonCodeParser(); } ReadCount(); testTimeTimer = new Timer(); testTimeTimer.Interval = 10000; testTimeTimer.AutoReset = true; testTimeTimer.Elapsed += TestTimeTimer_Elapsed; } private void TestTimeTimer_Elapsed(object sender, ElapsedEventArgs e) { if (testStartTime == null) return; var now = DateTime.Now; Dispatcher.BeginInvoke(new Action(() => { SetConsumeTime((now - testStartTime).Value.TotalSeconds); })); } public int GetSize() { return this.cellCount; } public SingleCell GetSingleCell(int index) { return cells[index]; } public void SetStatusText(string statusText) { this.statusText = statusText; } public void SetTemperature(double t) { infoTable.temperature = t; tempratures.Add(t); chart.AddData(t); } public void SetTemperature(string name, double t) { List list; if (detailTempratures.ContainsKey(name)) { list = detailTempratures[name]; } else { list = new List(); detailTempratures.Add(name, list); } list.Add(t); multiChart.AddData(name, t); } public void SetStatus(string status) { ViewControl.Logger.Debug($"In Status: {status}"); Dispatcher.BeginInvoke(new Action(() => { var lastStatus = infoTable.status; if (status == "preCheck") { ViewControl.Logger.Debug($"In preCheck"); IsTesting = true; return; } if (status == "stop") { IsTesting = false; return; } if (status == "abort") { IsTesting = false; } infoTable.status = status; if (lastStatus != "testing" && status == "testing") { testStartTime = DateTime.Now; SetStartTime(testStartTime?.ToString("yyyy-MM-dd HH:mm:ss")); testTimeTimer.Start(); } if (lastStatus == "testing" && status != "testing") { testTimeTimer.Stop(); var now = DateTime.Now; SetConsumeTime((now - testStartTime).Value.TotalSeconds); SetEndTime(now.ToString("yyyy-MM-dd HH:mm:ss")); testStartTime = null; } })); } public void SetOkCount(int count) { infoTable.okCount = count; } public void SetNgCount(int count) { infoTable.ngCount = count; } public void SetStartTime(string startTime) { infoTable.startTimeStr = startTime; } public void SetEndTime(string endTime) { infoTable.endTimeStr = endTime; } public void SetConsumeTime(double consumeTime) { infoTable.consumeTime = consumeTime; } private ChartWindow window; private void chart_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e) { /// 打开多个温度曲线 if (window == null) { window = new ChartWindow(title); window.Owner = Window.GetWindow(this); window.Closed += Window_Closed; window.mainGrid.Children.Add(multiChart); window.Show(); } else { window.Activate(); } } private Scanner scanner; private void Window_Closed(object sender, EventArgs e) { window = null; } private void SetStationGlobal_Click(object sender, RoutedEventArgs e) { } private void StartSingleClick(object sender, RoutedEventArgs e) { if (IsTesting) { if (MsgBoxHelper2.WarnChoose($"确实停止老化炉[{title}]的测试吗") == MessageBoxResult.OK) { parent.SetStartFlag(this.index, false); } } else { ClearChartData(); parent.SetStartFlag(this.index, true); } } private void ScanWindow_Click(object sender, RoutedEventArgs e) { if (!parent.IsRunning) { MsgBoxHelper.WarnMessage(this, "请先点击右侧启动按钮启动测试程序!", null, MessageBoxButton.OK); return; } if (scanner != null) { scanner.ShowDialog(); } else { scanner = new Scanner(this.lang("Tr.ScanTitle", title)) { Owner = Window.GetWindow(this), Tag = title }; scanner.FinishBarcode += Scanner_FinishBarcode; scanner.ComplateClick += Scanner_ComplateClick; ; scanner.Closed += Scanner_Closed; scanner.ShowDialog(); } } private void Scanner_ComplateClick(object sender, RoutedEventArgs e) { string paramName = $"StationState.Scanner[{index}]"; parent.engine.Globals.SetValBoolean(paramName, 1, true); //parent.engine.CommitGlobalsToDisk(promptOnSaveConflicts: false); } private void Scanner_Closed(object sender, EventArgs e) { scanner = null; } private void Scanner_FinishBarcode(object sender, BarcodeEventArg e) { if (parent.SequenceContext == null) return; CellInfo cellInfo = codeParser.GetCellInfoByCode(e.positionCode); string positionCode = e.positionCode, snrCode = e.snrCode; //将读到的条码写入到SN中 int dutNo = this.index * this.cellCount + cellInfo.Index; string LookupStr = $"StationState.SN[{dutNo}]"; ViewControl.Logger.Debug($"PositionCode: [{e.positionCode}], SNR: [{e.snrCode}], LookUpStr: [{LookupStr}]"); ViewControl.Logger.Debug($"OvenName: [{cellInfo.OvenName}], CellIndex: [{cellInfo.Index}]"); var cell = parent.nameTables[cellInfo.OvenName].GetSingleCell(cellInfo.Index); if (snrCode == null) { string oldLookUp = $"StationState.SN[{e.oldIndex}]"; var oldCellInfo = codeParser.GetCellInfoByCode(e.oldPosition); var oldCell = parent.nameTables[oldCellInfo.OvenName].GetSingleCell(oldCellInfo.Index); if (oldCell.status != "hadCode") { throw new Exception($"穴位[{e.oldPosition}]当前不允许清除条码!"); } // 移除条码 parent.engine.Globals.SetValString(oldLookUp, 1, ""); parent.engine.CommitGlobalsToDisk(promptOnSaveConflicts: false); oldCell.SetStatus("waiting"); oldCell.sn = ""; return; } /// 清掉上个条码的记录 var lastSn = cell.sn; if (!string.IsNullOrEmpty(lastSn)) { Scanner.RemoveSNR(lastSn); } // 写入条码 parent.engine.Globals.SetValString(LookupStr, 1, snrCode); parent.engine.CommitGlobalsToDisk(promptOnSaveConflicts: false); parent.nameTables[cellInfo.OvenName].GetSingleCell(cellInfo.Index).SetStatus("hadCode"); parent.nameTables[cellInfo.OvenName].GetSingleCell(cellInfo.Index).sn = snrCode; Scanner.InsertNewCode(snrCode, positionCode, dutNo); } /// /// 清空两个图表数据 /// public void ClearChartData() { chart.Clear(); multiChart.Clear(); tempratures.Clear(); detailTempratures.Clear(); } /// /// 启动Tcp服务器 /// private void StartTcpServer() { var serverConfig = new ServerConfig() { MaxRequestLength = 1024 * 1024, Port = config.PortStart + index }; try { if (tcpServer == null) { tcpServer = new TcpServer(); tcpServer.NewRequestReceived += TcpServer_NewRequestReceived; if (!tcpServer.Setup(serverConfig)) { ChangeTcpServerStatus("ERROR", this.lang("Tr.TcpServer.SettingFailed")); return; } if (!tcpServer.Start()) { ChangeTcpServerStatus("ERROR", this.lang("Tr.TcpServer.StartFailed")); return; } ChangeTcpServerStatus("RUNNING", this.lang("Tr.TcpServer.Running")); } else if (tcpServer.State != SuperSocket.SocketBase.ServerState.Running) { if (!tcpServer.Setup(serverConfig)) { ChangeTcpServerStatus("ERROR", this.lang("Tr.TcpServer.SettingFailed")); return; } if (!tcpServer.Start()) { ChangeTcpServerStatus("ERROR", this.lang("Tr.TcpServer.StartFailed")); return; } ChangeTcpServerStatus("RUNNING", this.lang("Tr.TcpServer.Running")); } } catch (Exception ex) { ChangeTcpServerStatus("ERROR", $"{ex.Message}"); tcpServer?.Stop(); tcpServer = null; } } /// /// 更新Tcp服务器状态 /// /// /// private void ChangeTcpServerStatus(string status, string info) { Dispatcher.Invoke(() => { TcpServerStatus = status; TcpServerInfo = info; }); } /// /// 停止Tcp服务器 /// private void StopTcpServer() { try { tcpServer?.Stop(); tcpServer = null; } catch (Exception ex) { } } /// /// 释放资源 /// public void RelaseResource() { testTimeTimer?.Stop(); StopTcpServer(); } /// /// Tcp消息处理 /// /// /// private void TcpServer_NewRequestReceived(TcpSession session, StringRequestInfo requestInfo) { string msg = requestInfo.Body; ViewControl.Logger.Debug($"TCP Data From {session.RemoteEndPoint}: {msg}."); string[] datas_10015 = msg.Split(';'); int cellIndex = int.Parse(datas_10015[1]); string strs = datas_10015[2]; string[] values = strs.Split(','); //string step = datas_10015[2]; //string result = datas_10015[3]; GetSingleCell(cellIndex).SetInfos(new Info { step = values[0], value = values[1], limitUp = values[2], limitDown = values[3], unit = values[4], result = values[5], updateTime = values[6] }); //session.Send("1"); } public void RefreshCount(int ok, int ng) { infoTable.UpdateNumber(infoTable.okCount + ok, infoTable.ngCount + ng); IniFileHelper.WriteIniData($"Oven_{index}", "Pass", infoTable.okCount.ToString(), this.CountIniPath); IniFileHelper.WriteIniData($"Oven_{index}", "Fail", infoTable.ngCount.ToString(), this.CountIniPath); } /// /// 读取保存的数据 /// public void ReadCount() { try { int ok = Convert.ToInt32(IniFileHelper.ReadIniData($"Oven_{index}", "Pass", "", CountIniPath)); int ng = Convert.ToInt32(IniFileHelper.ReadIniData($"Oven_{index}", "Fail", "", CountIniPath)); infoTable.UpdateNumber(ok, ng); } catch (Exception ex) { //do nothing } } /// /// 计数清零 /// public void ClearNumber() { infoTable.UpdateNumber(0, 0); IniFileHelper.WriteIniData($"Oven_{index}", "Pass", infoTable.okCount.ToString(), this.CountIniPath); IniFileHelper.WriteIniData($"Oven_{index}", "Fail", infoTable.ngCount.ToString(), this.CountIniPath); } private void UserControl_Loaded(object sender, RoutedEventArgs e) { StartTcpServer(); Loaded -= UserControl_Loaded; } private void Button_Click(object sender, RoutedEventArgs e) { StartTcpServer(); } public void SaveTempFile(string filePath) { try { FileInfo fi = new FileInfo(filePath); if (!fi.Directory.Exists) { fi.Directory.Create(); //文件不存在,创建文件 } using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8)) { string title = string.Join(",", detailTempratures.Keys) + ",平均值"; sw.WriteLine(title); for (int i = 0; i < tempratures.Count; i++) { string line = ""; foreach (string key in detailTempratures.Keys) { if (detailTempratures[key] == null || detailTempratures[key].Count <= i) { line += ","; } else { line += $"{detailTempratures[key][i]},"; } } line += tempratures[i]; sw.WriteLine(line); } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } public void SetProductSource(List productSource) { CbProduct.ItemsSource = productSource; } public void SetCurrentProduct(string currentProduct) { CbProduct.SelectedItem = currentProduct; } private void CbProduct_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (e.AddedItems.Count > 0) { var str = e.AddedItems[0]; parent.SetOvenProduct(index, str.ToString()); } else { parent.SetOvenProduct(index, ""); } } public void ClearElectricData() { foreach (var cell in cells) { cell.ClearElectricData(); } } public void ClearVData() { foreach (var cell in cells) { cell.ClearVData(); } } private void Button_Click_1(object sender, RoutedEventArgs e) { ScannerSetting setting = new ScannerSetting() { Owner = Window.GetWindow(this) }; setting.Open(true, this.title); } private void ClearAllSnr_Click(object sender, RoutedEventArgs e) { var str = $"StationState.DoorClose[{index}]"; if (parent.engine.Globals.GetValBoolean(str, 0) == true) { MsgBoxHelper.Error(Window.GetWindow(this), "程序运行中,不能清空条码"); return; } if (MsgBoxHelper.WarnMessage(Window.GetWindow(this), LangUtil.Get("Tr.MakeSureClearAllSNR")) == MessageBoxResult.OK) { try { ClearAllSN(); ToastHelper.Success(LangUtil.Get("App.DeleteSuccess")); } catch (Exception ex) { ViewControl.Logger.Error("ClearAllSnr_Click Error.", ex); MsgBoxHelper.Error(Window.GetWindow(this), ex.Message); } } } public void ClearAllSN() { for (int i = 0; i < this.cellCount; i++) { ClearCellSN(i); } } public void TryClearCellSN(int cellIndex) { var str = $"StationState.DoorClose[{this.index}]"; if (parent.engine.Globals.GetValBoolean(str, 0) == true) { MsgBoxHelper.Error(Window.GetWindow(this), "程序运行中,不能清空条码"); return; } ClearCellSN(cellIndex); } private void ClearCellSN(int index) { var cell = GetSingleCell(index); int dutNo = this.index * this.cellCount + index; string LookupStr = $"StationState.SN[{dutNo}]"; var lastSN = cell.sn; cell.sn = ""; cell.SetStatus("waiting"); parent.engine.Globals.SetValString(LookupStr, 1, ""); parent.engine.CommitGlobalsToDisk(promptOnSaveConflicts: false); if (!string.IsNullOrEmpty(lastSN)) Scanner.RemoveSNR(lastSN); } private void Button_Click_2(object sender, RoutedEventArgs e) { if (MsgBoxHelper.WarnMessage(Window.GetWindow(this), "确定要停止该炉位的老化测试吗?") == MessageBoxResult.OK) { parent.SetStartFlag(this.index, false); } } } }