using HMI.Base; using HMI.Core.Api; using HMI.Core.Entity; using HMI.Core.Manager; using HMI.Core.Setting; using HMI.Core.Util; using HMI.Simple.Util; using HMI.UI.Util; using HMI.Util; using LiveChartsCore; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Painting; using log4net; using NationalInstruments.TestStand.Interop.API; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using Plugin.TsSupport; using SkiaSharp; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Windows; using System.Windows.Controls; namespace Plugin.StandardTest { /// /// UserControl1.xaml 的交互逻辑 /// public partial class StandardTestUI : PluginMaskControl { #region TestStand事件 /// /// TS 引擎 /// //private Engine engine = null; ///// ///// 测试序列 ///// //private SequenceFile testSeq = null; ///// ///// 测试模型序列 ///// //private SequenceFile modeSeq = null; //private Execution execution = null; private string testSeqFile = string.Empty; public ITestExecutionWrapper testExecutionWrapper { get; private set; } #endregion public static ILog logger { get; private set; } public List tsSockets { get; private set; } = new List(); /// /// 样件模式状态 /// private bool sampleStatus; public bool SampleStatus { get { return sampleStatus; } set { Set(ref sampleStatus, value); SampleTest(value); } } private string _currentUserCode; public string CurrentUserCode { get { return _currentUserCode; } set { Set(ref _currentUserCode, value); } } private bool isLoadOK = false; private int PassAmount = 0; private int FailAmount = 0; /// /// Socket数量 /// private int socketNum = 1; private ProductData selectedProduct; private MSMQHelper mSMQHelper = new MSMQHelper("HMI_Alarm"); public ProductData SelectedProduct { get { return selectedProduct; } set { Set(ref selectedProduct, value); CurrentProductModel = value?.Name; if (tsSockets != null) { foreach (SingleControl socket in tsSockets) { socket.RefreshProduct(value); // socket.RefreshProbeCount(value); } } SetTestSeqFile(value); } } private string currentProductModel; public string CurrentProductModel { get => currentProductModel; set { Set(ref currentProductModel, value); } } public override void SetLogger(ILog logger) { base.SetLogger(logger); StandardTestUI.logger = logger; } private ObservableCollection products; public ObservableCollection Products { get { return products; } set { Set(ref products, value); } } public List FontSizeSource { get; set; } = new List { 10,11,12,13,14,15,16,17,18,19,20 }; private string CountIniPath; private bool IsOptRequirePassword; private bool alarmVisiable; public bool AlarmVisiable { get => alarmVisiable; set { Set(ref alarmVisiable, value); } } private bool _enableMes; public bool EnableMes { get => _enableMes; set { if (RequirePassword() == true) { if (WriteConfig("EnableMes", value)) { Set(ref _enableMes, value); } } } } private bool _enableCanLog; public bool EnableCanLog { get => _enableCanLog; set { if (RequirePassword() == true) { if (WriteConfig("EnableCanLog", value)) { Set(ref _enableCanLog, value); } } } } private bool _enableDebugMode; public bool EnableDebugMode { get => _enableDebugMode; set { if (RequirePassword() == true) { if (WriteConfig("EnableDebugMode", value)) { Set(ref _enableDebugMode, value); } } } } private bool _enableNGPause; public bool EnableNGPause { get => _enableNGPause; set { if (RequirePassword() == true) { if (WriteConfig("EnableNGPause", value)) { Set(ref _enableNGPause, value); } } } } private bool _enableSimpleMode; public bool EnableSimpleMode { get => _enableSimpleMode; set { if (RequirePassword() == true) { if (WriteConfig("EnableSimpleMode", value)) { Set(ref _enableSimpleMode, value); foreach (var cell in tsSockets) cell.SetSimpleUI(value); } } } } private bool _ui_showInfoDock; public bool UI_ShowInfoDock { get => _ui_showInfoDock; set { if (RequirePassword() == true) { if (WriteConfig("UI_ShowInfoDock", value)) { Set(ref _ui_showInfoDock, value); detailPanel.Visibility = value ? Visibility.Visible : Visibility.Collapsed; } } } } private bool autoExecuteSeq; public bool AutoExecuteSeq { get => autoExecuteSeq; set { Set(ref autoExecuteSeq, value); } } private string currentWorkorder; public string CurrentWorkorder { get => currentWorkorder; set { if (WriteIni("UI_CurrentWorkorder", value)) { Set(ref currentWorkorder, value); testExecutionWrapper?.SetStationGlobalValue("StationState.WorkOrder", 1, value); testExecutionWrapper?.CommitToDisk(false); } } } private bool _DisableScanner; public bool DisableScanner { get => _DisableScanner; set { if (RequirePassword() == true) { if (WriteConfig("DisableScanner", value)) { Set(ref _DisableScanner, value); } } } } private bool enableManualDebug; public bool EnableManualDebug { get => enableManualDebug; set { if (IsTesting) { MsgBoxHelper2.Warn("请先结束自动测试"); return; } Set(ref enableManualDebug, value); } } public string tsModelPath { get; private set; } private string dataLogPath; private SqliteHelper sqliteHelper; private int probeWarn; #region 图表 private SolidColorPaint tooltipTextPaint = new SolidColorPaint(SKColors.Black) { SKTypeface = SKFontManager.Default.MatchCharacter('汉') }; public SolidColorPaint TooltipTextPaint { get => tooltipTextPaint; set { Set(ref tooltipTextPaint, value); } } public ISeries[] Chart1_series { get; set; } = new PieSeries[] { new PieSeries { Name="Passed", Values = new double[]{ 0}, DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Outer, DataLabelsSize = 15, DataLabelsPaint = new SolidColorPaint(new SKColor(30, 30, 30)){ SKTypeface = SKFontManager.Default.MatchCharacter('汉') }, Fill = new SolidColorPaint(new SKColor(0, 128, 0)), DataLabelsFormatter = point =>point.StackedValue.Total>0? $"Passed\r\n计数:{point.Coordinate.PrimaryValue}\r\n占比:{point.StackedValue.Share:P2}":"", ToolTipLabelFormatter = point => $"{point.StackedValue.Share:P2}" }, new PieSeries { Values = new double[]{ 0} , Name="Failed", DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.Outer, DataLabelsSize = 15, DataLabelsPaint = new SolidColorPaint(new SKColor(30, 30, 30)){ SKTypeface = SKFontManager.Default.MatchCharacter('汉') }, Fill = new SolidColorPaint(new SKColor(255, 0, 0)), DataLabelsFormatter = point =>point.StackedValue.Total>0? $"Failed\r\n计数:{point.Coordinate.PrimaryValue}\r\n占比:{point.StackedValue.Share:P2}":"", ToolTipLabelFormatter = point => $"{point.StackedValue.Share:P2}"}, }; #endregion public StandardTestUI() { DataContext = this; InitializeComponent(); InitChart(); InitTsEngine(); } public override void SetBaseFolder(string folder) { CountIniPath = Path.Combine(folder, "Count.ini"); base.SetBaseFolder(folder); } private void CheckSqlHelper() { string today = DateTime.Now.ToString("yyyyMMdd"); string dbPath = Path.Combine(dataLogPath, $"Data_{today}.db"); if (!File.Exists(dbPath)) { SqliteHelper.CreateDatabase(dbPath); } if (sqliteHelper == null || sqliteHelper.DataBaseFile != dbPath) { sqliteHelper?.Dispose(); sqliteHelper = new SqliteHelper(dbPath); sqliteHelper.ExecuteSql(@"CREATE TABLE IF NOT EXISTS serialData ( id INTEGER PRIMARY KEY AUTOINCREMENT, sn TEXT NOT NULL, model TEXT, station TEXT NOT NULL, step TEXT NOT NULL, position TEXT, limitDown TEXT, limitUp TEXT, unit TEXT, offset TEXT, value TEXT, status TEXT, finalStatus TEXT, consumeTime TEXT, totalConsumeTime TEXT, time DATETIME NOT NULL);"); sqliteHelper.ExecuteSql(@"CREATE TABLE IF NOT EXISTS testResult ( id INTEGER PRIMARY KEY AUTOINCREMENT, sn TEXT NOT NULL, model TEXT, station TEXT NOT NULL, position TEXT, status TEXT, result TEXT NOT NULL, time DATETIME NOT NULL);"); } } public override void InitFinish() { this.ReadCount(out int pass, out int fail); this.DisplayCount(pass, fail); ReadConfig(); InitProducts(); CheckSqlHelper(); base.InitFinish(); if (ParamSetting.EnableAutoModel) { selectModelPanel.Visibility = Visibility.Collapsed; autoModelPanel.Visibility = Visibility.Visible; CurrentProductModel = string.Empty; } try { UserInfo user = UserInfo.User; CurrentUserCode = user?.Code; testExecutionWrapper?.SetStationGlobalValue("StationState.OPID", 1, CurrentUserCode); testExecutionWrapper?.CommitToDisk(false); } catch (Exception ex) { log.Warn("Get Login User Failed.", ex); } RefreshUIConfig(); } /// /// 刷新UI配置 /// private void RefreshUIConfig() { try { bool enableManualDebug = ParameterManager.GetCommonParameterByName("EnableManualDebug", false); if (enableManualDebug) { Cb_ManualDebug.Visibility = Visibility.Visible; EnableManualDebug = false; } else { Cb_ManualDebug.Visibility = Visibility.Collapsed; EnableManualDebug = false; } } catch (Exception ex) { log.Error("RefreshUIConfig Error.", ex); } } //private MQConnector mqConnector; //private void InitMQ() //{ // mqConnector = new MQConnector("UI"); // mqConnector.BeginReceive(HandleMQUI); //} //void HandleMQUI(string msg) //{ // string[] arr = msg.Split('|'); // int eventCode = int.Parse(arr[0]); // int index = int.Parse(arr[1]); // string strData = arr[2]; // Dispatcher.BeginInvoke(new Action(() => // { // HandleUIMessage(eventCode, index, strData); // })); //} /// /// 初始化Winform图表 /// private void InitChart() { // pieChart.Plot.Axes.Frameless(); // pieChart.Plot.HideGrid(); // pieChart.Plot.DataBackground.Color = ScottPlot.Colors.Transparent; // var legend = pieChart.Plot.ShowLegend(Alignment.UpperRight); // legend.Alignment = Alignment.UpperRight; // legend.Padding = new PixelPadding(0); // legend.FontSize = (float)WidthSizeConverter.CountFontSize(20, 300, 300); // pieChart.UserInputProcessor.Disable(); // pieChart.Plot.Font.Automatic(); // List slices = new List { //new PieSlice() { Value = 5, FillColor = ScottPlot.Colors.Green, // LabelFontSize = (float)WidthSizeConverter.CountFontSize(20,300,300), // Label = "Pass",LegendText="Pass" }, //new PieSlice() { Value = 2, FillColor = ScottPlot.Colors.Red, // LabelFontSize = (float)WidthSizeConverter.CountFontSize(20,300,300), // Label = "Fail",LegendText="Fail" } }; // pie = pieChart.Plot.Add.Pie(slices); } private bool? RequirePassword() { if (!IsOptRequirePassword) return true; var win = new RequirePasswordWindow { Owner = Window.GetWindow(this) }; return win.ShowDialog(); } private void InitProducts() { RefershUI(); //Products = ProductManager.GetProducts>(); //if (Products != null && Products.Count > 0) //{ // string lastModel = testExecutionWrapper?.GetStationGlobalValue("StationState.ProductModel", 1); // var tempProduct = Products[0]; // if (!string.IsNullOrEmpty(lastModel)) // { // var product = Products.FirstOrDefault(p => p.Name == lastModel); // if (product != null) // { // tempProduct = product; // } // } // SelectedProduct = tempProduct; //} //RefershUI(); //if (tsSockets != null) //{ // foreach (SingleControl socket in tsSockets) // { // socket.RefreshProduct(SelectedProduct); // } //} //SampleStatus = false; } private bool _isTesting = false; public bool IsTesting { get { return _isTesting; } set { Set(ref _isTesting, value); Dispatcher.Invoke(() => { BtnStartSeq.IsEnabled = !value; BtnStopSeq.IsEnabled = value; CbProduct.IsEnabled = !value; }); } } /// /// 初始化TestStand引擎 /// private void InitTsEngine() { if (ParamSetting.EngineType == "Tap") { testExecutionWrapper = new TapWrapper(); } else { testExecutionWrapper = new TeststandWrapper(); } testExecutionWrapper.EndExecutionEvent += TestExecutionWrapper_EndExecutionEvent; testExecutionWrapper.UIMessageEvent += TestExecutionWrapper_UIMessageEvent; if (testExecutionWrapper is TeststandWrapper tsw) { var AxApplicationMgr = tsw.AxApplicationMgr; ((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).BeginInit(); host.Child = AxApplicationMgr; ((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).EndInit(); } try { testSeqFile = ParameterManager.GetCommonParameterByName("BurnInMainSeq", string.Empty); } catch { } testExecutionWrapper.Init(); } private void TestExecutionWrapper_UIMessageEvent(object sender, UIMessageEvent e) { try { int eventCode = Convert.ToInt32(e.EventCode); int MethodCode = Convert.ToInt16(e.NumberData);//SocketIndex var data = e.Data; string strData = e.StrData; try { log.Debug($"Event: {eventCode}, MethodCode: {MethodCode}, StringData: {strData}"); } catch { } HandleUIMessage(eventCode, MethodCode, strData, data); } catch (Exception ex) { log.Warn("Ts Event Error.", ex); } } private void TestExecutionWrapper_EndExecutionEvent(object sender, ExecutionEndEvent e) { log.Info("AxApplicationMgr_EndExecution"); if (ReleaseSequenceFile()) { IsTesting = false; log.Info("Release SeqFile Success!"); if (canSwitchModel) switchAction?.Invoke(); } else { log.Warn("Release SeqFile Fail!"); } } private volatile bool canSwitchModel = false; private volatile Action switchAction = null; private void PluginControl_Loaded(object sender, RoutedEventArgs e) { ShowMask(() => { try { //Dispatcher.Invoke(() => //{ //}); isLoadOK = true; if (AutoExecuteSeq) 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; }); }, (ex) => { ToastHelper.Error("Loaded Failed."); log.Error("Loaded Error.", ex); }, null, LangUtil.Get("App.UsercontrolIsLoading")); } private void RefershUI() { panel.Children.Clear(); string[] names = ParamSetting.SocketNames.Split(','); //重新生成子面板 for (int i = 0; i < this.socketNum; i++) { string name = string.Empty; if (i < names.Length) { name = names[i]; } SingleControl control = new SingleControl(i, CountIniPath, this.probeWarn) { SocketName = name }; control.parent = this; panel.Children.Add(control); tsSockets.Add(control); //createChildInNewThread(i, CountIniPath, ProbeWarn); } if (tsSockets.Count == 1) { panel.Columns = 1; } else if (tsSockets.Count > 0 && (tsSockets.Count % 3) == 0) { panel.Columns = 3; } else { panel.Columns = 2; } } /// /// 读取Count配置文件的pass和fail数 /// /// 合格数 /// 不合格数 private void ReadCount(out int pass, out int fail) { pass = Convert.ToInt32(IniFileHelper.ReadIniData("Count", "Pass", "0", CountIniPath)); fail = Convert.ToInt32(IniFileHelper.ReadIniData("Count", "Fail", "0", CountIniPath)); var fontSize = Convert.ToDouble(IniFileHelper.ReadIniData("Config", "TableFontSize", "12", CountIniPath)); this.Resources["tableFontSize"] = 20d; //CbFontSize.SelectedItem = fontSize; } private string csvDir; /// /// 读取配置文件里的几个属性 /// /// /// private void ReadConfig() { HMI.Core.Entity.ParameterData value; bool flag = false; try { value = ParameterManager.GetCommonParameterByName("DefaultEnableMes"); if (value != null) { flag = bool.Parse(value.Value); } } catch { flag = false; } try { value = ParameterManager.GetCommonParameterByName("SocketNum"); if (value != null) { this.socketNum = int.Parse(value.Value); } } catch { this.socketNum = 2; } if (flag) { EnableMes = true; } else { try { value = ParameterManager.GetCommonParameterByName("EnableMes"); if (value == null) { CbEnableMes.Visibility = Visibility.Collapsed; } else { _enableMes = bool.Parse(value.Value); Set("EnableMes"); } } catch { _enableMes = false; Set("EnableMes"); } } try { value = ParameterManager.GetCommonParameterByName("EnableNGPause"); if (value == null) { CbEnableNGPause.Visibility = Visibility.Collapsed; } else { _enableNGPause = bool.Parse(value.Value); Set("EnableNGPause"); } } catch { _enableNGPause = false; Set("EnableNGPause"); } try { value = ParameterManager.GetCommonParameterByName("EnableDebugMode"); if (value == null) { CbEnableDebugMode.Visibility = Visibility.Collapsed; } else { _enableDebugMode = bool.Parse(value.Value); Set("EnableDebugMode"); } } catch { _enableDebugMode = false; Set("EnableDebugMode"); } try { value = ParameterManager.GetCommonParameterByName("DisableScanner"); if (value == null) { CbDisableScanner.Visibility = Visibility.Collapsed; } else { _DisableScanner = bool.Parse(value.Value); Set("DisableScanner"); } } catch { _DisableScanner = false; Set("DisableScanner"); } try { value = ParameterManager.GetCommonParameterByName("EnableCanLog"); _enableCanLog = bool.Parse(value.Value); Set("EnableCanLog"); } catch { _enableCanLog = false; Set("EnableCanLog"); } try { value = ParameterManager.GetCommonParameterByName("EnableSimpleMode"); if (value == null) { CbEnableSimpleMode.Visibility = Visibility.Collapsed; } else { EnableSimpleMode = bool.Parse(value.Value); } } catch { EnableSimpleMode = false; } try { value = ParameterManager.GetCommonParameterByName("UI_ShowInfoDock"); if (value == null) { CbUI_ShowInfoDock.Visibility = Visibility.Collapsed; } else { UI_ShowInfoDock = bool.Parse(value.Value); } } catch { UI_ShowInfoDock = false; } try { value = ParameterManager.GetCommonParameterByName("AutoExecuteSeq"); AutoExecuteSeq = bool.Parse(value.Value); } catch { AutoExecuteSeq = true; } try { value = ParameterManager.GetCommonParameterByName("TestReportFolder"); csvDir = value.Value; if (!Directory.Exists(csvDir)) { Directory.CreateDirectory(csvDir); } } catch { csvDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestReport"); } try { value = ParameterManager.GetCommonParameterByName("IsOptRequirePassword"); IsOptRequirePassword = bool.Parse(value.Value); } catch { IsOptRequirePassword = false; } try { value = ParameterManager.GetCommonParameterByName("UI_CurrentWorkorder"); CurrentWorkorder = value.Value; } catch { CurrentWorkorder = string.Empty; } try { value = ParameterManager.GetCommonParameterByName("TS_ShowTitleWorkorder"); var boo = bool.Parse(value.Value); if (boo) { workorderPanel.Visibility = Visibility.Visible; } } catch { } dataLogPath = ParamSetting.DataLogFolder; try { value = ParameterManager.GetCommonParameterByName("TsModelPath"); tsModelPath = value?.Value ?? @"C:\Users\Public\Documents\National Instruments\TestStand 2020 (64-bit)\Components\Models\ParallelModel.seq"; } catch { //@"C:\Program Files\National Instruments\TestStand 2020\Components\Models\TestStandModels\ParallelModel.seq" tsModelPath = @"C:\Users\Public\Documents\National Instruments\TestStand 2020 (64-bit)\Components\Models\ParallelModel.seq"; } try { value = ParameterManager.GetCommonParameterByName("ProbeWarn"); probeWarn = int.Parse(value?.Value); } catch { probeWarn = 0; } //Convert.ToBoolean(IniFileHelper.ReadIniData("Config", "EnableMes", "true", CountIniPath)); //EnableCanLog = Convert.ToBoolean(IniFileHelper.ReadIniData("Config", "EnableCanLog", "true", CountIniPath)); //EnableDebugMode = Convert.ToBoolean(IniFileHelper.ReadIniData("Config", "EnableDebugMode", "true", CountIniPath)); } private bool WriteConfig(string name, bool value) { try { if (ParameterManager.UpdateCommonParameter(name, value, out string errMsg)) { foreach (var ts in tsSockets) { testExecutionWrapper.SetStationGlobalValue($"SystemSetting.{name}", 1, value); if (testExecutionWrapper is TeststandWrapper tsw) { if (name == "EnableDebugMode" && tsw.context?.Sequence != null) { tsw.context.Sequence.FailureAction = value ? FailureActions.FailureAction_None : FailureActions.FailureAction_GotoCleanup; } } } return true; } else { throw new Exception(errMsg); } } catch (Exception ex) { MsgBoxHelper2.Error(ex.Message); return false; } } private bool WriteIni(string name, object value) { //IniFileHelper.WriteIniData("Config", name, value.ToString(), CountIniPath); try { if (ParameterManager.UpdateCommonParameter(name, value, out string errMsg)) { return true; } else { throw new Exception(errMsg); } } catch (Exception ex) { MsgBoxHelper2.Error(ex.Message); return false; } } private void WriteCount(double pass, double fail) { IniFileHelper.WriteIniData("Count", "Pass", pass.ToString(), CountIniPath); IniFileHelper.WriteIniData("Count", "Fail", fail.ToString(), CountIniPath); } /// /// 刷新计数 /// /// 合格数 /// 不合格数 private void DisplayCount(double pass, double fail) { double total = pass + fail; double passRate; if (total == 0) { passRate = 0.00; } else { passRate = (double)pass / (double)total * 100.00; } this.TbPass.Text = pass.ToString(); this.TbFail.Text = fail.ToString(); this.TbTotal.Text = total.ToString(); this.TbPassRate.Text = string.Format("{0:0.00}", passRate) + "%"; Dispatcher.BeginInvoke(new Action(() => { Chart1_series[0].Values = new double[] { pass }; Chart1_series[1].Values = new double[] { fail }; // webview2.CoreWebView2?.ExecuteScriptAsync($"drawChart1({res})"); })); WriteCount(pass, fail); } /// /// 启动样件测试 /// /// /// private void SampleTest(bool flag) { try { testExecutionWrapper.SetStationGlobalValue("StationState.Sample", 1, flag); } catch (Exception ex) { throw new Exception(LangUtil.Get("Ts.SampleTestFail"), ex); } } /// /// 启动测试序列 /// private void StartSequence() { log.Info($"Start ATE Seq isLoadOK:{isLoadOK}"); if (!isLoadOK) return; if (ParamSetting.EnableAutoModel) { try { var path = ParameterManager.GetCommonParameterByName("CommonMainSeq", ""); if (string.IsNullOrEmpty(path)) { Dispatcher.Invoke(() => { MsgBoxHelper.Error(this, $"请先设置CommonMainSeq参数"); }); return; } this.testSeqFile = path; testExecutionWrapper?.StartSequence(this.testSeqFile, this.tsModelPath); //this.modeSeq = this.engine.GetSequenceFileEx(tsModelPath); //this.testSeq = this.engine.GetSequenceFileEx(this.testSeqFile, 2, TypeConflictHandlerTypes.ConflictHandler_UseGlobalType); //this.execution = this.engine.NewExecution(this.testSeq, "Test UUTs", this.modeSeq, false, 0, null, null, null); IsTesting = true; } catch (Exception ex) { Dispatcher.Invoke(() => { log.Error("Start Sequence Failed.", ex); MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.StartSequenceFail")}: {ex.Message}"); }); } } else { //MaskWindow mask = new MaskWindow(); try { //for (int i = 0; i < tsSockets.Count; i++) //{ // testExecutionWrapper?.SetStationGlobalValue($"StationHMI.UUTHMI[{i}].Model", 1, CurrentProductModel); //} //testExecutionWrapper?.CommitToDisk(false); testExecutionWrapper?.StartSequence(this.testSeqFile, this.tsModelPath); IsTesting = true; } catch (Exception ex) { Dispatcher.Invoke(() => { log.Error("Start Sequence Failed.", ex); MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.StartSequenceFail")}: {ex.Message}"); }); } finally { } } } public void StopSequenceClick() { canSwitchModel = false; switchAction = null; ShowMask(() => { bool stoped = StopSequence(); }, null, null, LangUtil.Get("App.SequenceIsStopping")); } /// /// 停止测试序列 /// private bool StopSequence() { try { testExecutionWrapper.SetStationGlobalValue("StationHMI.AllStop", 1, true); //bool res = this.execution.WaitForEndEx(-1, true, null, null); bool res = this.testExecutionWrapper.WaitForExit(); //if (this.execution != null) // Marshal.ReleaseComObject(this.execution); //this.execution = null; return res; } catch (Exception ex) { log.Error("Stop Sequence Failed.", ex); MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.StopSequenceFail")}: {ex.Message}"); return false; } } private void Button_Click(object sender, RoutedEventArgs e) { Button btn = sender as Button; switch (btn.Name) { case "BtnStartSeq": StartClick(); break; case "BtnStopSeq": StopSequenceClick(); break; case "BtnClearNum": ClearNum(); break; case "BtnSample": SampleStatus = !SampleStatus; break; default: break; } } private void StartClick() { canSwitchModel = true; ShowMask(() => { StartSequence(); }, null, null, LangUtil.Get("Ts.SequenceIsStarting")); } public void UpdatePositionStatus(int index, string status) { this.tsSockets[index].UpdateStatus(status); OnStatusPublished(index, status); this.UpdateTestCounter(); } private void OnStatusPublished(int index, string status) { if (ParamSetting.CustomerCode != "SOUND") { return; } if (status == "Passed" || status == "Failed") { SaveSOUNDExcel(index, status); } } private string ConvertStatus(string status) { if (string.Equals(status, "passed", StringComparison.OrdinalIgnoreCase)) { return "Pass"; } else { return "Fail"; } } #region 桑德定制 private ICell CreateCell(ISheet sheet, int r, int c, ICellStyle style) { var row = sheet.GetRow(r); if (row == null) { row = sheet.CreateRow(r); } var cell = row.GetCell(c); if (cell == null) { cell = row.CreateCell(c); } if (style != null) { cell.CellStyle = style; } return cell; } private string GetOutputFolder() { var value = ParameterManager.GetCommonParameterByName("SOUND_Output"); if (value != null) { return value.Value; } return ParamSetting.DataLogFolder; } private void SaveSOUNDExcel(int index, string status) { lock (this) { try { string outputFolder = GetOutputFolder(); var socket = this.tsSockets[index]; DateTime testTime = DateTime.Now; string filePath = Path.Combine(outputFolder, $"{testTime.ToString("yy-MM-dd")}_{CurrentProductModel}.xls"); if (!File.Exists(filePath)) { Dictionary columnMap = new Dictionary(); HSSFWorkbook workbook = new HSSFWorkbook(); ISheet sheet = workbook.CreateSheet("Sheet1"); ICellStyle border = workbook.CreateCellStyle(); border.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin; border.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin; border.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin; border.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin; border.BottomBorderColor = NPOI.HSSF.Util.HSSFColor.Black.Index; border.TopBorderColor = NPOI.HSSF.Util.HSSFColor.Black.Index; border.LeftBorderColor = NPOI.HSSF.Util.HSSFColor.Black.Index; border.RightBorderColor = NPOI.HSSF.Util.HSSFColor.Black.Index; ICellStyle red = workbook.CreateCellStyle(); red.CloneStyleFrom(border); red.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Red.Index; red.FillPattern = FillPattern.SolidForeground; ICellStyle green = workbook.CreateCellStyle(); green.CloneStyleFrom(border); green.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.BrightGreen.Index; green.FillPattern = FillPattern.SolidForeground; CreateCell(sheet, 1, 0, border); CreateCell(sheet, 1, 1, border); CreateCell(sheet, 1, 2, border); CreateCell(sheet, 1, 3, border); CreateCell(sheet, 1, 4, border); CreateCell(sheet, 2, 0, border); CreateCell(sheet, 2, 1, border); CreateCell(sheet, 2, 2, border); CreateCell(sheet, 2, 3, border); CreateCell(sheet, 2, 4, border).SetCellValue("上限"); CreateCell(sheet, 3, 0, border).SetCellValue("测试时间"); CreateCell(sheet, 3, 1, border).SetCellValue("测试人"); CreateCell(sheet, 3, 2, border).SetCellValue("测试设备"); CreateCell(sheet, 3, 3, border).SetCellValue("条形码"); CreateCell(sheet, 3, 4, border).SetCellValue("下限"); int column = 5; int row = 4; CreateCell(sheet, row, 0, border).SetCellValue(testTime.ToString("*HH:mm:ss*")); CreateCell(sheet, row, 1, border).SetCellValue(UserInfo.User.Name); CreateCell(sheet, row, 2, border).SetCellValue(ParamSetting.StationName); CreateCell(sheet, row, 3, border).SetCellValue(socket.Barcode); CreateCell(sheet, row, 4, status == "Passed" ? green : red).SetCellValue(ConvertStatus(status)); foreach (var data in socket.Datasource) { int col = column; if (columnMap.ContainsKey(data.Name)) { col = columnMap[data.Name]; } else { columnMap[data.Name] = column++; } CreateCell(sheet, 1, col, border).SetCellValue(data.Name); CreateCell(sheet, 2, col, border).SetCellValue(data.LimitUp); CreateCell(sheet, 3, col, border).SetCellValue(data.LimitDown); CreateCell(sheet, row, col, data.Result == "Failed" ? red : border).SetCellValue(data.Value); } using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate)) { workbook.Write(fs); } } else { using (FileStream fs = File.OpenRead(filePath)) { IWorkbook workbook = new HSSFWorkbook(fs); ICellStyle border = workbook.CreateCellStyle(); border.BorderBottom = NPOI.SS.UserModel.BorderStyle.Thin; border.BorderTop = NPOI.SS.UserModel.BorderStyle.Thin; border.BorderLeft = NPOI.SS.UserModel.BorderStyle.Thin; border.BorderRight = NPOI.SS.UserModel.BorderStyle.Thin; border.BottomBorderColor = NPOI.HSSF.Util.HSSFColor.Black.Index; border.TopBorderColor = NPOI.HSSF.Util.HSSFColor.Black.Index; border.LeftBorderColor = NPOI.HSSF.Util.HSSFColor.Black.Index; border.RightBorderColor = NPOI.HSSF.Util.HSSFColor.Black.Index; ICellStyle red = workbook.CreateCellStyle(); red.CloneStyleFrom(border); red.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.Red.Index; red.FillPattern = FillPattern.SolidForeground; ICellStyle green = workbook.CreateCellStyle(); green.CloneStyleFrom(border); green.FillForegroundColor = NPOI.HSSF.Util.HSSFColor.BrightGreen.Index; green.FillPattern = FillPattern.SolidForeground; ISheet sheet = workbook.GetSheet("Sheet1"); Dictionary columnMap = new Dictionary(); var titleRow = sheet.GetRow(1); for (int i = 0; i < titleRow.LastCellNum; i++) { if (!string.IsNullOrEmpty(titleRow.GetCell(i).StringCellValue)) { columnMap[titleRow.GetCell(i).StringCellValue] = i; } } int row = sheet.LastRowNum + 1; CreateCell(sheet, row, 0, border).SetCellValue(testTime.ToString("*HH:mm:ss*")); CreateCell(sheet, row, 1, border).SetCellValue(UserInfo.User.Name); CreateCell(sheet, row, 2, border).SetCellValue(ParamSetting.StationName); CreateCell(sheet, row, 3, border).SetCellValue(socket.Barcode); CreateCell(sheet, row, 4, status == "Passed" ? green : red).SetCellValue(ConvertStatus(status)); foreach (var data in socket.Datasource) { int col = titleRow.LastCellNum; if (columnMap.ContainsKey(data.Name)) { col = columnMap[data.Name]; } else { columnMap[data.Name] = col; } CreateCell(sheet, 1, col, border).SetCellValue(data.Name); CreateCell(sheet, 2, col, border).SetCellValue(data.LimitUp); CreateCell(sheet, 3, col, border).SetCellValue(data.LimitDown); CreateCell(sheet, row, col, data.Result == "Failed" ? red : border).SetCellValue(data.Value); } using (FileStream nfs = new FileStream(filePath, FileMode.OpenOrCreate)) { workbook.Write(nfs); } } } } catch (Exception ex) { log.Error("SOUND Export Excel Data Error.", ex); } } } #endregion public void UpdatePositionProcessValue(int index, int value) { this.tsSockets[index].SetTestProcess(value); } public void PausePosition(int index) { this.tsSockets[index].ShowPausePanel(); } public void AddTestData(int index, string data) { string[] TestItems = data.Split(','); tsSockets[index].AddTestData(TestItems[0], TestItems[1], TestItems[2], TestItems[3], TestItems[4], TestItems[5], TestItems[6]); } public void SetPositionBarcode(int index, string strData) { if (strData.Contains(";")) { var strs = strData.Split(';'); this.tsSockets[index].Barcode = strs[0]; this.tsSockets[index].Model = strs[1]; } else { this.tsSockets[index].Barcode = strData; } } public void SavePositionCSV(int index, string csvPath) { //var time = DateTime.Now; //string status = this.tsSockets[index].Status == "Passed" ? "PASS" : "FAIL"; //string csvPath = Path.Combine(csvDir, SelectedProduct?.Name ?? "未知产品", time.ToString("yyyyMMdd"), status, // $"{this.tsSockets[index].Barcode}-{time.ToString("HHmmss")}.csv"); this.tsSockets[index].WriteToCSV(csvPath); } public void SaveTemplateCSV(int index) { var time = DateTime.Now; string status = this.tsSockets[index].Status == "Passed" ? "PASS" : "FAIL"; string csvPath = Path.Combine(csvDir, CurrentProductModel ?? "未知产品", time.ToString("yyyyMMdd"), status, $"{this.tsSockets[index].Barcode}-{time.ToString("HHmmss")}.csv"); this.tsSockets[index].WriteToCSV(csvPath); } public void SavePositionDB(int index, string status) { CheckSqlHelper(); var socket = this.tsSockets[index]; var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string snr = socket.Barcode; string model = CurrentProductModel; List sqls = new List(); foreach (var data in socket.Datasource) { sqls.Add($@"INSERT INTO serialData (sn,model,station,step,position,limitDown,limitUp,unit,value,status,finalStatus,consumeTime,totalConsumeTime,time) VALUES ('{snr}','{model}','','{data.Name}','{index}','{data.LimitDown}','{data.LimitUp}','{data.Unit}','{data.Value}','{data.Result}','{socket.Status}','{data.ConsumeTime}','{socket.ElapseTime}','{time}')"); } sqliteHelper.ExecuteBatchSql(sqls); var ssql = $@"INSERT INTO testResult (sn,model,station,result,time,position,status) VALUES ('{snr}','{model}','','{socket.Status}','{time}','{index}','{status}')"; sqliteHelper.ExecuteSql(ssql); } private void HandleUIMessage(int eventCode, int MethodCode, string strData, object xData) { if (eventCode == 10035) { string[] arr_10035 = strData.Split(';'); int[][] points = new int[arr_10035.Length - 1][]; for (int i = 1; i < arr_10035.Length; i++) { string[] strs = arr_10035[i].Split(','); points[i - 1] = new int[2] { int.Parse(strs[0]), int.Parse(strs[1]) }; } this.tsSockets[MethodCode].DrawScreenPoints(int.Parse(arr_10035[0]), points); return; } else if (eventCode == 100350) { string[] arr_100350 = strData.Split(';'); int[][] points_0 = new int[arr_100350.Length - 1][]; for (int i = 1; i < arr_100350.Length; i++) { if (string.IsNullOrEmpty(arr_100350[i])) { continue; } string[] strs = arr_100350[i].Split(','); points_0[i - 1] = new int[2] { int.Parse(strs[0]), int.Parse(strs[1]) }; } this.tsSockets[MethodCode].DrawNewScreenPoints(int.Parse(arr_100350[0]), points_0); return; } else if (eventCode == 10036) { this.tsSockets[MethodCode].ClearScreenPoint(int.Parse(strData)); return; } else if (eventCode == 10036) { this.tsSockets[MethodCode].ClearScreenPoint(int.Parse(strData)); return; } if (MethodCode == 0) { /// 设置句柄 testExecutionWrapper?.SetContext((SequenceContext)xData); return; } if (MethodCode == 3) { /// 更新炉子时间信息 string[] datas_10014 = strData.Split(';'); int ovenIndex = int.Parse(datas_10014[0]); string startTime = datas_10014[1]; string consumeTime = datas_10014[2]; string planEndTime = datas_10014[3]; tsSockets[ovenIndex].ElapseTime = consumeTime; return; } else if (MethodCode == 4) { /// 修改工位底部信息栏 string[] datas_10014 = strData.Split(';'); int ovenIndex = int.Parse(datas_10014[0]); string statusBar = datas_10014[1]; this.tsSockets[ovenIndex].CurrentStep = statusBar; return; } else if (MethodCode == 6) { Dispatcher.Invoke(() => {/// 更新穴位状态 string[] datas_10015 = strData.Split(';'); int ovenIndex = int.Parse(datas_10015[0]); int cellIndex = int.Parse(datas_10015[1]); string status_10015 = datas_10015[2]; UpdatePositionStatus(ovenIndex, status_10015); }); return; } else if (MethodCode == 9) { if (string.Equals(strData, "stop", StringComparison.OrdinalIgnoreCase)) { IsTesting = false; } return; } else if (MethodCode == 11) { // 清空测试数据 string[] datas_10015 = strData.Split(';'); int ovenIndex = int.Parse(datas_10015[0]); this.tsSockets[ovenIndex].IniTestData(); return; } else if (MethodCode == 18) { string[] datas = strData.Split(';'); int ovenIndex = int.Parse(datas[0]); int cellIndex = int.Parse(datas[1]); string filePath = datas[2]; if (ParamSetting.CustomerCode == "SOUND") { this.tsSockets[ovenIndex].WriteToExcel(filePath); Dispatcher.Invoke(() => { SavePositionDB(ovenIndex, tsSockets[ovenIndex].Status); }); return; } try { SavePositionCSV(ovenIndex, filePath); Dispatcher.Invoke(() => { var sss = this.tsSockets[ovenIndex].Status; SavePositionDB(ovenIndex, sss); }); } catch (Exception ex) { log.Warn("写CSV/DB数据失败.", ex); SaveTemplateCSV(ovenIndex); } return; } else if (MethodCode == 9000) { //更新型号 string[] datas = strData.Split(';'); int ovenIndex = int.Parse(datas[0]); int cellIndex = int.Parse(datas[1]); CurrentProductModel = datas[2]; return; } else if (MethodCode == 9001) { //更新条码 string[] datas = strData.Split(';'); int ovenIndex = int.Parse(datas[0]); int cellIndex = int.Parse(datas[1]); SetPositionBarcode(ovenIndex, datas[2]); return; } else if (MethodCode == 9002) { //显示测试进度 string[] datas = strData.Split(';'); int ovenIndex = int.Parse(datas[0]); int cellIndex = int.Parse(datas[1]); int ProcessVal = Convert.ToInt32(datas[2]); this.tsSockets[ovenIndex].SetTestProcess(ProcessVal); return; } else if (MethodCode == 9003) { //开始计时 string[] datas = strData.Split(';'); int ovenIndex = int.Parse(datas[0]); int cellIndex = int.Parse(datas[1]); tsSockets[ovenIndex].ElapseTime = "Start Timing"; return; } else if (MethodCode == 9004) { //结束计时 string[] datas = strData.Split(';'); int ovenIndex = int.Parse(datas[0]); int cellIndex = int.Parse(datas[1]); tsSockets[ovenIndex].ElapseTime = "Stop Timing"; return; } else if (MethodCode == 9005) { //手动设置耗时 string[] datas = strData.Split(';'); int ovenIndex = int.Parse(datas[0]); int cellIndex = int.Parse(datas[1]); tsSockets[ovenIndex].ElapseTime = datas[2]; return; } } private void SwitchSequenceByModel(int index, string model, string snr) { Dispatcher.Invoke(() => { var target = Products.FirstOrDefault(e => e.Name == model); ShowMask(() => { bool stoped = StopSequence(); //if (stoped) //{ // IsTesting = false; //} }, null, null, "换型中,请稍后..."); if (target == null) { MsgBoxHelper2.Warn($"请先在产品管理页面配置型号 [{model}] 的产品信息!"); return; } switchAction = () => { switchAction = null; log?.Info($"尝试自动换型: {switchAction}"); if (canSwitchModel) { Dispatcher.Invoke(() => { try { log?.Info("开始自动换型"); SelectedProduct = target; testExecutionWrapper?.SetStationGlobalValue($"CacheSNR[{index}]", 1, snr); testExecutionWrapper?.CommitToDisk(false); StartClick(); } catch (Exception ex) { log?.Error("自动换型失败", ex); } }); } }; }); } private void ShowAlarm(AlarmText alarm) { AlarmShowHelper.ShowAlarm(alarm); mSMQHelper.Send("Alarm", "PC", $"ATE测试 {alarm.AlarmInfo}", 2); } private void UpdateTestCounter() { double PassNum = 0; double FailNum = 0; foreach (SingleControl socket in this.tsSockets) { PassNum += socket.PassNum; FailNum += socket.FailNum; } this.DisplayCount(PassNum, FailNum); } 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(); if (AutoExecuteSeq) { StartSequence(); } } private void ClearNum() { if (MsgBoxHelper.WarnMessage(Window.GetWindow(this), LangUtil.Get("Ts.MakeSureClearNum")) == MessageBoxResult.OK) { PassAmount = 0; FailAmount = 0; //this.OpcHandle.DoFctWriteSingle("Count_Clear", "1", out string ErrMsg); foreach (SingleControl socket in tsSockets) { socket.ResetCounter(); } DisplayCount(PassAmount, FailAmount); } } public override void OnClose(object sender, CancelEventArgs e) { try { StopSequence(); base.OnClose(sender, e); } catch (Exception ex) { log.Error("OnClose Error.", ex); } } public override void DoClose(object sender, EventArgs e) { testExecutionWrapper.Dispose(); base.DoClose(sender, e); } /// /// 释放所有的序列文件 /// private bool ReleaseSequenceFile() { try { lock (this) { //execution.Abort(); int count = 10; while (count > 0) { try { return testExecutionWrapper.ReleaseSeqFile(); } catch (Exception ex) { log.Warn($"ReleaseSequenceFile In {count} Times Fail.", ex); count--; System.Threading.Thread.Sleep(1000); } } log.Warn($"ReleaseSequenceFile Failed."); return false; } } catch (Exception ex) { log.Warn("ReleaseSequenceFile Error.", ex); return false; } } private void PluginControl_SizeChanged(object sender, SizeChangedEventArgs e) { } private void CbFontSize_SelectionChanged(object sender, SelectionChangedEventArgs e) { try { if (e.AddedItems != null && e.AddedItems.Count > 0) { var fontSize = (double)e.AddedItems[0]; this.Resources["tableFontSize"] = fontSize; IniFileHelper.WriteIniData("Config", "TableFontSize", fontSize.ToString(), CountIniPath); } } catch { } } private void Label_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e) { //workOrderEditor.Focus(); //workOrderEditor.IsEditing = true; if (RequirePassword() == true) { var win = new WorkOrderWin { WorkOrder = CurrentWorkorder, Owner = Window.GetWindow(this) }; if (win.ShowDialog() == true) { CurrentWorkorder = win.WorkOrder; } } } } }