alielie
2025-08-25 c4a3f8db90530a727ffab77c3bb5bb7d782792bf
Plugin.TsExecution/TsExecution.xaml.cs
@@ -1,9 +1,12 @@
using HMI.Base;
using HMI.Core;
using HMI.Core.Api;
using HMI.Core.Entity;
using HMI.Core.Manager;
using HMI.Core.Util;
using HMI.MQUtil;
using HMI.UI;
using HMI.UI.Controls;
using HMI.UI.Util;
using HMI.Util;
using log4net;
@@ -22,6 +25,7 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.DataVisualization.Charting;
using System.Windows.Media;
namespace Plugin.TsExecution
{
@@ -90,6 +94,8 @@
        private ProductData selectedProduct;
        private MSMQHelper mSMQHelper = new MSMQHelper("HMI_Alarm");
        public ProductData SelectedProduct
        {
            get { return selectedProduct; }
@@ -119,6 +125,7 @@
        private Pie pie;
        private string CountIniPath;
        private bool IsOptRequirePassword;
        private bool alarmVisiable;
        public bool AlarmVisiable
@@ -136,9 +143,12 @@
            get => _enableMes;
            set
            {
                if (WriteConfig("EnableMes", value))
                if (RequirePassword() == true)
                {
                    Set(ref _enableMes, value);
                    if (WriteConfig("EnableMes", value))
                    {
                        Set(ref _enableMes, value);
                    }
                }
            }
        }
@@ -162,9 +172,12 @@
            get => _enableDebugMode;
            set
            {
                if (WriteConfig("EnableDebugMode", value))
                if (RequirePassword() == true)
                {
                    Set(ref _enableDebugMode, value);
                    if (WriteConfig("EnableDebugMode", value))
                    {
                        Set(ref _enableDebugMode, value);
                    }
                }
            }
        }
@@ -175,9 +188,12 @@
            get => _enableNGPause;
            set
            {
                if (WriteConfig("EnableNGPause", value))
                if (RequirePassword() == true)
                {
                    Set(ref _enableNGPause, value);
                    if (WriteConfig("EnableNGPause", value))
                    {
                        Set(ref _enableNGPause, value);
                    }
                }
            }
        }
@@ -210,6 +226,34 @@
            }
        }
        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);
                }
            }
        }
        private string dataLogPath;
        private SqliteHelper sqliteHelper;
        private MQConnector mqConnector;
        public TsExecution()
        {
            DataContext = this;
@@ -220,7 +264,6 @@
            //初始化TestStand引擎
            this.InitTestStandEngine();
        }
        public override void SetBaseFolder(string folder)
        {
            CountIniPath = Path.Combine(folder, "Count.ini");
@@ -232,7 +275,70 @@
            this.ReadCount(out int pass, out int fail);
            this.DisplayCount(pass, fail);
            InitProducts();
            ReadConfig();
            if (!File.Exists(dataLogPath))
            {
                SqliteHelper.CreateDatabase(dataLogPath);
            }
            sqliteHelper = new SqliteHelper(dataLogPath);
            sqliteHelper.ExecuteSql(@"CREATE TABLE IF NOT EXISTS serialData (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    sn TEXT NOT NULL,
                    station TEXT NOT NULL,
                    step TEXT NOT NULL,
                    limitDown TEXT,
                    limitUp TEXT,
                    unit TEXT,
                    offset TEXT,
                    value TEXT,
                    status TEXT,
                    finalStatus TEXT,
                    consumeTime TEXT,
                    totalConsumeTime TEXT,
                    time DATETIME NOT NULL);");
            base.InitFinish();
        }
        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);
            }));
        }
        void createChildInNewThread(int index, string configFile, int probeWarn)
        {
            HostVisual hostVisual = new HostVisual();
            UIElement content = new VisualHost(hostVisual);
            System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(() =>
            {
                VisualTarget visualTarget = new VisualTarget(hostVisual);
                var control = new SingleControl(index, configFile, probeWarn);
                control.Arrange(new Rect(new Point(), content.RenderSize));
                visualTarget.RootVisual = control;
                tsSockets.Add(control);
                System.Windows.Threading.Dispatcher.Run();
            }));
            //panel.Children.Add(content);
            thread.SetApartmentState(System.Threading.ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
        }
        /// <summary>
