using HMI.Core.Util; using HMI.UI.DpUtil; using NationalInstruments.TestStand.Interop.API; using Plugin.TsSupport; using SuperSocket.SocketBase.Config; using System.Collections; using System.Collections.ObjectModel; using System.ComponentModel; using System.Configuration; using System.Globalization; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Media; using Util.ManualDebug.Model; namespace Util.ManualDebug { public class BtnConfig { public string Title { get; set; } public string Name { get; set; } } // ½á¹ûʧ°ÜÅжÏת»»Æ÷£¨Ö§³Ö²»Çø·Ö´óСд£© public class ResultFailedConverter : IMultiValueConverter { public static readonly ResultFailedConverter Instance = new ResultFailedConverter(); public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values.Length > 0 && values[0] is string) { string result = (string)values[0]; string upper = result.ToUpperInvariant(); return upper == "NG" || upper == "FAIL"; } return false; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } // ÈÕÖ¾¼¶±ðö¾Ù public enum LogLevel { Debug = 0, Info = 1, Warn = 2, Error = 3 } public partial class ManualDebug : 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 public static readonly DependencyProperty OvenNameProperty = DependencyProperty.Register( "OvenName", typeof(string), typeof(ManualDebug), new PropertyMetadata("")); public static readonly DependencyProperty CellNameProperty = DependencyProperty.Register( "CellName", typeof(string), typeof(ManualDebug), new PropertyMetadata("")); public static readonly DependencyProperty OvenIndexProperty = DependencyProperty.Register( "OvenIndex", typeof(int), typeof(ManualDebug), new PropertyMetadata(0)); public static readonly DependencyProperty CellIndexProperty = DependencyProperty.Register( "CellIndex", typeof(int), typeof(ManualDebug), new PropertyMetadata(-1)); public static readonly DependencyProperty CellCountProperty = DependencyProperty.Register( "CellCount", typeof(int), typeof(ManualDebug), new PropertyMetadata(0)); public string OvenName { get { return (string)GetValue(OvenNameProperty); } set { SetValue(OvenNameProperty, value); } } public string CellName { get { return (string)GetValue(CellNameProperty); } set { SetValue(CellNameProperty, value); } } public int OvenIndex { get { return (int)GetValue(OvenIndexProperty); } set { SetValue(OvenIndexProperty, value); } } public int CellIndex { get { return (int)GetValue(CellIndexProperty); } set { SetValue(CellIndexProperty, value); } } public int CellCount { get { return (int)GetValue(CellCountProperty); } set { SetValue(CellCountProperty, value); } } public ObservableCollection TestData { get; private set; } = new ObservableCollection(); private Dictionary btnCache = new Dictionary(); // ÈÕÖ¾¼¶±ðÑÕÉ« private readonly SolidColorBrush _debugBrush; private readonly SolidColorBrush _infoBrush; private readonly SolidColorBrush _warnBrush; private readonly SolidColorBrush _errorBrush; private ITestExecutionWrapper executionWrapper; private TcpServer tcpServer; public string seqPath { get; set; } public string modelPath { get; set; } = "C:\\Program Files\\National Instruments\\TestStand 2020\\Components\\Models\\TestStandModels\\ParallelModel.seq"; 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); } } public ManualDebug() { _debugBrush = new SolidColorBrush(Color.FromRgb(0x71, 0x80, 0x8A)); // »ÒÉ« _infoBrush = new SolidColorBrush(Colors.Black); _warnBrush = new SolidColorBrush(Color.FromRgb(0xD6, 0x9E, 0x2E)); // ³È»ÆÉ« _errorBrush = new SolidColorBrush(Color.FromRgb(0xC5, 0x30, 0x30)); // ºìÉ« this.Loaded += ManualDebug_Loaded; InitializeComponent(); RefreshButtons(null); } public void HideCells(bool flag) { CellSelectBorder.Visibility = flag ? Visibility.Collapsed : Visibility.Visible; } private List Cells = new List(); private List StatusCells = new List(); public void RefreshGrid(CellConfig[] cells) { if (cells != null) { int i = 0; foreach (var cell in cells) { var mCell = new ManualCell { Title = cell.Name, Index = cell.Index }; mCell.SelectedChanged += MCell_SelectedChanged; Cells.Add(mCell); CellGrid.Children.Add(mCell); var sCell = new StatusCell { Title = cell.Name, Index = cell.Index }; StatusCells.Add(sCell); CellResultGrid.Children.Add(sCell); BindingOperations.SetBinding(sCell, StatusCell.StatusProperty, new Binding(nameof(ManualCell.Selected)) { Source = mCell, Mode = BindingMode.OneWay, //UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, Converter = CellStatusConverter.Instance }); } UniformGridHelper.RefreshGridInnerBorder(CellGrid); UniformGridHelper.RefreshGridInnerBorder(CellResultGrid); } } private void MCell_SelectedChanged(object sender, EventArgs e) { object[] arr = Cells.Select(c => (object)c.Selected).ToArray(); SetArray($"Running.CellIndex", PropertyValueTypes.PropValType_Boolean, arr); } private void ManualDebug_Loaded(object sender, RoutedEventArgs e) { StartTcpServer(); Task.Run(() => { System.Threading.Thread.Sleep(500); Dispatcher.BeginInvoke(() => { InitWrapper(); StartSeq(); mask.Visibility = Visibility.Collapsed; }); }); } private int GetConfigPort() { try { var customConfig = (Hashtable)ConfigurationManager.GetSection("TestResultConfig"); if (customConfig.ContainsKey("PortStart")) { int port = int.Parse(customConfig["PortStart"].ToString()) - 1; return port; } else { return 6659; } } catch (Exception ex) { AppendLog(LogLevel.Error, $"¶ÁÈ¡Æðʼ¶Ë¿Ú´íÎó£º {ex.Message} {ex.StackTrace} ʹÓÃĬÈ϶˿Ú6659"); return 6659; } } /// /// Æô¶¯Tcp·þÎñÆ÷ /// private void StartTcpServer() { int port = GetConfigPort(); var serverConfig = new ServerConfig() { MaxRequestLength = 1024 * 1024, Port = port }; 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")); AppendLog(LogLevel.Debug, $"Êý¾Ý½ÓÊÕ·þÎñÆ÷Æô¶¯£¬¶Ë¿Ú£º{port}"); } 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")); AppendLog(LogLevel.Debug, $"Êý¾Ý½ÓÊÕ·þÎñÆ÷Æô¶¯£¬¶Ë¿Ú£º{port}"); } } catch (Exception ex) { ChangeTcpServerStatus("ERROR", $"{ex.Message}"); AppendLog(LogLevel.Error, $"Êý¾Ý½ÓÊÕ·þÎñÆ÷Æô¶¯´íÎó£º {ex.Message} {ex.StackTrace}"); tcpServer?.Stop(); tcpServer = null; } } /// /// ¸üÐÂTcp·þÎñÆ÷״̬ /// /// /// private void ChangeTcpServerStatus(string status, string info) { Dispatcher.Invoke(() => { TcpServerStatus = status; TcpServerInfo = info; }); } private void TcpServer_NewRequestReceived(TcpSession session, SuperSocket.SocketBase.Protocol.StringRequestInfo requestInfo) { string msg = requestInfo.Body; string[] datas_10015 = msg.Split(';'); //int cellIndex = int.Parse(datas_10015[1]); string strs = datas_10015[2]; string[] arr = strs.Split(','); Dispatcher.Invoke(() => { AddTestData(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7]); }); } public void RefreshButtons(List settings) { if (settings == null) return; for (int i = 0; i < settings.Count; i++) { var setting = settings[i]; var margin = new Thickness(0, 0, 20, 0); if (i == settings.Count - 1) { margin = new Thickness(0); } var btn = new StatusBtn { Title = setting.Title, Tag = setting, Margin = margin }; btn.BtnClick += Btn_BtnClick; btnCache[setting.Name] = btn; btnPanel.Children.Add(btn); } } public void StartSeq() { try { executionWrapper?.StartSequence(seqPath, modelPath); } catch (Exception ex) { AppendLog(LogLevel.Error, $"Æô¶¯²âÊÔÐòÁÐʧ°Ü {ex.Message} {ex.StackTrace}"); } } private void InitWrapper() { try { var wrapper = new TeststandWrapper(); var AxApplicationMgr = wrapper.AxApplicationMgr; ((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).BeginInit(); host.Child = AxApplicationMgr; ((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).EndInit(); wrapper.Init(); executionWrapper = wrapper; wrapper.UIMessageEvent += Wrapper_UIMessageEvent; } catch (Exception ex) { AppendLog(LogLevel.Error, $"³õʼ»¯Teststand {ex.Message} {ex.StackTrace}"); } } private void SetArray(string name, PropertyValueTypes type, object[] arr) { try { var context = ((TeststandWrapper)executionWrapper).context; context.FileGlobals.DeleteSubProperty(name, 2); context.FileGlobals.NewSubProperty(name, type, true, null, 1); context.FileGlobals.GetPropertyObject(name, 0).SetNumElements(arr.Length); for (int i = 0; i < arr.Length; i++) { if (type == PropertyValueTypes.PropValType_Boolean) { context.FileGlobals.SetValBoolean($"{name}[{i}]", 0, arr[i] == null ? false : (bool)arr[i]); } else { context.FileGlobals.SetValString($"{name}[{i}]", 0, arr[i]?.ToString()); } // (type == PropertyValueTypes.PropValType_String) } } catch (Exception ex) { AppendLog(LogLevel.Error, $"дÊý×é {name} ´íÎó£º {ex.Message} {ex.StackTrace}"); } } private void Wrapper_UIMessageEvent(object sender, UIMessageEvent e) { try { if (e.EventCode == 10000) { executionWrapper?.SetContext(e.Data); string key = $"Running.OvenName"; executionWrapper?.SetFileGlobalValue(key, 1, OvenName); key = $"Running.OvenIndex"; executionWrapper?.SetFileGlobalValue(key, 1, OvenIndex); //key = $"Running.CellIndex"; //executionWrapper?.SetFileGlobalValue(key, 1, CellIndex); if (CellIndex >= 0) { key = $"Running.CellIndex"; object[] arr = new object[CellCount]; arr[CellIndex] = true; SetArray(key, PropertyValueTypes.PropValType_Boolean, arr); key = $"Running.CellName"; string[] names = new string[CellCount]; names[CellIndex] = CellName; SetArray(key, PropertyValueTypes.PropValType_String, names); } else { string[] names = Cells.Select(c => c.Title).ToArray(); SetArray($"Running.CellName", PropertyValueTypes.PropValType_String, names); } Dispatcher.Invoke(() => { CellGrid.IsEnabled = true; AppendLog(LogLevel.Debug, "Context³õʼ»¯Íê³É"); }); return; } if (e.EventCode == 10001) { string[] arr = e.StrData.Split(','); Dispatcher.BeginInvoke(() => { AddTestData(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7]); }); return; } if (e.EventCode == 10002) { string[] arr = e.StrData.Split(','); LogLevel level = (LogLevel)int.Parse(arr[0]); Dispatcher.BeginInvoke(() => { AppendLog(level, arr[1]); }); return; } if (e.EventCode == 10003) { string[] arr = e.StrData.Split(','); DebugStatus status = (DebugStatus)int.Parse(arr[1]); Dispatcher.BeginInvoke(() => { SetStatus(arr[0], status); }); return; } if (e.EventCode == 10004) { int index = Convert.ToInt32(e.NumberData); //CellStatus status = (CellStatus)Enum.Parse(typeof(CellStatus), e.StrData); CellStatus status = (CellStatus)int.Parse(e.StrData); Dispatcher.BeginInvoke(() => { if (index < StatusCells.Count) { StatusCells[index].SetCurrentValue(StatusCell.StatusProperty, status); } }); return; } } catch (Exception ex) { AppendLog(LogLevel.Error, $"´¦ÀíUIÐÅϢʧ°Ü {ex.Message} {ex.StackTrace}"); } } private void Btn_BtnClick(object sender, RoutedEventArgs e) { var btn = (StatusBtn)sender; BtnConfig config = (BtnConfig)btn.Tag; StartSingleTest(config.Name); } private void StartSingleTest(string name) { try { string key = $"Running.ActionName"; executionWrapper?.SetFileGlobalValue(key, 1, name); } catch (Exception ex) { AppendLog(LogLevel.Error, $"Æô¶¯¹¦ÄÜʧ°Ü {ex.Message} {ex.StackTrace}"); } } // ÉèÖÃ״̬ÏÔʾ private void SetStatus(string labelName, DebugStatus status) { if (btnCache.ContainsKey(labelName)) { var btn = btnCache[labelName]; btn.Status = status; } } // ÖØÖÃ״̬ÏÔʾ private void ResetStatus(string labelName) { SetStatus(labelName, DebugStatus.Idle); } // ÉèÖòâÊÔÖÐ״̬²¢½ûÓð´Å¥ private void SetTestingStatus(string labelName, Button button) { SetStatus(labelName, DebugStatus.Testing); button.IsEnabled = false; } private void OnClearClick(object sender, RoutedEventArgs e) { TestData.Clear(); } private void OnClearLogClick(object sender, RoutedEventArgs e) { LogRichTextBox.Document.Blocks.Clear(); } private void AddTestData(string name, string send, string receive, string unit, string upper, string lower, string result, string time) { TestData.Add(new TestDataItem { Name = name, Send = send, Receive = receive, Unit = unit, UpperLimit = upper, LowerLimit = lower, Result = result, Time = time }); if (DataGridComm.Items.Count > 0) { DataGridComm.ScrollIntoView(DataGridComm.Items[DataGridComm.Items.Count - 1]); } } // »ñÈ¡ÈÕÖ¾¼¶±ð¶ÔÓ¦µÄÑÕÉ« private Brush GetLogLevelBrush(LogLevel level) { switch (level) { case LogLevel.Debug: return _debugBrush; case LogLevel.Info: return _infoBrush; case LogLevel.Warn: return _warnBrush; case LogLevel.Error: return _errorBrush; default: return _infoBrush; } } // Ìí¼Ó´ø¼¶±ðµÄÈÕÖ¾ private void AppendLog(LogLevel level, string message) { Dispatcher.BeginInvoke(() => { string timestamp = DateTime.Now.ToString("HH:mm:ss.fff"); string levelStr = level.ToString().ToUpper(); Paragraph? paragraph = LogRichTextBox.Document.Blocks.LastBlock as Paragraph; if (paragraph == null) { paragraph = new Paragraph(); LogRichTextBox.Document.Blocks.Add(paragraph); } // ʱ¼ä´Á£¨»ÒÉ«£© Run timestampRun = new Run("[" + timestamp + "] ") { Foreground = _debugBrush }; paragraph.Inlines.Add(timestampRun); // ¼¶±ð±êÇ© Brush levelBrush = GetLogLevelBrush(level); Run levelRun = new Run("[" + levelStr + "] ") { Foreground = levelBrush, FontWeight = FontWeights.SemiBold }; paragraph.Inlines.Add(levelRun); // ÏûÏ¢ÄÚÈÝ Run messageRun = new Run(message + "\n") { Foreground = levelBrush }; paragraph.Inlines.Add(messageRun); LogRichTextBox.ScrollToEnd(); }); } // ¼æÈݾɵ÷Ó÷½Ê½£¬Ä¬ÈÏ Info ¼¶±ð private void AppendLog(string message) { AppendLog(LogLevel.Info, message); } public void Stop() { try { executionWrapper?.SetFileGlobalValue("Running.StopTest", 1, true); executionWrapper?.WaitForExit(); executionWrapper?.Dispose(); tcpServer?.Stop(); } catch (Exception ex) { } } private void Button_Click(object sender, RoutedEventArgs e) { StartTcpServer(); } } public class TestDataItem : INotifyPropertyChanged { private string _name = ""; private string _receive = ""; private string _send = ""; private string _unit = ""; private string _upperLimit = ""; private string _lowerLimit = ""; private string _result = ""; private string _time = ""; public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } } public string Receive { get { return _receive; } set { _receive = value; OnPropertyChanged("Receive"); } } public string Send { get { return _send; } set { _send = value; OnPropertyChanged("Send"); } } public string Unit { get { return _unit; } set { _unit = value; OnPropertyChanged("Unit"); } } public string UpperLimit { get { return _upperLimit; } set { _upperLimit = value; OnPropertyChanged("UpperLimit"); } } public string LowerLimit { get { return _lowerLimit; } set { _lowerLimit = value; OnPropertyChanged("LowerLimit"); } } public string Result { get { return _result; } set { _result = value; OnPropertyChanged("Result"); } } public string Time { get { return _time; } set { _time = value; OnPropertyChanged("Time"); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }