using HMI.Base;
|
using HMI.Core.Entity;
|
using HMI.Core.Manager;
|
using HMI.Core.Util;
|
using HMI.UI;
|
using HMI.UI.Entity;
|
using HMI.UI.Util;
|
using NationalInstruments.TestStand.Interop.API;
|
using NationalInstruments.TestStand.Interop.UI.Ax;
|
using Panuon.WPF.UI;
|
using System;
|
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
using System.IO;
|
using System.IO.Ports;
|
using System.Linq;
|
using System.Reflection;
|
using System.Windows;
|
using System.Windows.Controls;
|
|
namespace Plugin.JarUI
|
{
|
/// <summary>
|
/// UserControl1.xaml 的交互逻辑
|
/// </summary>
|
public partial class JarUI : PluginControl
|
{
|
public JarUI()
|
{
|
DataContext = this;
|
InitializeComponent();
|
InitProducts();
|
InitTsEngine();
|
}
|
|
public override void InitFinish()
|
{
|
string iniFile = Path.Combine(BaseFolder, "Config.ini");
|
if (!File.Exists(iniFile))
|
{
|
File.Create(iniFile);
|
}
|
this.iniFile = iniFile;
|
}
|
|
#region Properties
|
|
#region TestStand相关
|
private AxApplicationMgr AxApplicationMgr;
|
/// <summary>
|
/// TS 引擎
|
/// </summary>
|
private Engine engine = null;
|
|
private string testSeqFile = string.Empty;
|
/// <summary>
|
/// 测试序列
|
/// </summary>
|
private SequenceFile testSeq = null;
|
|
/// <summary>
|
/// 测试模型序列
|
/// </summary>
|
private SequenceFile modeSeq = null;
|
public SequenceContext SequenceContext { get; private set; } = null;
|
private Execution execution = null;
|
#endregion
|
|
private bool _isRunning;
|
public bool IsRunning
|
{
|
get => _isRunning;
|
set
|
{
|
Dispatcher.Invoke(() =>
|
{
|
startBtn.IsEnabled = !value;
|
stopBtn.IsEnabled = value;
|
CbProduct.IsEnabled = !value;
|
});
|
Set(ref _isRunning, value);
|
}
|
}
|
|
private ObservableCollection<ProductData> _products;
|
|
public ObservableCollection<ProductData> Products
|
{
|
get { return _products; }
|
set { Set(ref _products, value); }
|
}
|
|
private ProductData _selectedProduct;
|
|
public ProductData SelectedProduct
|
{
|
get { return _selectedProduct; }
|
set
|
{
|
SetTestSeqFile(value);
|
Set(ref _selectedProduct, value);
|
}
|
}
|
|
|
private bool isLoadOk = false;
|
private string iniFile;
|
private JarCell selectedCell;
|
|
private JarCell[] tsSockets;
|
private Dictionary<string, JarCell> socketMap = new Dictionary<string, JarCell>();
|
private SerialPort serialPort;
|
#endregion
|
|
private void RefershUI()
|
{
|
tsSockets = new JarCell[18];
|
for (int i = 0; i < 18; i++)
|
{
|
var cell = new JarCell(i);
|
cell.GotFocus += Cell_GotFocus;
|
uGrid.Children.Add(cell);
|
tsSockets[i] = cell;
|
socketMap.Add(cell.Name, cell);
|
}
|
}
|
|
private void Cell_GotFocus(object sender, RoutedEventArgs e)
|
{
|
selectedCell = sender as JarCell;
|
}
|
|
private void SetTestSeqFile(ProductData product)
|
{
|
if (product == null)
|
{
|
testSeqFile = null;
|
return;
|
}
|
string name = product.Name;
|
List<ParameterData> parameters = ProductManager.GetParametersByProductName(name);
|
testSeqFile = parameters.FirstOrDefault(p => p.Name == "TestSequence")?.Value?.ToString();
|
StartSequence();
|
}
|
|
private void InitProducts()
|
{
|
Products = ProductManager.GetProducts<ObservableCollection<ProductData>>();
|
if (Products != null && Products.Count > 0)
|
{
|
List<ParameterData> parameters =
|
ParameterManager.GetCommonParameter<List<ParameterData>>();
|
string tmpNum = parameters?.FirstOrDefault(p => p.Name == "SocketNum")?.Value?.ToString();
|
string lastModel = engine?.Globals.GetValString("StationState.ProductModel", 1);
|
|
if (!string.IsNullOrEmpty(lastModel))
|
{
|
var product = Products.FirstOrDefault(p => p.Name == lastModel);
|
if (product != null) SelectedProduct = product;
|
goto Write;
|
}
|
goto Write;
|
|
Write:
|
SelectedProduct = Products[0];
|
engine?.Globals.SetValString("StationState.ProductModel", 1, Products[0].Name);
|
|
RefershUI();
|
}
|
}
|
|
#region 扫码枪相关
|
/// <summary>
|
/// 设置扫码枪
|
/// </summary>
|
private void InitScanner()
|
{
|
if (serialPort != null) return;
|
ScannerConfig common = ScannerConfig.ReadFromIni(iniFile, "Config");
|
// 配置串口
|
serialPort = new SerialPort
|
{
|
PortName = common.PortName,
|
BaudRate = common.BaudRate,
|
Parity = Parity.None,
|
DataBits = common.DataBits,
|
StopBits = common.StopBits,
|
Handshake = Handshake.None,
|
DtrEnable = common.DtrEnable,
|
RtsEnable = common.RtsEnable
|
//ReadTimeout = 500,
|
//WriteTimeout = 500,
|
//ReciveBufferSize=4096
|
};
|
|
try
|
{
|
// 打开串口
|
serialPort.Open();
|
// 注册接收数据事件
|
serialPort.DataReceived += SerialPort_DataReceived;
|
}
|
catch (Exception ex)
|
{
|
log.Error("Init Scan Gun Failed.", ex);
|
MsgBoxHelper.Error(this, $"{this.lang("Tr.InitGunFailed")}: {ex.StackTrace}");
|
}
|
}
|
private string ReadDataFrom(SerialPort sp)
|
{
|
string barcode = "";
|
while (sp.BytesToRead > 0)
|
{
|
byte[] buffer = new byte[sp.BytesToRead];
|
sp.Read(buffer, 0, buffer.Length);
|
barcode += System.Text.Encoding.UTF8.GetString(buffer);
|
System.Threading.Thread.Sleep(50);
|
}
|
return barcode;
|
}
|
|
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
{
|
try
|
{
|
SerialPort sp = (SerialPort)sender;
|
string barcode = ReadDataFrom(sp);
|
if (selectedCell != null)
|
{
|
Dispatcher.Invoke(() =>
|
{
|
selectedCell.SetSn(barcode);
|
});
|
SequenceContext.StationGlobals.SetValString($"StationState.SN[{selectedCell.Index}]", 1, barcode);
|
SequenceContext.StationGlobals.SetValBoolean($"StationState.Socket_{selectedCell.Index}", 1, true);
|
}
|
}
|
catch (Exception ex)
|
{
|
log.Error("Get Scan Gun Data Failed.", ex);
|
MessageBox.Show($"{this.lang("Tr.GetGunData")}: {ex.StackTrace}");
|
}
|
}
|
#endregion
|
|
private void Button_Click(object sender, RoutedEventArgs e)
|
{
|
Button btn = sender as Button;
|
switch (btn?.Name)
|
{
|
case "startBtn":
|
StartBtnClick();
|
break;
|
case "stopBtn":
|
StopBtnClick();
|
break;
|
case "scannerSettingBtn":
|
ScannerSetting ss = new ScannerSetting
|
{
|
Owner = Window.GetWindow(this)
|
};
|
if (ss.Open(true, "Config", iniFile) == true)
|
{
|
serialPort?.Close();
|
InitScanner();
|
}
|
break;
|
default:
|
break;
|
}
|
}
|
|
private void StartBtnClick()
|
{
|
new MaskWindow(Window.GetWindow(this),
|
(win) =>
|
{
|
try
|
{
|
StartSequence();
|
}
|
finally
|
{
|
win.Dispatcher.Invoke(() =>
|
{
|
win.Close();
|
});
|
}
|
}).Info(LangUtil.Get("Ts.SequenceIsStarting"));
|
}
|
|
public void StopBtnClick()
|
{
|
new MaskWindow((WindowX)Window.GetWindow(this),
|
(win) =>
|
{
|
try
|
{
|
bool stoped = StopSequence();
|
if (stoped)
|
{
|
IsRunning = false;
|
}
|
}
|
finally
|
{
|
Dispatcher.Invoke(() =>
|
{
|
win.Close();
|
});
|
}
|
}
|
).Info(LangUtil.Get("App.SequenceIsStopping"));
|
}
|
|
private bool StopSequence()
|
{
|
try
|
{
|
SequenceContext?.StationGlobals.SetValBoolean("StationState.StopTest", 1, true);
|
if (this.execution == null) return true;
|
return this.execution.WaitForEndEx(2000, true, null, null);
|
}
|
catch (Exception ex)
|
{
|
log.Error("Stop Sequence Failed.", ex);
|
MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.StopSequenceFail")}: {ex.Message}");
|
return false;
|
}
|
}
|
|
private void PluginControl_Loaded(object sender, RoutedEventArgs e)
|
{
|
new MaskWindow((WindowX)Window.GetWindow(this),
|
(win) =>
|
{
|
try
|
{
|
InitScanner();
|
isLoadOk = true;
|
StartSequence();
|
}
|
catch (Exception ex)
|
{
|
log.Error("TsExecution Loaded Failed.", ex);
|
MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.UserControlLoadFailed")}: {ex.Message}");
|
}
|
Dispatcher.Invoke(() =>
|
{
|
if (isLoadOk) Loaded -= PluginControl_Loaded;
|
});
|
}
|
).Info(LangUtil.Get("App.SequenceIsStarting"));
|
}
|
|
#region teststand初始化相关
|
/// <summary>
|
/// 启动测试序列
|
/// </summary>
|
private void StartSequence()
|
{
|
try
|
{
|
if (!isLoadOk) return;
|
this.modeSeq = this.engine.GetSequenceFileEx(@"C:\Program Files\National Instruments\TestStand 2020\Components\Models\TestStandModels\ParallelModel.seq");
|
this.testSeq = this.engine.GetSequenceFileEx(this.testSeqFile, 0, TypeConflictHandlerTypes.ConflictHandler_UseGlobalType);
|
this.execution = this.engine.NewExecution(this.testSeq, "Test UUTs", this.modeSeq, false, 0, null, null, null);
|
IsRunning = true;
|
}
|
catch (Exception ex)
|
{
|
Dispatcher.Invoke(() =>
|
{
|
log.Error("Start Sequence Failed.", ex);
|
MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.StartSequenceFail")}: {ex.Message}");
|
});
|
}
|
}
|
|
/// <summary>
|
/// 初始化TestStand引擎
|
/// </summary>
|
private void InitTsEngine()
|
{
|
try
|
{
|
AxApplicationMgr = new AxApplicationMgr();
|
AxApplicationMgr.ExitApplication += new EventHandler(this.AxApplicationMgr_ExitApplication);
|
AxApplicationMgr.UIMessageEvent +=
|
new _ApplicationMgrEvents_UIMessageEventEventHandler(this.AxApplicationMgr_UIMessageEvent);
|
AxApplicationMgr.ExecutionClosed +=
|
new _ApplicationMgrEvents_ExecutionClosedEventHandler(this.AxApplicationMgr_ExecutionClosed);
|
((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).BeginInit();
|
host.Child = AxApplicationMgr;
|
((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).EndInit();
|
|
this.engine = this.AxApplicationMgr.GetEngine();
|
this.engine.PersistBreakpoints = false;
|
this.AxApplicationMgr.IsEditor = true;
|
this.AxApplicationMgr.LoginOnStart = false;
|
this.AxApplicationMgr.Start();
|
this.modeSeq = this.engine.GetSequenceFileEx(@"C:\Program Files\National Instruments\TestStand 2020\Components\Models\TestStandModels\ParallelModel.seq");
|
}
|
catch (Exception ex)
|
{
|
log.Error("InitTsEngine Failed.", ex);
|
throw ex;
|
}
|
}
|
|
/// <summary>
|
/// 退出应用
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void AxApplicationMgr_ExitApplication(object sender, EventArgs e)
|
{
|
//Environment.ExitCode = this.AxApplicationMgr.ExitCode;
|
//this.Close();
|
}
|
|
/// <summary>
|
/// 进程结束事件
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void AxApplicationMgr_ExecutionClosed(object sender, _ApplicationMgrEvents_ExecutionClosedEvent e)
|
{
|
try
|
{
|
if (this.testSeq == null)
|
return;
|
this.engine.ReleaseSequenceFileEx(this.testSeq, 0);
|
this.engine.ReleaseSequenceFileEx(this.modeSeq, 0);
|
this.engine.UnloadAllModules();
|
this.testSeq = null;
|
this.modeSeq = null;
|
}
|
catch (Exception ex)
|
{
|
log.Error("ReleaseSequenceFileEx Failed.", ex);
|
MsgBoxHelper.Error(Window.GetWindow(this), $"{LangUtil.Get("Ts.ReleaseSequenceFileFail")}: {ex.Message}");
|
}
|
}
|
|
/// <summary>
|
/// TestStand用户交互事件
|
/// </summary>
|
/// <param name="sender"></param>
|
/// <param name="e"></param>
|
private void AxApplicationMgr_UIMessageEvent(object sender, _ApplicationMgrEvents_UIMessageEventEvent e)
|
{
|
try
|
{
|
int EventCase = Convert.ToInt32(e.uiMsg.Event);
|
int MethodCode = Convert.ToInt16(e.uiMsg.NumericData);
|
string strData = e.uiMsg.StringData;
|
|
try
|
{
|
log.Info($"Event: {EventCase}, NumericData: {MethodCode}, StringData: {strData}");
|
}
|
catch
|
{
|
|
}
|
|
if (EventCase != 10015) return;
|
switch (MethodCode)
|
{
|
case 0:
|
/// 设置句柄
|
this.SequenceContext = (SequenceContext)e.uiMsg.ActiveXData;
|
break;
|
case 1:
|
var arr1 = strData.Split(';');
|
int index1 = int.Parse(arr1[0]);
|
this.tsSockets[index1].SetStatus(arr1[1]);
|
break;
|
case 2:
|
var arr2 = strData.Split(';');
|
int index2 = int.Parse(arr2[0]);
|
this.tsSockets[index2].SetInfo(arr2[1]);
|
break;
|
default:
|
break;
|
}
|
}
|
catch (Exception ex)
|
{
|
log.Warn("Ts Event Error.", ex);
|
}
|
}
|
#endregion
|
|
|
}
|
}
|