@@ -242,7 +348,7 @@
        {
            pieChart.Plot.Axes.Frameless();
            pieChart.Plot.HideGrid();
            pieChart.Plot.DataBackground.Color = Colors.Transparent;
            pieChart.Plot.DataBackground.Color = ScottPlot.Colors.Transparent;
            var legend = pieChart.Plot.ShowLegend(Alignment.UpperRight);
            legend.Alignment = Alignment.UpperRight;
@@ -252,15 +358,25 @@
            pieChart.Plot.Font.Automatic();
            List<PieSlice> slices = new List<PieSlice> {
    new PieSlice() { Value = 5, FillColor = Colors.Green,
    new PieSlice() { Value = 5, FillColor = ScottPlot.Colors.Green,
        LabelFontSize = (float)WidthSizeConverter.CountFontSize(20,300,300),
        Label = "Pass",LegendText="Pass" },
    new PieSlice() { Value = 2, FillColor = Colors.Red,
    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()
@@ -315,6 +431,7 @@
        private void InitTsEngine()
        {
            AxApplicationMgr = new AxApplicationMgr();
            AxApplicationMgr.EndExecution += AxApplicationMgr_EndExecution;
            AxApplicationMgr.ExitApplication += new EventHandler(this.AxApplicationMgr_ExitApplication);
            AxApplicationMgr.UIMessageEvent +=
                new _ApplicationMgrEvents_UIMessageEventEventHandler(this.AxApplicationMgr_UIMessageEvent);
@@ -323,6 +440,11 @@
            ((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).BeginInit();
            host.Child = AxApplicationMgr;
            ((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).EndInit();
        }
        private void AxApplicationMgr_EndExecution(object sender, _ApplicationMgrEvents_EndExecutionEvent e)
        {
            ReleaseSequenceFile();
        }
        private void PluginControl_Loaded(object sender, RoutedEventArgs e)
@@ -343,10 +465,9 @@
                            {
                                log.Warn("Get Login User Failed.", ex);
                            }
                            ReadConfig();
                        });
                        isLoadOK = true;
                        StartSequence();
                        if (AutoExecuteSeq) StartSequence();
                    }
                    catch (Exception ex)
                    {
@@ -369,25 +490,6 @@
                    {
                        if (isLoadOK) Loaded -= PluginControl_Loaded;
                    });
                    //Dispatcher.Invoke(() =>
                    //{
                    //    try
                    //    {
                    //        ReadConfig();
                    //        //连接OPChandle
                    //        //this.OpcHandle.Connect2("127.0.0.1", 6543, 18081, out string ErrMsg, null);
                    //        isLoadOK = true;
                    //        //启动测试进程
                    //        StartSequence();
                    //    }
                    //    catch (Exception ex)
                    //    {
                    //        log.Error("TsExecution Loaded Failed.", ex);
                    //        MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.UserControlLoadFailed")}: {ex.Message}");
                    //    }
                    //});
                }
                ).Info(LangUtil.Get("App.UsercontrolIsLoading"));
        }
@@ -415,6 +517,8 @@
                SingleControl control = new SingleControl(i, CountIniPath, ProbeWarn);
                panel.Children.Add(control);
                tsSockets.Add(control);
                //createChildInNewThread(i, CountIniPath, ProbeWarn);
            }
            if (tsSockets.Count == 1)
            {
@@ -537,6 +641,16 @@
            try
            {
                value = ParameterManager.GetCommonParameterByName("AutoExecuteSeq");
                AutoExecuteSeq = bool.Parse(value.Value);
            }
            catch
            {
                AutoExecuteSeq = true;
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("TestReportFolder");
                csvDir = value.Value;
@@ -548,6 +662,55 @@
            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;
                Set("CurrentWorkorder");
            }
            catch
            {
                currentWorkorder = string.Empty;
                Set("CurrentWorkorder");
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("TS_ShowTitleWorkorder");
                var boo = bool.Parse(value.Value);
                if (boo)
                {
                    workorderPanel.Visibility = Visibility.Visible;
                }
            }
            catch
            {
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("TS_DataLogPath");
                dataLogPath = value.Value;
            }
            catch
            {
                dataLogPath = Path.Combine(PathHelper.ConfigFolder, "DataBoard", "DataLog.db");
            }
            //Convert.ToBoolean(IniFileHelper.ReadIniData("Config", "EnableMes", "true", CountIniPath));
@@ -577,6 +740,27 @@
                    {
                        ts?.SequenceFileContext?.StationGlobals.SetValBoolean($"SystemSetting.{name}", 1, value);
                    }
                    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
@@ -664,10 +848,6 @@
                engine?.CommitGlobalsToDisk(promptOnSaveConflicts: false);
                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);
                //var sb = testSeq.GetSequenceByName("MainSequence");
                //sb.
                this.execution = this.engine.NewExecution(this.testSeq, "Test UUTs", this.modeSeq, false, 0, null, null, null);
                IsTesting = true;
            }
