using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.Input;
|
using HMI.Core.Util;
|
using HMI.UI.DpUtil;
|
using NationalInstruments.TestStand.Interop.API;
|
using Plugin.BurnIn.Model;
|
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 System.Xml.Linq;
|
|
namespace Plugin.BurnIn
|
{
|
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
|
}
|
|
[ObservableObject]
|
public partial class ManualDebug : UserControl
|
{
|
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<TestDataItem> TestData { get; private set; } = new ObservableCollection<TestDataItem>();
|
|
private Dictionary<string, StatusBtn> btnCache = new Dictionary<string, StatusBtn>();
|
|
// ÈÕÖ¾¼¶±ðÑÕÉ«
|
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";
|
|
[ObservableProperty]
|
private string tcpServerStatus;
|
[ObservableProperty]
|
private string tcpServerInfo;
|
|
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<ManualCell> Cells = new List<ManualCell>();
|
private List<StatusCell> StatusCells = new List<StatusCell>();
|
|
public void RefreshGrid(SingleCell[] cells)
|
{
|
if (cells != null)
|
{
|
int i = 0;
|
foreach (var cell in cells)
|
{
|
var mCell = new ManualCell
|
{
|
Title = cell.title,
|
Index = cell.index
|
};
|
mCell.SelectedChanged += MCell_SelectedChanged;
|
Cells.Add(mCell);
|
CellGrid.Children.Add(mCell);
|
|
var sCell = new StatusCell
|
{
|
Title = cell.title,
|
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;
|
}
|
}
|
|
/// <summary>
|
/// Æô¶¯Tcp·þÎñÆ÷
|
/// </summary>
|
[RelayCommand]
|
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;
|
}
|
}
|
|
/// <summary>
|
/// ¸üÐÂTcp·þÎñÆ÷״̬
|
/// </summary>
|
/// <param name="status"></param>
|
/// <param name="info"></param>
|
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<BtnConfig> 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)
|
{
|
|
}
|
}
|
}
|
|
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));
|
}
|
}
|
}
|