using HMI.Core.Entity; using HMI.Core.Manager; using HMI.Core.Setting; using HMI.Core.Util; using HMI.UI.Util; using HMI.Util; using NationalInstruments.TestStand.Interop.API; using Plugin.StandardTest.Entity; using Plugin.StandardTest.Setting; using SuperSocket.SocketBase.Config; using SuperSocket.SocketBase.Protocol; using System.Collections; using System.Collections.ObjectModel; using System.ComponentModel; using System.Configuration; using System.IO; using System.Runtime.CompilerServices; using System.Timers; using System.Windows; using System.Windows.Controls; using Util.ManualDebug; namespace Plugin.StandardTest { /// /// SingleControl.xaml 的交互逻辑 /// public partial class SingleControl : UserControl, INotifyPropertyChanged { #region ... public event PropertyChangedEventHandler PropertyChanged; protected void Set([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } protected void Set(ref T old, T @new, [CallerMemberName] string propertyName = null) { old = @new; if (propertyName != null) { Set(propertyName); } } #endregion private int index; private string CountIniPath; private string status = "Ready"; private ScreenTouch[] screens; private ScreenGrid screenGrid; public string Status { get { return status; } set { Set(ref status, value); } } private double totalNum; public double TotalNum { get => totalNum; private set { Set(ref totalNum, value); } } public StandardTestUI parent { get; set; } private int passNum; public int PassNum { get => passNum; private set { Set(ref passNum, value); } } private int failNum; public int FailNum { get => failNum; private set { Set(ref failNum, value); } } private double passRate; public double PassRate { get => passRate; private set { Set(ref passRate, value); } } public string NumInfo { get => this.lang("Ts.NumInfo", TotalNum, PassNum, FailNum, string.Format("{0:0.00}", PassRate)); } public string TestInfo { get => this.lang("Ts.TestInfo", Barcode, ElapseTime); } private string barcode = string.Empty; public string Barcode { get { return barcode; } set { Set(ref barcode, value); } } private string model = string.Empty; public string Model { get { return model; } set { Set(ref model, value); } } private string elapseTime = "00:00:00"; public string ElapseTime { get { return elapseTime; } set { if (value == "Start Timing") { this.refreshTimer.Enabled = true; TestStartTime = DateTime.Now; StepStartTime = DateTime.Now; } else { this.refreshTimer.Enabled = false; if (value != "Stop Timing") { Set(ref elapseTime, value + "s"); Set("TestInfo"); } } } } private string socketName = string.Empty; public string SocketName { get { return socketName; } set { Set(ref socketName, value); } } private ObservableCollection _datasource = new ObservableCollection(); public ObservableCollection Datasource { get => _datasource; set { Set(ref _datasource, value); } } private DateTime TestStartTime = new DateTime(); private DateTime StepStartTime = new DateTime(); private TimeSpan TimeCount = new TimeSpan(); private System.Timers.Timer refreshTimer; private string currentStep = ""; public string CurrentStep { get => currentStep; set { Set(ref currentStep, value); } } private int _probeCount; public int ProbeCount { get => _probeCount; set { Set(ref _probeCount, value); try { if (ProbeWarn <= 0) probeCountAlarm.Visibility = Visibility.Collapsed; else if (value >= ProbeWarn) probeCountAlarm.Visibility = Visibility.Visible; else probeCountAlarm.Visibility = Visibility.Collapsed; } catch { } } } /// /// 进度值 /// private int _processValue; public int ProcessValue { get => _processValue; set { Set(ref _processValue, value); } } public string ProcessValueLabel { get { if (ProcessValue > 0) return $"{ProcessValue}%"; return ""; } set { } } public void SetSimpleUI(bool flag) { if (flag) { simplePanel.Visibility = Visibility.Visible; detailPanel.Visibility = Visibility.Collapsed; } else { simplePanel.Visibility = Visibility.Collapsed; detailPanel.Visibility = Visibility.Visible; } } private int _probeWarn; public int ProbeWarn { get => _probeWarn; private set { Set(ref _probeWarn, value); } } private bool isAutoMode; public bool IsAutoMode { get => isAutoMode; set { Set(ref isAutoMode, value); } } public SingleControl(int Index, string CountIniPath, int probeWarn) { DataContext = this; this.CountIniPath = CountIniPath; this.index = Index; ProbeWarn = probeWarn; refreshTimer = new System.Timers.Timer() { Interval = 100 }; refreshTimer.Elapsed += RefreshTimer_Elapsed; ReadCounter(); InitializeComponent(); RefreshProbeCount(null); try { var value = ParameterManager.GetCommonParameterByName("AutoTestMode"); IsAutoMode = bool.Parse(value.Value); } catch { IsAutoMode = true; } } private void RefreshTimer_Elapsed(object sender, ElapsedEventArgs e) { TimeCount = DateTime.Now - TestStartTime; elapseTime = string.Format("{0:00}:{1:00}:{2:00}", TimeCount.Hours, TimeCount.Minutes, TimeCount.Seconds); Set("ElapseTime"); Set("TestInfo"); } /// /// 获取TS的每步测试的数据添加到表格 /// 项目名称,测试参数,测试值,上限,下限,单位,结果 /// /// public void AddTestData(string name, string step_name, string value, string HightLimit, string LowLimit, string unit, string Status) { try { var data = new TestStep { Name = name, Step = step_name, Value = value, LimitUp = HightLimit, LimitDown = LowLimit, Unit = unit, Result = Status }; table.Dispatcher.Invoke(new Action(() => { var now = DateTime.Now; var span = now - StepStartTime; StepStartTime = now; data.ConsumeTime = $"{(span.TotalMilliseconds / 1000d).ToString("F2")}s"; Datasource.Add(data); table.ScrollIntoView(data); })); } catch (Exception ex) { //屏蔽错误 } } public void UpdateStatus(string status) { if (status == "Passed") { UpdateTestCounter(true); } else if (status == "Error" || status == "Failed") { UpdateTestCounter(false); } else if (Status != "Testing" && status == "Testing") { UpdateProbeCount(ProbeCount + 1); } Status = status; } public void IniTestData() { Datasource.Clear(); } /// /// 设置测试进度条 /// /// public void SetTestProcess(int ProcessVal) { ProcessValue = ProcessVal; Set("ProcessValueLabel"); } private void UserControl_Loaded(object sender, RoutedEventArgs e) { StartTcpServer(); this.UpdateTestCounter(null); Loaded -= UserControl_Loaded; } private void UpdateTestCounter(bool? result) { if (result == true) { PassNum += 1; //Interlocked.Increment(ref passNum); //Set("PassNum"); } else if (result == false) { FailNum += 1; //Interlocked.Increment(ref failNum); //Set("FailNum"); } TotalNum = PassNum + FailNum; if (TotalNum != 0) { PassRate = ((double)PassNum / TotalNum); } else { PassRate = 0.0; } Set("NumInfo"); this.WriteCounter(); } private void WriteCounter() { IniFileHelper.WriteIniData("Socket" + this.index.ToString(), "Pass", this.passNum.ToString(), this.CountIniPath); IniFileHelper.WriteIniData("Socket" + this.index.ToString(), "Fail", this.failNum.ToString(), this.CountIniPath); } private void ReadCounter() { try { this.PassNum = Convert.ToInt32(IniFileHelper.ReadIniData("Socket" + this.index.ToString(), "Pass", "", CountIniPath)); this.FailNum = Convert.ToInt32(IniFileHelper.ReadIniData("Socket" + this.index.ToString(), "Fail", "", CountIniPath)); } catch (Exception ex) { //do nothing } } public void ResetCounter() { this.PassNum = 0; this.FailNum = 0; this.UpdateTestCounter(null); } public void WriteToExcel(string path) { Dispatcher.Invoke(() => { try { string suffix = Path.GetExtension(path); if (!string.Equals(".xlsx", suffix, StringComparison.OrdinalIgnoreCase) && !string.Equals(".xls", suffix, StringComparison.OrdinalIgnoreCase)) { path = path.Replace(suffix, ".xls"); } FileInfo fi = new FileInfo(path); if (!fi.Directory.Exists) { fi.Directory.Create(); //文件不存在,创建文件 } List rows = new List(); rows.Add(new string[] { "测试时间", "测试人", "测试设备", "条形码", "测试结果" }); rows.Add(new string[] { DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), UserInfo.User.Name, ParamSetting.StationName, Barcode, Status }); rows.Add(new string[] { "项目名称", "测试参数", "测试值", "上限", "下限", "单位", "结果" }); if (Datasource != null && Datasource.Count > 0) { foreach (var data in Datasource) { rows.Add(new string[] { data.Name, data.Step, data.Value, data.LimitUp, data.LimitDown, data.Unit, data.Result }); } } ExcelHelper.ExportExcel(path, rows); } catch (Exception ex) { StandardTestUI.logger.Error("Write CSV File Failed.", ex); } }); } public void WriteToCSV(string path) { Dispatcher.Invoke(() => { try { FileInfo fi = new FileInfo(path); if (!fi.Directory.Exists) { fi.Directory.Create(); //文件不存在,创建文件 } using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8)) { string title = "项目名称,测试参数,测试值,上限,下限,单位,结果"; sw.WriteLine(title); if (Datasource != null && Datasource.Count > 0) { foreach (var data in Datasource) { sw.WriteLine($"{data.Name},{data.Step},{data.Value},{data.LimitUp},{data.LimitDown},{data.Unit},{data.Result}"); } } } } catch (Exception ex) { StandardTestUI.logger.Error("Write CSV File Failed.", ex); } }); } #region TCP相关 private string tcpServerStatus; public string TcpServerStatus { get => tcpServerStatus; set { Set(ref tcpServerStatus, value); } } private string tcpServerInfo; public string TcpServerInfo { get => tcpServerInfo; set { Set(ref tcpServerInfo, value); } } private TcpServer tcpServer; private int GetConfigPort() { try { var customConfig = (Hashtable)ConfigurationManager.GetSection("TestResultConfig"); if (customConfig.ContainsKey("PortStart")) { int port = int.Parse(customConfig["PortStart"].ToString()); return port; } else { return 6660; } } catch (Exception ex) { return 6660; } } private void StartTcpServer() { int port = GetConfigPort(); var serverConfig = new ServerConfig() { MaxRequestLength = 1024 * 1024, Port = port + 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) { } } private void TcpServer_NewRequestReceived(TcpSession session, StringRequestInfo requestInfo) { string msg = requestInfo.Body; StandardTestUI.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(() => { AddTestData("", values[0], values[2], values[4], values[5], values[3], values[6]); //new Info //{ // step = values[0], // value = values[2], // unit = values[3], // limitUp = values[4], // limitDown = values[5], // result = values[6], // updateTime = values[7] //} }); //session.Send("1"); } #endregion public void ShowPausePanel() { pausePanel.Visibility = Visibility.Visible; } private void Button_Click(object sender, RoutedEventArgs e) { Button btn = sender as Button; switch (btn.Name) { case "clear": UpdateProbeCount(0); break; case "cancelPauseBtn": parent.testExecutionWrapper.SetStationGlobalValue($"StationState.IsContinue_{index}", 1, false); pausePanel.Visibility = Visibility.Collapsed; break; case "continuePauseBtn": parent.testExecutionWrapper.SetStationGlobalValue($"StationState.IsContinue_{index}", 1, true); pausePanel.Visibility = Visibility.Collapsed; break; case "scannerSetting": //ScannerSetting setting = new ScannerSetting() //{ // Owner = Window.GetWindow(this) //}; //setting.Open(true, $"Socket{index}", CountIniPath); ShowScannerPanel(); break; case "scannerOkBtn": SendSnr2Ts(); break; default: break; } } public void ShowScannerPanel() { //scannerPanel.Visibility = Visibility.Visible; } private void SendSnr2Ts() { } private void pausePanel_Loaded(object sender, RoutedEventArgs e) { if (sender == pausePanel) { var can = pausePanel; var modal = visualModal; Canvas.SetLeft(modal, (pausePanel.ActualWidth - visualModal.ActualWidth) / 2); Canvas.SetTop(modal, (pausePanel.ActualHeight - visualModal.ActualHeight) / 2); } else { //var can = scannerPanel; //var modal = scannerVisualModal; //Canvas.SetLeft(modal, (scannerPanel.ActualWidth - scannerVisualModal.ActualWidth) / 2); //Canvas.SetTop(modal, (scannerPanel.ActualHeight - scannerVisualModal.ActualHeight) / 2); } } public void RefreshScreen(int[][] configs) { //foreach (UIElement item in canvas.Children) //{ // if (item is ScreenTouch) // { // canvas.Children.Remove(item); // } //} screenContainer.Child = null; screenGrid = new ScreenGrid(1, configs.Length); screens = new ScreenTouch[configs.Length]; int space = 2 * (screens.Length + 1); for (int i = 0; i < configs.Length; i++) { var screen = new ScreenTouch(configs[i][0], configs[i][1]) { Width = Math.Max((tableHeader.ActualHeight / 9 * 16 - space) / screens.Length, 0), Height = Math.Max((tableHeader.ActualHeight / 9 * 16 - space) / screens.Length / 16 * 9, 0) }; screens[i] = screen; screenGrid.AddScreen(screen, 0, i); } screenContainer.Child = screenGrid; //canvas.Children.Add(screens[0]); //Canvas.SetBottom(screens[0], 0); //Canvas.SetRight(screens[0], 0); //Panel.SetZIndex(screens[0], 999); } public void DrawScreenPoint(int index, int x, int y) { screens[index].DrawPoint(x, y); } /// /// 绘图之前清空已有的 /// /// /// public void DrawScreenPoints(int index, int[][] points) { screens[index].DrawPoints(points); } /// /// 绘图之前不清空已有的 /// /// /// public void DrawNewScreenPoints(int index, int[][] points) { screens[index].DrawNewPoints(points); } public void ClearScreenPoint(int index) { screens[index].Clear(); } public void RefreshProbeCount(ProductData product) { try { var num = IniFileHelper.ReadIniData($"Socket{this.index.ToString()}", "ProbeCount", "0", this.CountIniPath); this.ProbeCount = int.Parse(num); } catch (Exception ex) { this.ProbeCount = 0; } } /// /// 更新探针使用次数 /// /// private void UpdateProbeCount(int count) { /// 写到配置文件 IniFileHelper.WriteIniData("Socket" + this.index.ToString(), "ProbeCount", count.ToString(), this.CountIniPath); ProbeCount = count; } public void RefreshProduct(ProductData product) { if (product == null) { screenContainer.Child = null; return; } try { string screenSize = ProductManager.GetParameterByProductAndName(product.Name, "ScreenTouch")?.Value; if (string.IsNullOrEmpty(screenSize)) { screenContainer.Child = null; return; } string[] arr = screenSize.Split(';'); int[][] configs = new int[arr.Length][]; for (int i = 0; i < arr.Length; i++) { string[] size = arr[i].Split(','); configs[i] = new int[2] { int.Parse(size[0]), int.Parse(size[1]) }; } RefreshScreen(configs); } catch (Exception ex) { StandardTestUI.logger.Error("RefreshProduct Failed.", ex); screenContainer.Child = null; } } private void control_SizeChanged(object sender, SizeChangedEventArgs e) { if (screenGrid == null) { return; } //screenGrid.Height = tableHeader.ActualHeight - 2; //screenGrid.Width = tableHeader.ActualHeight / 9 * 16 - 2; int space = 2 * (screens.Length + 1); for (int i = 0; i < screens.Length; i++) { var screen = screens[i]; screen.Width = Math.Max(Math.Floor((tableHeader.ActualHeight / 9 * 16 - space) / screens.Length), 0); screen.Height = Math.Max(Math.Floor(screen.Width / 16 * 9), 0); } } private void screenContainer_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { if (e.ClickCount == 2) { new ScreenTouchWin(screens) { Owner = Window.GetWindow(this) }.ShowDialog(); } } private void control_PreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { if (parent.EnableManualDebug) { ContextMenu contextMenu = new ContextMenu(); contextMenu.Closed += ContextMenu_Closed; var item = new MenuItem { IsCheckable = false, Name = "manualDebugItem", Header = this.lang("手动调试"), }; item.Click += Item_Click; ; contextMenu.Items.Add(item); this.ContextMenu = contextMenu; } else { this.ContextMenu = null; } } private void Item_Click(object sender, RoutedEventArgs e) { string manualDebugSeq = ParameterManager.GetCommonParameterByName("ManualDebugSeqPath")?.Value; if (string.IsNullOrEmpty(manualDebugSeq)) { MsgBoxHelper2.Error("请先设置手动调试序列路径[ManualDebugSeqPath]!"); return; } string modelPath = parent.tsModelPath; var win = new ManualDebugWindow(manualDebugSeq, modelPath, false) { Title = $"工位{this.index}手动调试", Owner = Window.GetWindow(this), OvenIndex = index, OvenName = "", CellCount = parent.tsSockets.Count, CellIndex = 0, CellName = "", }; win.ShowDialog(); } private void ContextMenu_Closed(object sender, RoutedEventArgs e) { this.ContextMenu = null; } } }