@@ -706,10 +886,6 @@
                                win.Close();
                            });
                        }
                        //Dispatcher.Invoke(() =>
                        //{
                        //});
                    }
                    ).Info(LangUtil.Get("App.SequenceIsStopping"));
        }
@@ -736,7 +912,9 @@
                    }
                }
                if (this.execution == null) return true;
                return this.execution.WaitForEndEx(2000, true, null, null);
                bool res = this.execution.WaitForEndEx(2000, true, null, null);
                return res;
            }
            catch (Exception ex)
            {
@@ -805,21 +983,7 @@
        /// <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}");
            }
            ReleaseSequenceFile();
        }
        public void UpdatePositionStatus(int index, string status)
@@ -859,6 +1023,125 @@
            this.tsSockets[index].WriteToCSV(csvPath);
        }
        public void SavePositionDB(int index)
        {
            var socket = this.tsSockets[index];
            var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            string snr = socket.Barcode;
            List<string> sqls = new List<string>();
            foreach (var data in socket.Datasource)
            {
                sqls.Add($@"INSERT INTO serialData (sn,station,step,limitDown,limitUp,unit,value,status,finalStatus,consumeTime,totalConsumeTime,time) VALUES
('{snr}','','{data.Name}','{data.LimitDown}','{data.LimitUp}','{data.Unit}','{data.Value}','{data.Result}','{socket.Status}','{data.ConsumeTime}','{socket.ElapseTime}','{time}')");
            }
            sqliteHelper.ExecuteBatchSql(sqls);
        }
        private void HandleUIMessage(int eventCode, int index, string strData)
        {
            switch (eventCode)
            {
                case 10002://更新测试状态
                    string status = strData;
                    UpdatePositionStatus(index, status);
                    break;
                case 10003://发送测试数据
                    AddTestData(index, strData);
                    break;
                case 10004://发送测试过程信息
                    this.tsSockets[index].CurrentStep = strData;
                    break;
                case 10005://初始化测试数据,清空测试数据
                    this.tsSockets[index].IniTestData();
                    break;
                case 10006://发送产品条码
                    SetPositionBarcode(index, strData);
                    break;
                case 10007://开始测试计时
                    tsSockets[index].ElapseTime = "Start Timing";
                    BtnStopSeq.IsEnabled = false;
                    break;
                case 10008://停止测试计时
                    tsSockets[index].ElapseTime = "Stop Timing";
                    BtnStopSeq.IsEnabled = true;
                    break;
                case 10009:
                    //
                    break;
                case 10010:
                    //PropertyObj.SetValBoolean("Locals.MD5_Used", 0, true);
                    //PropertyObj.SetValVariant("FileGlobals.MD5_Value", 0, MD5_DATA);
                    //PropertyObj.SetValVariant("StationGlobals.MD5", 0, MD5_DATA);
                    break;
                case 10011:
                    // write model
                    break;
                case 10012:
                    // read model
                    break;
                case 10013:
                    // read continue
                    break;
                case 10014:
                    break;
                case 10015:
                    break;
                case 10016://显示3D拼接图片
                    break;
                case 10017://更新测试计时,针对部分计时有PLC完成的项目
                    this.tsSockets[index].ElapseTime = strData;
                    break;
                case (int)UIMessageCodes.UIMsg_EndExecution://执行结束
                    IsTesting = false;
                    //this.ReleaseSequenceFile();
                    break;
                case 10030://显示测试进度
                    int ProcessVal = Convert.ToInt32(strData);
                    this.tsSockets[index].SetTestProcess(ProcessVal);
                    break;
                case 10031://导出CSV
                    SavePositionCSV(index);
                    SavePositionDB(index);
                    break;
                case 10032://按下标暂停测试
                    this.tsSockets[index].ShowPausePanel();
                    break;
                case 10033:
                    ShowAlarm(strData);
                    break;
                default:
                    break;
            }
        }
        private void ShowAlarm(string info)
        {
            AlarmShowHelper.ShowAlarm(info);
            mSMQHelper.Send("Alarm", $"ATE测试 {info}");
        }
        /// <summary>
        /// TestStand用户交互事件
        /// </summary>
@@ -868,113 +1151,24 @@
        {
            try
            {
                int EventCase = Convert.ToInt32(e.uiMsg.Event);
                int Index = Convert.ToInt16(e.uiMsg.NumericData);//SocketIndex
                int eventCode = Convert.ToInt32(e.uiMsg.Event);
                int index = Convert.ToInt16(e.uiMsg.NumericData);//SocketIndex
                string strData = e.uiMsg.StringData;
                try
                {
                    log.Info($"Event: {EventCase}, NumericData: {Index}, StringData: {strData}");
                    log.Info($"Event: {eventCode}, NumericData: {index}, StringData: {strData}");
                }
                catch
                {
                }
                switch (EventCase)
                if (eventCode == 10001)
                {
                    case 10001://传递SocketContext
                        tsSockets[Index].SequenceFileContext = (SequenceContext)e.uiMsg.ActiveXData;
                        break;
                    case 10002://更新测试状态
                        string status = e.uiMsg.StringData;
                        UpdatePositionStatus(Index, status);
                        break;
                    case 10003://发送测试数据
                        AddTestData(Index, e.uiMsg.StringData);
                        break;
                    case 10004://发送测试过程信息
                        this.tsSockets[Index].CurrentStep = e.uiMsg.StringData;
                        break;
                    case 10005://初始化测试数据,清空测试数据
                        this.tsSockets[Index].IniTestData();
                        break;
                    case 10006://发送产品条码
                        SetPositionBarcode(Index, e.uiMsg.StringData);
                        break;
                    case 10007://开始测试计时
                        tsSockets[Index].ElapseTime = "Start Timing";
                        BtnStopSeq.IsEnabled = false;
                        break;
                    case 10008://停止测试计时
                        tsSockets[Index].ElapseTime = "Stop Timing";
                        BtnStopSeq.IsEnabled = true;
                        break;
                    case 10009:
                        //
                        break;
                    case 10010:
                        //PropertyObj.SetValBoolean("Locals.MD5_Used", 0, true);
                        //PropertyObj.SetValVariant("FileGlobals.MD5_Value", 0, MD5_DATA);
                        //PropertyObj.SetValVariant("StationGlobals.MD5", 0, MD5_DATA);
                        break;
                    case 10011:
                        // write model
                        break;
                    case 10012:
                        // read model
                        break;
                    case 10013:
                        // read continue
                        break;
                    case 10014:
                        break;
                    case 10015:
                        break;
                    case 10016://显示3D拼接图片
                        break;
                    case 10017://更新测试计时,针对部分计时有PLC完成的项目
                        this.tsSockets[Index].ElapseTime = e.uiMsg.StringData;
                        break;
                    case (int)UIMessageCodes.UIMsg_EndExecution://执行结束
                        IsTesting = false;
                        // this.ReleaseSequenceFile();
                        break;
                    case 10030://显示测试进度
                        int ProcessVal = Convert.ToInt32(e.uiMsg.StringData);
                        this.tsSockets[Index].SetTestProcess(ProcessVal);
                        break;
                    case 10031://导出CSV
                        SavePositionCSV(Index);
                        break;
                    case 10032://按下标暂停测试
                        this.tsSockets[Index].ShowPausePanel();
                        break;
                    default:
                        break;
                    tsSockets[index].SequenceFileContext = (SequenceContext)e.uiMsg.ActiveXData;
                    return;
                }
                HandleUIMessage(eventCode, index, strData);
            }
            catch (Exception ex)
            {
@@ -1027,13 +1221,6 @@
            try
            {
                StopSequence();
                // this.engine?.TerminateAll();
                // this.engine?.ReleaseSequenceFileEx(this.testSeq, 0);
                // this.engine?.ReleaseSequenceFileEx(this.modeSeq, 0);
                // this.engine?.UnloadAllModules();
                // this.engine?.ShutDown(true);
                //this.testSeq = null;
                //this.modeSeq = null;
                base.OnClose(sender, e);
            }
            catch (Exception ex)
@@ -1042,6 +1229,36 @@
            }
        }
        /// <summary>
        /// 释放所有的序列文件
        /// </summary>
        private bool ReleaseSequenceFile()
        {
            try
            {
                lock (this)
                {
                    if (this.testSeq == null)
                        return true;
                    if (this.engine.ReleaseSequenceFileEx(this.testSeq, 4))
                    {
                        this.testSeq = null;
                    }
                    if (this.engine.ReleaseSequenceFileEx(this.modeSeq, 4))
                    {
                        this.modeSeq = null;
                    }
                    this.engine.UnloadAllModules();
                    return true;
                }
            }
            catch (Exception ex)
            {
                log.Warn("ReleaseSequenceFile Error.", ex);
                return false;
            }
        }
        private void PluginControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {