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 { /// /// UserControl1.xaml 的交互逻辑 /// 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; /// /// TS 引擎 /// private Engine engine = null; private string testSeqFile = string.Empty; /// /// 测试序列 /// private SequenceFile testSeq = null; /// /// 测试模型序列 /// 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 _products; public ObservableCollection 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 socketMap = new Dictionary(); 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 parameters = ProductManager.GetParametersByProductName(name); testSeqFile = parameters.FirstOrDefault(p => p.Name == "TestSequence")?.Value?.ToString(); StartSequence(); } private void InitProducts() { Products = ProductManager.GetProducts>(); if (Products != null && Products.Count > 0) { List parameters = ParameterManager.GetCommonParameter>(); 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 扫码枪相关 /// /// 设置扫码枪 /// 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初始化相关 /// /// 启动测试序列 /// 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}"); }); } } /// /// 初始化TestStand引擎 /// 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; } } /// /// 退出应用 /// /// /// private void AxApplicationMgr_ExitApplication(object sender, EventArgs e) { //Environment.ExitCode = this.AxApplicationMgr.ExitCode; //this.Close(); } /// /// 进程结束事件 /// /// /// 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}"); } } /// /// TestStand用户交互事件 /// /// /// 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 } }