using HMI.Base; using HMI.Core.Setting; using HMI.Core.Util; using HMI.LogUtil; using HMI.UI.Util; using HMI.Util; using Plugin.TestResult; using Plugin.TestResult.Util; using Plugin.TestResult_WPF.Model; using Plugin.TsSupport; using SuperSocket.SocketBase.Config; using SuperSocket.SocketBase.Protocol; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Runtime.CompilerServices; using System.Timers; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; 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 ushort coolerStatus; public ushort CoolerStatus { get => coolerStatus; set { RaiseAndSetIfchanged(ref coolerStatus, 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); } } public int index { get; private set; } public readonly int cellCount; private readonly string chartTitle; public readonly TestResultView parent; private BaseConfig config; private LiveChart chart; private LiveChart multiChart; public SingleCell[] cells { get; private set; } 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 = this.lang("Tr.AvgTemp"); DataContext = this; InitializeComponent(); mainGrid.Columns = config.PositionColumn; this.chart = new LiveChart("平均温度,平均温度(℃)", false, true); this.multiChart = new LiveChart(",详细温度(℃)", true) { 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; } ScannerParser.Init(config.CodeParserType); ReadCount(); testTimeTimer = new Timer(); testTimeTimer.Interval = 10000; testTimeTimer.AutoReset = true; testTimeTimer.Elapsed += TestTimeTimer_Elapsed; if (!ParamSetting.ShowCoolerSetting) coolerSetting.Visibility = Visibility.Collapsed; if (!ParamSetting.ShowBurnInAbort) abortBtn.Visibility = Visibility.Collapsed; } 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.AddDynamicData("平均温度", "平均温度(℃)", DateTime.Now, 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.AddDynamicData(name, "详细温度(℃)", DateTime.Now, 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; // infoTable.UpdateConsumeTime((now - testStartTime).Value.TotalSeconds, null); // 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 UpdateConsumeTime(double consumeTime, double? leftTime) { infoTable.UpdateConsumeTime(consumeTime, leftTime); } 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(this.lang("Tr.MakeSureStopOvenTest", title)) == MessageBoxResult.OK) { LogHelper.Info("UI", $"老化炉[{title}]停止按钮按下", out _); ViewControl.Logger.Info($"老化炉[{title}]停止按钮按下"); parent.SetStartFlag(this.index, false); } } else { /// 检查是否关门 if (!GetDoorClose(parent.executionWrapper)) { /// 没关门不允许启动 MsgBoxHelper2.Warn("请先关闭舱门!"); return; } /// 检查是否有条码 bool flag = false; foreach (var cell in cells) { if (!string.IsNullOrEmpty(cell.sn)) { flag = true; break; } } if (flag) { LogHelper.Info("UI", $"老化炉[{title}]启动按钮按下", out _); ViewControl.Logger.Info($"老化炉[{title}]启动按钮按下"); ClearChartData(); parent.SetStartFlag(this.index, true); } else { MsgBoxHelper2.Warn("请先完成扫码!"); } } } private void ScanWindow_Click(object sender, RoutedEventArgs e) { if (!parent.IsRunning) { MsgBoxHelper.WarnMessage(this, this.lang("Tr.StartSeqFirst"), null, MessageBoxButton.OK); return; } if (scanner != null) { scanner.ShowDialog(); } else { int rows = config.CellCount / config.PositionColumn + 1; scanner = new Scanner(this.index, this.lang("Tr.ScanTitle", title), CbProduct.SelectedItem?.ToString(), mainGrid.Columns, rows) { 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.executionWrapper.SetStationGlobalValue(paramName, 1, true); //parent.engine.Globals.SetValBoolean(paramName, 1, true); } private void Scanner_Closed(object sender, EventArgs e) { scanner = null; } public bool GetDoorClose(ITestExecutionWrapper wrapper) { return wrapper?.GetStationGlobalValue($"StationState.DoorClose[{this.index}]", 0) == true; } private void Scanner_FinishBarcode(object sender, BarcodeEventArg e) { if (parent.executionWrapper == null) return; //if (parent.SequenceContext == null) return; int rows = (config.CellCount / config.PositionColumn) + 1; CellInfo cellInfo = ScannerParser.GetCellInfoByCode(CbProduct.SelectedItem?.ToString(), mainGrid.Columns, rows, e.positionCode); string positionCode = e.positionCode, snrCode = e.snrCode; //if (cellInfo.OvenName != this.title) //{ // MsgBoxHelper2.Warn($"请切换至 [{cellInfo.OvenName}] 区扫码,当前为 [{this.title}] 区!"); // return; //} var targetTable = TestResultView.nameTables[cellInfo.OvenName]; //将读到的条码写入到SN中 int dutNo = targetTable.index * targetTable.cellCount + cellInfo.Index; string LookupStr = $"StationState.SN[{dutNo}]"; cellInfo.LookUpStr = LookupStr; ViewControl.Logger.Info($"PositionCode: [{e.positionCode}], SNR: [{e.snrCode}], LookUpStr: [{LookupStr}]"); ViewControl.Logger.Info($"OvenName: [{cellInfo.OvenName}], CellIndex: [{cellInfo.Index}]"); var cell = targetTable.GetSingleCell(cellInfo.Index); if (targetTable.GetDoorClose(parent.executionWrapper)) { /// 关门了就不允许清条码 MsgBoxHelper2.Warn($"{targetTable.title}炉生产中,不允许操作条码"); //MsgBoxHelper2.Warn(this.lang("Tr.CantClearSNR")); return; } if (snrCode == null) { var oldCellInfo = e.lastInfo; var oldTable = TestResultView.nameTables[oldCellInfo.OvenName]; var oldCell = oldTable.GetSingleCell(oldCellInfo.Index); if (oldCell.status != "hadCode") { throw new Exception(this.lang("Tr.PositionCantClearSNR", oldCellInfo.OriginCode)); } // 移除条码 parent.executionWrapper.SetStationGlobalValue(oldCellInfo.LookUpStr, 1, ""); parent.executionWrapper.CommitToDisk(false); //parent.engine.Globals.SetValString(oldCellInfo.LookUpStr, 1, ""); //parent.engine.CommitGlobalsToDisk(promptOnSaveConflicts: false); oldCell.SetStatus("waiting"); oldCell.ClearSN(); return; } /// 清掉上个条码的记录 var lastSn = cell.sn; if (!string.IsNullOrEmpty(lastSn)) { Scanner.RemoveSNR(lastSn); } // 写入条码 parent.executionWrapper.SetStationGlobalValue(LookupStr, 1, snrCode); parent.executionWrapper.CommitToDisk(false); //parent.engine.Globals.SetValString(LookupStr, 1, snrCode); //parent.engine.CommitGlobalsToDisk(promptOnSaveConflicts: false); cell.SetStatus("hadCode"); cell.sn = snrCode; Scanner.InsertNewCode(snrCode, cellInfo); cell.LightGreen(true, out string msg); } /// /// 清空两个图表数据 /// 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(','); Dispatcher.Invoke(() => { 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); if (ParamSetting.ProbeByModel) { } else { 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) + "," + this.lang("Tr.AvgTemp"); 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, ""); } foreach (var cell in cells) { cell.RefreshProbe(); cell.RefreshCharts(); } } public void ClearCellData() { foreach (var cell in cells) { cell.ClearChart(); } } //public void ClearElectricData() //{ // foreach (var cell in cells) // { // cell.ClearElectricData(); // } //} //public void ClearVData() //{ // foreach (var cell in cells) // { // cell.ClearVData(); // } //} //public void ClearWaterData() //{ // foreach (var cell in cells) // { // cell.ClearWaterData(); // } //} private void Button_Click_1(object sender, RoutedEventArgs e) { ScannerSetting setting = new ScannerSetting() { Owner = Window.GetWindow(this) }; setting.Open(true, this.title); } private void Manual_Cooler_Opt(object sender, RoutedEventArgs e) { //var btn = (Button)sender; //var target = CoolerStatus == 2 ? 0 : 2; //if (MsgBoxHelper2.WarnChoose($"确定要进行{btn.Content}吗?") == MessageBoxResult.OK) //{ // if (S7Context.WriteData("1", $"Oven{index + 1}_CoolerStatus", (ushort)target, out string msg)) // { // CoolerStatus = (ushort)target; // ToastHelper.Success("Success"); // } // else // { // ToastHelper.Error($"{msg}"); // } //} if (parent.IsRunning) { MsgBoxHelper2.Warn(this.lang("Tr.CantOptCooler")); return; } var columns = mainGrid.Columns; var window = new CoolerStatus(this.index, columns, title + this.lang("Tr.CoolerSetting")) { Owner = Window.GetWindow(this) }; window.ShowDialog(); } private void ClearAllSnr_Click(object sender, RoutedEventArgs e) { if (GetDoorClose(parent.executionWrapper)) { /// 关门了就不允许清条码 MsgBoxHelper2.Warn(this.lang("Tr.CantClearSNR")); 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) { if (GetDoorClose(parent.executionWrapper)) { MsgBoxHelper.Error(Window.GetWindow(this), this.lang("Tr.CantClearSNR")); 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.SetStatus("waiting"); parent.executionWrapper.SetStationGlobalValue(LookupStr, 1, ""); parent.executionWrapper.CommitToDisk(false); //parent.engine.Globals.SetValString(LookupStr, 1, ""); //parent.engine.CommitGlobalsToDisk(promptOnSaveConflicts: false); if (!string.IsNullOrEmpty(lastSN)) Scanner.RemoveSNR(lastSN); cell.ClearSN(); } private void Abort_Click(object sender, RoutedEventArgs e) { if (!parent.IsRunning) { MsgBoxHelper.WarnMessage(this, this.lang("Tr.StartSeqFirst"), null, MessageBoxButton.OK); return; } //string key = $"StationState.Start[{this.index}]"; //if (parent.executionWrapper?.GetStationGlobalValue(key, 0) == true) //{ // MsgBoxHelper2.Warn("测试启动中,不允许Abort"); // return; //} var win = new RequirePasswordByUser("admin") { Owner = Window.GetWindow(this) }; if (win.ShowDialog() != true) { return; } if (MsgBoxHelper2.WarnChoose("请确认老化仓在安全温度,水冷机吹水完成,单击OK按钮仓位回到初始化状态") != MessageBoxResult.OK) { return; } LogHelper.Info("UI", $"{title} Abort按钮按下", out _); ViewControl.Logger.Info($"{title} Abort按钮按下"); string key = $"StationState.Abort[{this.index}]"; parent.executionWrapper?.SetStationGlobalValue(key, 0, true); } } }