From f08871fe7d148d667f2f11f80f64de71a0d9504c Mon Sep 17 00:00:00 2001
From: alielie <alielie@git.com>
Date: 星期一, 15 六月 2026 18:19:37 +0800
Subject: [PATCH] 优化标准老化界面

---
 Plugin.BurnIn/ManualDebug/StatusBtn.xaml            |   75 ++
 Plugin.BurnIn/Scanner.xaml.cs                       |    2 
 Plugin.BurnIn/DataTable.xaml.cs                     |   73 ++
 SimpleUtil/HMI.Simple.Util/HMI.Simple.Util.csproj   |    1 
 Plugin.BurnIn/ManualDebug/ManualCell.xaml           |   33 +
 Plugin.BurnIn/ManualDebug/ManualDebug.xaml          |  212 +++++++
 Plugin.BurnIn/SingleCell.xaml.cs                    |   14 
 HMI.Util/Alarm/AlarmUtil.cs                         |    4 
 Plugin.BurnIn/ManualDebug/ManualDebugWindow.xaml.cs |   26 
 Plugin.BurnIn/ManualDebug/StatusCell.xaml           |   39 +
 SimpleUtil/HMI.Simple.Util/DataSender.cs            |  103 +++
 Plugin.BurnIn/BurnInUI.xaml.cs                      |   12 
 Plugin.BurnIn/ManualDebug/ManualDebug.xaml.cs       |  691 ++++++++++++++++++++++++
 Plugin.BurnIn/ManualDebug/StatusBtn.xaml.cs         |   40 +
 Plugin.BurnIn/Plugin.BurnIn.csproj                  |   10 
 Plugin.BurnIn/ManualDebug/ManualCell.xaml.cs        |   47 +
 Plugin.BurnIn/ManualDebug/StatusCell.xaml.cs        |   71 ++
 Plugin.BurnIn/ManualDebug/ManualDebugStyle.xaml     |  130 ++++
 Plugin.BurnIn/ManualDebug/ManualDebugWindow.xaml    |    6 
 Plugin.TsExecution/SingleControl.xaml               |   10 
 Plugin.BurnIn/DataTable.xaml                        |    1 
 Plugin.BurnIn/TestResultView.xaml.cs                |    5 
 Plugin.TestResult/DataTable.xaml.cs                 |   21 
 Plugin.TsExecution/SingleControl.xaml.cs            |   27 
 24 files changed, 1,598 insertions(+), 55 deletions(-)

diff --git a/HMI.Util/Alarm/AlarmUtil.cs b/HMI.Util/Alarm/AlarmUtil.cs
index ea9988f..35ad725 100644
--- a/HMI.Util/Alarm/AlarmUtil.cs
+++ b/HMI.Util/Alarm/AlarmUtil.cs
@@ -20,7 +20,7 @@
 
         public event EventHandler<LoadMsg> LoadMessageAppend;
 
-        private static ILog log = LogManager.GetLogger("AlarmHelper");
+        internal static ILog log = LogManager.GetLogger("AlarmHelper");
 
         internal AlarmHelper()
         {
@@ -353,10 +353,12 @@
 
         public static void Init()
         {
+            AlarmHelper.log.Info("AlarmUtil initing...");
             Instance = new AlarmHelper();
             Instance.LoadMessageAppend += Instance_LoadMessageAppend; ;
             Instance.InitInstance();
             Instance.OnAlarm += Instance_OnAlarm;
+            AlarmHelper.log.Info("AlarmUtil inited finished.");
         }
 
         private static void Instance_LoadMessageAppend(object sender, LoadMsg e)
diff --git a/Plugin.BurnIn/BurnInUI.xaml.cs b/Plugin.BurnIn/BurnInUI.xaml.cs
index 7c372f1..86f5759 100644
--- a/Plugin.BurnIn/BurnInUI.xaml.cs
+++ b/Plugin.BurnIn/BurnInUI.xaml.cs
@@ -128,12 +128,6 @@
 
                 }
 
-                if (EventCase == 8)
-                {
-                    IsRunning = false;
-                    return;
-                }
-
                 if (EventCase != 10014) return;
 
                 if (MethodCode == 0)
@@ -155,6 +149,10 @@
                 {
                     /// 鏇存柊鐢熶骇鐘舵��
                     produceStatus = strData;
+                    if (string.Equals(strData, "stop", StringComparison.OrdinalIgnoreCase))
+                    {
+                        IsRunning = false;
+                    }
                     return;
                 }
             }
@@ -391,7 +389,7 @@
                 log.Info("鎬诲仠姝㈡寜閽寜涓�");
                 testResultView.StopTest();
                 /// 宸茬粡鍔犱簡WaitForExit,杩欓噷鍙互鏀逛负false
-                IsRunning = false;
+                //IsRunning = false;
             }
             catch (Exception ex)
             {
diff --git a/Plugin.BurnIn/DataTable.xaml b/Plugin.BurnIn/DataTable.xaml
index 4d57492..cf3aad3 100644
--- a/Plugin.BurnIn/DataTable.xaml
+++ b/Plugin.BurnIn/DataTable.xaml
@@ -16,6 +16,7 @@
              BorderBrush="Black"
              BorderThickness="1"
              x:Name="control"
+             PreviewMouseRightButtonDown="control_PreviewMouseRightButtonDown"
              Loaded="UserControl_Loaded"
              d:DesignHeight="450" d:DesignWidth="800">
     <UserControl.Resources>
diff --git a/Plugin.BurnIn/DataTable.xaml.cs b/Plugin.BurnIn/DataTable.xaml.cs
index f9ad8ac..7cf2998 100644
--- a/Plugin.BurnIn/DataTable.xaml.cs
+++ b/Plugin.BurnIn/DataTable.xaml.cs
@@ -1,4 +1,5 @@
 锘縰sing HMI.Base;
+using HMI.Core.Manager;
 using HMI.Core.Setting;
 using HMI.Core.Util;
 using HMI.LogUtil;
@@ -584,12 +585,12 @@
                 GetSingleCell(cellIndex).SetInfos(new Info
                 {
                     step = values[0],
-                    value = values[1],
-                    limitUp = values[2],
-                    limitDown = values[3],
-                    unit = values[4],
-                    result = values[5],
-                    updateTime = values[6]
+                    value = values[2],
+                    unit = values[3],
+                    limitUp = values[4],
+                    limitDown = values[5],
+                    result = values[6],
+                    updateTime = values[7]
                 });
             });
             //session.Send("1");
@@ -599,17 +600,10 @@
         {
             infoTable.UpdateNumber(infoTable.okCount + ok, infoTable.ngCount + ng);
 
-            if (ParamSetting.ProbeByModel)
-            {
-
-            }
-            else
-            {
-                IniFileHelper.WriteIniData($"Oven_{index}", "Pass", infoTable.okCount.ToString(),
+            IniFileHelper.WriteIniData($"Oven_{index}", "Pass", infoTable.okCount.ToString(),
                    this.CountIniPath);
-                IniFileHelper.WriteIniData($"Oven_{index}", "Fail", infoTable.ngCount.ToString(),
-                    this.CountIniPath);
-            }
+            IniFileHelper.WriteIniData($"Oven_{index}", "Fail", infoTable.ngCount.ToString(),
+                this.CountIniPath);
         }
 
         /// <summary>
@@ -883,5 +877,52 @@
             string key = $"StationHMI.UUTHMI[{this.index}].Abort";
             parent.executionWrapper?.SetStationGlobalValue(key, 0, true);
         }
+
+        private void MenuItem_Click(object sender, RoutedEventArgs e)
+        {
+            string manualDebugSeq = ParameterManager.GetCommonParameterByName("ManualDebugSeqPath")?.Value;
+            if (string.IsNullOrEmpty(manualDebugSeq))
+            {
+                MsgBoxHelper2.Error("璇峰厛璁剧疆鎵嬪姩璋冭瘯搴忓垪璺緞[ManualDebugSeqPath]!");
+                return;
+            }
+            string modelPath = parent.testModelFile;
+            var win = new ManualDebugWindow(manualDebugSeq, modelPath, true, cells, mainGrid.Columns)
+            {
+                CellCount = cells.Length,
+                Title = $"{this.title}鎵嬪姩璋冭瘯",
+                Owner = Window.GetWindow(this),
+                OvenIndex = this.index,
+                OvenName = this.title,
+                CellName = this.title,
+                CellIndex = -1
+            };
+            win.ShowDialog();
+        }
+        private void ContextMenu_Closed(object sender, RoutedEventArgs e)
+        {
+            this.ContextMenu = null;
+        }
+
+        private void control_PreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
+        {
+            if (!parent.inManualDebugMode)
+            {
+                return;
+            }
+            ContextMenu contextMenu = new ContextMenu();
+            contextMenu.Closed += ContextMenu_Closed;
+
+            var item = new MenuItem
+            {
+                IsCheckable = false,
+                Name = "manualDebugItem",
+                Header = this.lang("鎵嬪姩璋冭瘯"),
+            };
+            item.Click += MenuItem_Click;
+            contextMenu.Items.Add(item);
+
+            this.ContextMenu = contextMenu;
+        }
     }
 }
diff --git a/Plugin.BurnIn/ManualDebug/ManualCell.xaml b/Plugin.BurnIn/ManualDebug/ManualCell.xaml
new file mode 100644
index 0000000..4938bc4
--- /dev/null
+++ b/Plugin.BurnIn/ManualDebug/ManualCell.xaml
@@ -0,0 +1,33 @@
+锘�<UserControl x:Class="Plugin.BurnIn.ManualCell"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:Plugin.BurnIn"
+        xmlns:pu="https://opensource.panuon.com/wpf-ui"
+             mc:Ignorable="d" Padding="5" MaxHeight="80"
+             d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Style>
+        <Style TargetType="UserControl">
+            <Style.Triggers>
+                <DataTrigger Binding="{Binding Selected}" Value="True">
+                    <Setter Property="Background" Value="{DynamicResource SuccessColor}"/>
+                    <Setter Property="Foreground" Value="#FFF"/>
+                </DataTrigger>
+            </Style.Triggers>
+        </Style>
+    </UserControl.Style>
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition/>
+            <RowDefinition/>
+        </Grid.RowDefinitions>
+        <TextBlock FontSize="20" FontWeight="Bold" Text="{Binding Title}"/>
+        <pu:Switch Grid.Row="1" FontSize="18" BoxHeight="20" Cursor="Hand"
+        Content="鍏�"
+        CheckedBackground="Green"
+        Background="Red"
+        CheckedContent="寮�"
+        IsChecked="{Binding Selected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
+    </Grid>
+</UserControl>
diff --git a/Plugin.BurnIn/ManualDebug/ManualCell.xaml.cs b/Plugin.BurnIn/ManualDebug/ManualCell.xaml.cs
new file mode 100644
index 0000000..c7adec8
--- /dev/null
+++ b/Plugin.BurnIn/ManualDebug/ManualCell.xaml.cs
@@ -0,0 +1,47 @@
+锘縰sing CommunityToolkit.Mvvm.ComponentModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Plugin.BurnIn
+{
+    /// <summary>
+    /// ManualCell.xaml 鐨勪氦浜掗�昏緫
+    /// </summary>
+    [ObservableObject]
+    public partial class ManualCell : UserControl
+    {
+        [ObservableProperty]
+        private string title;
+
+        [ObservableProperty]
+        private bool selected;
+
+        [ObservableProperty]
+        private int index;
+
+        public event EventHandler SelectedChanged;
+
+        public ManualCell()
+        {
+            this.DataContext = this;
+            InitializeComponent();
+        }
+
+        partial void OnSelectedChanged(bool value)
+        {
+            SelectedChanged?.Invoke(this, new EventArgs());
+        }
+    }
+}
diff --git a/Plugin.BurnIn/ManualDebug/ManualDebug.xaml b/Plugin.BurnIn/ManualDebug/ManualDebug.xaml
new file mode 100644
index 0000000..077b360
--- /dev/null
+++ b/Plugin.BurnIn/ManualDebug/ManualDebug.xaml
@@ -0,0 +1,212 @@
+<UserControl x:Class="Plugin.BurnIn.ManualDebug"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:Plugin.BurnIn"
+        xmlns:dp="clr-namespace:HMI.UI.DpUtil;assembly=HMI.UI"
+        mc:Ignorable="d"
+        x:Name="self"
+        MinHeight="400" MinWidth="500">
+
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/Util.ManualDebug;component/ManualDebugStyle.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
+
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition/>
+            <RowDefinition Height="Auto"/>
+        </Grid.RowDefinitions>
+        <Grid Margin="10">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="Auto"/>
+                <ColumnDefinition/>
+            </Grid.ColumnDefinitions>
+
+            <Grid x:Name="CellSelectBorder">
+                <Grid.RowDefinitions>
+                    <RowDefinition/>
+                    <RowDefinition/>
+                </Grid.RowDefinitions>
+
+                <Border Background="{StaticResource TsPanelBrush}" Margin="0,0,10,5"
+BorderBrush="{StaticResource BorderBrush}" 
+BorderThickness="1" CornerRadius="4" Padding="15">
+                    <StackPanel>
+                        <TextBlock Text="绌翠綅閫夋嫨" FontSize="14" FontWeight="SemiBold" 
+           Foreground="{StaticResource PrimaryBrush}" Margin="0,0,0,15"/>
+
+                        <UniformGrid IsEnabled="False" x:Name="CellGrid" dp:UniformGridHelper.InnerBorder="1"
+ dp:UniformGridHelper.InnerBorderBrush="{StaticResource BorderBrush}">
+
+                        </UniformGrid>
+                    </StackPanel>
+                </Border>
+
+                <Border Grid.Row="1" Background="{StaticResource TsPanelBrush}" Margin="0,5,10,0"
+BorderBrush="{StaticResource BorderBrush}" 
+BorderThickness="1" CornerRadius="4" Padding="15">
+                    <StackPanel>
+                        <TextBlock Text="绌翠綅娴嬭瘯缁撴灉" FontSize="14" FontWeight="SemiBold" 
+           Foreground="{StaticResource PrimaryBrush}" Margin="0,0,0,15"/>
+
+                        <UniformGrid IsEnabled="False" x:Name="CellResultGrid" dp:UniformGridHelper.InnerBorder="1"
+ dp:UniformGridHelper.InnerBorderBrush="{StaticResource BorderBrush}">
+
+                        </UniformGrid>
+                    </StackPanel>
+                </Border>
+            </Grid>
+
+            <Grid Grid.Column="1">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="Auto"/>
+                    <RowDefinition Height="5"/>
+                    <RowDefinition Height="*"/>
+                    <RowDefinition Height="5"/>
+                    <RowDefinition Height="*"/>
+                </Grid.RowDefinitions>
+                <WindowsFormsHost x:Name="host" Visibility="Collapsed"></WindowsFormsHost>
+
+                <!-- 鎸夐挳鍜岀姸鎬佸尯鍩� -->
+                <Border Grid.Row="0" Background="{StaticResource TsPanelBrush}" 
+                BorderBrush="{StaticResource BorderBrush}" 
+                BorderThickness="1" CornerRadius="4" Padding="15">
+                    <StackPanel>
+                        <TextBlock Text="鎵嬪姩璋冭瘯鎺у埗" FontSize="14" FontWeight="SemiBold" 
+                           Foreground="{StaticResource PrimaryBrush}" Margin="0,0,0,15"/>
+
+                        <WrapPanel x:Name="btnPanel">
+
+                        </WrapPanel>
+                    </StackPanel>
+                </Border>
+
+                <!-- 鍒嗛殧鏉�1 -->
+                <GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" 
+                      Background="Transparent" Cursor="SizeNS"/>
+
+                <!-- TX/RX 鏁版嵁鍖哄煙 -->
+                <Border Grid.Row="2" Background="{StaticResource TsPanelBrush}" 
+                BorderBrush="{StaticResource BorderBrush}" 
+                BorderThickness="1" CornerRadius="4" Padding="10">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="Auto"/>
+                            <RowDefinition Height="*"/>
+                        </Grid.RowDefinitions>
+
+                        <StackPanel Orientation="Horizontal" Grid.Row="0" Margin="0,0,0,10">
+                            <TextBlock Text="娴嬭瘯鏁版嵁" FontSize="14" FontWeight="SemiBold" 
+                               Foreground="{StaticResource PrimaryBrush}" VerticalAlignment="Center"/>
+                            <Button Content="娓呯┖" Style="{StaticResource ActionButtonStyle}" 
+                            Margin="15,0,0,0" Click="OnClearClick"/>
+                        </StackPanel>
+
+                        <DataGrid x:Name="DataGridComm" Grid.Row="1"
+                          ItemsSource="{Binding TestData,ElementName=self}">
+                            <DataGrid.Columns>
+                                <DataGridTextColumn Header="娴嬭瘯椤�" Binding="{Binding Name}" Width="120" IsReadOnly="True"/>
+                                <DataGridTextColumn Header="鏀�" Binding="{Binding Receive}" Width="*" IsReadOnly="True"/>
+                                <DataGridTextColumn Header="鍙�" Binding="{Binding Send}" Width="*" IsReadOnly="True"/>
+                                <DataGridTextColumn Header="鍗曚綅" Binding="{Binding Unit}" Width="60" IsReadOnly="True"/>
+                                <DataGridTextColumn Header="涓婇檺" Binding="{Binding UpperLimit}" Width="80" IsReadOnly="True"/>
+                                <DataGridTextColumn Header="涓嬮檺" Binding="{Binding LowerLimit}" Width="80" IsReadOnly="True"/>
+                                <DataGridTextColumn Header="缁撴灉" Binding="{Binding Result}" Width="70" IsReadOnly="True"/>
+                                <DataGridTextColumn Header="鏃堕棿" Binding="{Binding Time}" Width="90" IsReadOnly="True"/>
+                            </DataGrid.Columns>
+                            <DataGrid.RowStyle>
+                                <Style TargetType="DataGridRow">
+                                    <Style.Triggers>
+                                        <DataTrigger Value="True">
+                                            <DataTrigger.Binding>
+                                                <MultiBinding Converter="{x:Static local:ResultFailedConverter.Instance}">
+                                                    <Binding Path="Result"/>
+                                                </MultiBinding>
+                                            </DataTrigger.Binding>
+                                            <Setter Property="Background" Value="#FFE0E0"/>
+                                            <Setter Property="Foreground" Value="#C53030"/>
+                                        </DataTrigger>
+                                    </Style.Triggers>
+                                </Style>
+                            </DataGrid.RowStyle>
+                        </DataGrid>
+                    </Grid>
+                </Border>
+
+                <!-- 鍒嗛殧鏉�2 -->
+                <GridSplitter Grid.Row="3" Height="5" HorizontalAlignment="Stretch" 
+                      Background="Transparent" Cursor="SizeNS"/>
+
+                <!-- 鏃ュ織鍖哄煙 -->
+                <Border Grid.Row="4" Background="{StaticResource TsPanelBrush}" 
+                BorderBrush="{StaticResource BorderBrush}" 
+                BorderThickness="1" CornerRadius="4" Padding="10">
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="Auto"/>
+                            <RowDefinition Height="*"/>
+                        </Grid.RowDefinitions>
+
+                        <StackPanel Orientation="Horizontal" Grid.Row="0" Margin="0,0,0,8">
+                            <TextBlock Text="鏃ュ織" FontSize="14" FontWeight="SemiBold" 
+                               Foreground="{StaticResource PrimaryBrush}" VerticalAlignment="Center"/>
+                            <Button Content="娓呯┖鏃ュ織" Style="{StaticResource ActionButtonStyle}" 
+                            Margin="15,0,0,0" Click="OnClearLogClick"/>
+                        </StackPanel>
+
+                        <RichTextBox x:Name="LogRichTextBox" Grid.Row="1"
+                             IsReadOnly="True"
+                             VerticalScrollBarVisibility="Auto"
+                             FontFamily="Consolas"
+                             FontSize="11"
+                             BorderThickness="1"
+                             BorderBrush="Black" 
+                             Padding="4"/>
+                    </Grid>
+                </Border>
+            </Grid>
+            <Border Background="#AAFFFFFF" Grid.ColumnSpan="2" x:Name="mask">
+                <TextBlock Text="鍒濆鍖栦腑..." 
+                       FontSize="16" FontWeight="Bold" Foreground="{StaticResource PrimaryBrush}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
+            </Border>
+        </Grid>
+
+        <StatusBar FontSize="14" Grid.Row="1">
+            <StatusBar.ItemsPanel>
+                <ItemsPanelTemplate>
+                    <DockPanel LastChildFill="False"/>
+                </ItemsPanelTemplate>
+            </StatusBar.ItemsPanel>
+
+            <StatusBarItem DockPanel.Dock="Left">
+                <StackPanel Orientation="Horizontal" dp:StackPanelHelper.ChildSpace="8">
+                    <StackPanel Orientation="Horizontal">
+                        <Ellipse Width="10" Height="10">
+                            <Ellipse.Style>
+                                <Style TargetType="Ellipse">
+                                    <Setter Property="Fill" Value="LightGray"/>
+                                    <Style.Triggers>
+                                        <DataTrigger Binding="{Binding TcpServerStatus,ElementName=self}" Value="ERROR">
+                                            <Setter Property="Fill" Value="Red"/>
+                                        </DataTrigger>
+                                        <DataTrigger Binding="{Binding TcpServerStatus,ElementName=self}" Value="RUNNING">
+                                            <Setter Property="Fill" Value="Green"/>
+                                        </DataTrigger>
+                                    </Style.Triggers>
+                                </Style>
+                            </Ellipse.Style>
+                        </Ellipse>
+                        <TextBlock Text="{Binding TcpServerInfo,ElementName=self}"/>
+                        <Button Padding="0" Margin="0" BorderThickness="0" Command="{Binding StartTcpServerCommand,ElementName=self}">馃攧</Button>
+                    </StackPanel>
+                </StackPanel>
+            </StatusBarItem>
+        </StatusBar>
+    </Grid>
+</UserControl>
diff --git a/Plugin.BurnIn/ManualDebug/ManualDebug.xaml.cs b/Plugin.BurnIn/ManualDebug/ManualDebug.xaml.cs
new file mode 100644
index 0000000..93c2289
--- /dev/null
+++ b/Plugin.BurnIn/ManualDebug/ManualDebug.xaml.cs
@@ -0,0 +1,691 @@
+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.ObjectModel;
+using System.ComponentModel;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Media;
+
+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;
+                });
+            });
+        }
+
+        /// <summary>
+        /// 启动Tcp服务器
+        /// </summary>
+        [RelayCommand]
+        private void StartTcpServer()
+        {
+            var serverConfig = new ServerConfig()
+            {
+                MaxRequestLength = 1024 * 1024,
+                Port = 7777
+            };
+            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"));
+                }
+                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"));
+                }
+            }
+            catch (Exception ex)
+            {
+                ChangeTcpServerStatus("ERROR", $"{ex.Message}");
+                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();
+                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));
+        }
+    }
+}
diff --git a/Plugin.BurnIn/ManualDebug/ManualDebugStyle.xaml b/Plugin.BurnIn/ManualDebug/ManualDebugStyle.xaml
new file mode 100644
index 0000000..cf459fb
--- /dev/null
+++ b/Plugin.BurnIn/ManualDebug/ManualDebugStyle.xaml
@@ -0,0 +1,130 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+
+    <!-- 棰滆壊瀹氫箟 -->
+    <SolidColorBrush x:Key="TsBgBrush" Color="#F0F2F5"/>
+    <SolidColorBrush x:Key="TsPanelBrush" Color="#FFFFFF"/>
+    <SolidColorBrush x:Key="BorderBrush" Color="#A0AEC0"/>
+    <SolidColorBrush x:Key="PrimaryBrush" Color="#2E5C8A"/>
+
+    <!-- 鐘舵�侀鑹茬敾鍒� -->
+    <SolidColorBrush x:Key="StatusOKBrush" Color="#2D8659"/>
+    <SolidColorBrush x:Key="StatusNGBrush" Color="#C53030"/>
+    <SolidColorBrush x:Key="StatusTestingBrush" Color="#3182CE"/>
+    <SolidColorBrush x:Key="StatusDefaultBrush" Color="#E0E0E0"/>
+    <SolidColorBrush x:Key="BorderDarkBrush" Color="#718096"/>
+
+    <!-- ActionButtonStyle 鎸夐挳鏍峰紡 -->
+    <Style x:Key="ActionButtonStyle" TargetType="Button">
+        <Setter Property="Height" Value="22"/>
+        <Setter Property="Padding" Value="8,0"/>
+        <Setter Property="Background" Value="White"/>
+        <Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
+        <Setter Property="BorderThickness" Value="1"/>
+        <Setter Property="FontSize" Value="11"/>
+        <Setter Property="Cursor" Value="Hand"/>
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="Button">
+                    <Border Background="{TemplateBinding Background}"
+                            BorderBrush="{TemplateBinding BorderBrush}"
+                            BorderThickness="{TemplateBinding BorderThickness}"
+                            CornerRadius="2"
+                            Padding="{TemplateBinding Padding}">
+                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                    </Border>
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="IsMouseOver" Value="True">
+                            <Setter Property="Background" Value="#F0F0F0"/>
+                        </Trigger>
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+
+    <!-- ManualDebug 绐楀彛涓撶敤鎸夐挳鏍峰紡 -->
+    <Style x:Key="DebugButtonStyle" TargetType="Button">
+        <Setter Property="Width" Value="100"/>
+        <Setter Property="Height" Value="32"/>
+        <Setter Property="Background" Value="White"/>
+        <Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
+        <Setter Property="BorderThickness" Value="1"/>
+        <Setter Property="FontSize" Value="11"/>
+        <Setter Property="Cursor" Value="Hand"/>
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="Button">
+                    <Border Background="{TemplateBinding Background}"
+                            BorderBrush="{TemplateBinding BorderBrush}"
+                            BorderThickness="{TemplateBinding BorderThickness}"
+                            CornerRadius="4"
+                            Padding="{TemplateBinding Padding}">
+                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                    </Border>
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="IsMouseOver" Value="True">
+                            <Setter Property="Background" Value="#E8E8E8"/>
+                        </Trigger>
+                        <Trigger Property="IsPressed" Value="True">
+                            <Setter Property="Background" Value="#D0D0D0"/>
+                        </Trigger>
+                        <Trigger Property="IsEnabled" Value="False">
+                            <Setter Property="Background" Value="LightGray"/>
+                        </Trigger>
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+
+    <!-- DataGrid鏍峰紡 -->
+    <Style TargetType="DataGrid">
+        <Setter Property="AutoGenerateColumns" Value="False"/>
+        <Setter Property="CanUserAddRows" Value="False"/>
+        <Setter Property="CanUserDeleteRows" Value="False"/>
+        <Setter Property="HeadersVisibility" Value="Column"/>
+        <Setter Property="GridLinesVisibility" Value="All"/>
+        <Setter Property="HorizontalGridLinesBrush" Value="{StaticResource BorderBrush}"/>
+        <Setter Property="VerticalGridLinesBrush" Value="{StaticResource BorderBrush}"/>
+        <Setter Property="BorderBrush" Value="{StaticResource BorderDarkBrush}"/>
+        <Setter Property="BorderThickness" Value="1"/>
+        <Setter Property="Background" Value="White"/>
+        <Setter Property="RowBackground" Value="White"/>
+        <Setter Property="AlternatingRowBackground" Value="#F5F5F5"/>
+        <Setter Property="FontSize" Value="11"/>
+    </Style>
+
+    <Style TargetType="DataGridColumnHeader">
+        <Setter Property="Background" Value="#F5F5F5"/>
+        <Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
+        <Setter Property="BorderThickness" Value="0,0,1,1"/>
+        <Setter Property="Padding" Value="4"/>
+        <Setter Property="Height" Value="26"/>
+        <Setter Property="FontWeight" Value="Normal"/>
+    </Style>
+
+    <Style TargetType="DataGridCell">
+        <Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
+        <Setter Property="BorderThickness" Value="0"/>
+        <Setter Property="Padding" Value="2,4"/>
+        <Style.Triggers>
+            <Trigger Property="IsSelected" Value="True">
+                <Setter Property="Background" Value="#BBDEFB"/>
+                <Setter Property="Foreground" Value="Black"/>
+            </Trigger>
+        </Style.Triggers>
+    </Style>
+
+    <Style TargetType="DataGridRow">
+        <Style.Triggers>
+            <Trigger Property="IsSelected" Value="True">
+                <Setter Property="Background" Value="#BBDEFB"/>
+            </Trigger>
+            <Trigger Property="IsMouseOver" Value="True">
+                <Setter Property="Background" Value="#E3F2FD"/>
+            </Trigger>
+        </Style.Triggers>
+    </Style>
+
+</ResourceDictionary>
diff --git a/Plugin.BurnIn/ManualDebugWindow.xaml b/Plugin.BurnIn/ManualDebug/ManualDebugWindow.xaml
similarity index 79%
rename from Plugin.BurnIn/ManualDebugWindow.xaml
rename to Plugin.BurnIn/ManualDebug/ManualDebugWindow.xaml
index ba5a019..bfa4090 100644
--- a/Plugin.BurnIn/ManualDebugWindow.xaml
+++ b/Plugin.BurnIn/ManualDebug/ManualDebugWindow.xaml
@@ -4,16 +4,18 @@
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         mc:Ignorable="d"
-        xmlns:sb="clr-namespace:Util.SB;assembly=Util.ManualDebug"
         Title="ManualDebugWindow" 
         xmlns:pu="https://opensource.panuon.com/wpf-ui"
+        xmlns:local="clr-namespace:Plugin.BurnIn"
         Style="{StaticResource ModalWindow}"
         Closing="Window_Closing"
+        WindowState="Maximized"
         WindowStartupLocation="CenterScreen"
         pu:WindowXModalDialog.Buttons="{x:Null}"
         Height="1000" Width="900">
     <Grid x:Name="sb">
-        <sb:ManualDebug OvenName="{Binding OvenName,Mode=OneWay}" 
+        <local:ManualDebug OvenName="{Binding OvenName,Mode=OneWay}" 
+                           CellCount="{Binding CellCount,Mode=OneWay}" 
     CellName="{Binding CellName,Mode=OneWay}" 
     OvenIndex="{Binding OvenIndex,Mode=OneWay}" 
     CellIndex="{Binding CellIndex,Mode=OneWay}"/>
diff --git a/Plugin.BurnIn/ManualDebugWindow.xaml.cs b/Plugin.BurnIn/ManualDebug/ManualDebugWindow.xaml.cs
similarity index 77%
rename from Plugin.BurnIn/ManualDebugWindow.xaml.cs
rename to Plugin.BurnIn/ManualDebug/ManualDebugWindow.xaml.cs
index 3118483..1723f14 100644
--- a/Plugin.BurnIn/ManualDebugWindow.xaml.cs
+++ b/Plugin.BurnIn/ManualDebug/ManualDebugWindow.xaml.cs
@@ -3,7 +3,6 @@
 using System.ComponentModel;
 using System.IO;
 using System.Windows;
-using Util.SB;
 
 namespace Plugin.BurnIn
 {
@@ -15,15 +14,26 @@
 
         private ManualDebug debug;
 
-        public ManualDebugWindow(string seqPath, string modelPath)
+        public ManualDebugWindow(string seqPath, string modelPath, bool isMuilt) : this(seqPath, modelPath, isMuilt, null, 1)
+        {
+        }
+
+        public ManualDebugWindow(string seqPath, string modelPath, bool isMuilt, SingleCell[] cells, int col)
         {
             DataContext = this;
             InitializeComponent();
             debug = (ManualDebug)sb.Children[0];
             ReadBtns();
+            if (!isMuilt)
+            {
+                debug.HideCells(true);
+            }
             //List<BtnConfig> settings = new List<BtnConfig> { new BtnConfig { Title = "涓婄數婵�娲�", Name = "Active" } };
             debug.seqPath = seqPath;
             debug.modelPath = modelPath;
+            debug.CellGrid.Columns = col;
+            debug.CellResultGrid.Columns = col;
+            debug.RefreshGrid(cells);
         }
 
         private string ovenName;
@@ -56,7 +66,7 @@
             }
         }
 
-        private int cellIndex;
+        private int cellIndex = -1;
         public int CellIndex
         {
             get => cellIndex;
@@ -66,6 +76,16 @@
             }
         }
 
+        private int cellCount = 0;
+        public int CellCount
+        {
+            get => cellCount;
+            set
+            {
+                Set(ref cellCount, value);
+            }
+        }
+
         private void ReadBtns()
         {
             string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Settings.ini");
diff --git a/Plugin.BurnIn/ManualDebug/StatusBtn.xaml b/Plugin.BurnIn/ManualDebug/StatusBtn.xaml
new file mode 100644
index 0000000..2eba3e6
--- /dev/null
+++ b/Plugin.BurnIn/ManualDebug/StatusBtn.xaml
@@ -0,0 +1,75 @@
+锘�<UserControl x:Class="Plugin.BurnIn.StatusBtn"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:Plugin.BurnIn"
+             mc:Ignorable="d" 
+             d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/Plugin.BurnIn;component/ManualDebug/ManualDebugStyle.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+
+            <Style x:Key="StatusTextStyle" TargetType="TextBlock">
+                <Setter Property="HorizontalAlignment" Value="Center"/>
+                <Setter Property="VerticalAlignment" Value="Center"/>
+                <Setter Property="FontWeight" Value="SemiBold"/>
+                <Setter Property="FontSize" Value="12"/>
+                <Setter Property="Text" Value="-"/>
+                <Style.Triggers>
+                    <DataTrigger Binding="{Binding Status}" Value="{x:Static local:DebugStatus.NG}">
+                        <Setter Property="Text" Value="NG"/>
+                        <Setter Property="Foreground" Value="#FFF"/>
+                    </DataTrigger>
+                    <DataTrigger Binding="{Binding Status}" Value="{x:Static local:DebugStatus.OK}">
+                        <Setter Property="Text" Value="OK"/>
+                        <Setter Property="Foreground" Value="#FFF"/>
+                    </DataTrigger>
+                    <DataTrigger Binding="{Binding Status}" Value="{x:Static local:DebugStatus.Testing}">
+                        <Setter Property="Text" Value="TESTING"/>
+                        <Setter Property="Foreground" Value="#FFF"/>
+                    </DataTrigger>
+                </Style.Triggers>
+            </Style>
+
+            <!-- 鐘舵�佽竟妗嗘牱寮� -->
+            <Style x:Key="StatusBorderStyle" TargetType="Border">
+                <Setter Property="Background" Value="{StaticResource StatusDefaultBrush}"/>
+                <Setter Property="CornerRadius" Value="2"/>
+                <Setter Property="HorizontalAlignment" Value="Center"/>
+                <Setter Property="Width" Value="100"/>
+                <Setter Property="Height" Value="24"/>
+                <Setter Property="Margin" Value="0,5,0,0"/>
+
+                <Style.Triggers>
+                    <DataTrigger Binding="{Binding Status}" Value="{x:Static local:DebugStatus.NG}">
+                        <Setter Property="Background" Value="{StaticResource StatusNGBrush}"/>
+                    </DataTrigger>
+                    <DataTrigger Binding="{Binding Status}" Value="{x:Static local:DebugStatus.OK}">
+                        <Setter Property="Background" Value="{StaticResource StatusOKBrush}"/>
+                    </DataTrigger>
+                    <DataTrigger Binding="{Binding Status}" Value="{x:Static local:DebugStatus.Testing}">
+                        <Setter Property="Background" Value="{StaticResource StatusTestingBrush}"/>
+                    </DataTrigger>
+                </Style.Triggers>
+            </Style>
+
+            <Style x:Key="btnStyle" TargetType="Button" BasedOn="{StaticResource DebugButtonStyle}">
+                <Style.Triggers>
+                    <DataTrigger Binding="{Binding Status}" Value="{x:Static local:DebugStatus.Testing}">
+                        <Setter Property="IsEnabled" Value="False"/>
+                    </DataTrigger>
+                </Style.Triggers>
+            </Style>
+        </ResourceDictionary>
+
+    </UserControl.Resources>
+    <StackPanel>
+        <Button x:Name="btn" Content="{Binding Title}" Style="{StaticResource btnStyle}" Click="Button_Click"/>
+        <Border Style="{StaticResource StatusBorderStyle}">
+            <TextBlock Style="{StaticResource StatusTextStyle}"/>
+        </Border>
+    </StackPanel>
+</UserControl>
diff --git a/Plugin.BurnIn/ManualDebug/StatusBtn.xaml.cs b/Plugin.BurnIn/ManualDebug/StatusBtn.xaml.cs
new file mode 100644
index 0000000..7a0551a
--- /dev/null
+++ b/Plugin.BurnIn/ManualDebug/StatusBtn.xaml.cs
@@ -0,0 +1,40 @@
+锘縰sing CommunityToolkit.Mvvm.ComponentModel;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace Plugin.BurnIn
+{
+    // 鐘舵�佹灇涓�
+    public enum DebugStatus
+    {
+        Idle = 0,    // 绌洪棽
+        Testing = 1, // 娴嬭瘯涓�
+        OK = 2,      // 閫氳繃
+        NG = 3       // 澶辫触
+    }
+    /// <summary>
+    /// StatusBtn.xaml 鐨勪氦浜掗�昏緫
+    /// </summary>
+    [ObservableObject]
+    public partial class StatusBtn : UserControl
+    {
+        public event RoutedEventHandler BtnClick;
+
+        public StatusBtn()
+        {
+            DataContext = this;
+            InitializeComponent();
+        }
+
+        [ObservableProperty]
+        private string title = string.Empty;
+
+        [ObservableProperty]
+        private DebugStatus status = DebugStatus.Idle;
+
+        private void Button_Click(object sender, RoutedEventArgs e)
+        {
+            BtnClick?.Invoke(this, e);
+        }
+    }
+}
diff --git a/Plugin.BurnIn/ManualDebug/StatusCell.xaml b/Plugin.BurnIn/ManualDebug/StatusCell.xaml
new file mode 100644
index 0000000..3ff8bd8
--- /dev/null
+++ b/Plugin.BurnIn/ManualDebug/StatusCell.xaml
@@ -0,0 +1,39 @@
+锘�<UserControl x:Class="Plugin.BurnIn.StatusCell"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:Plugin.BurnIn"
+        xmlns:pu="https://opensource.panuon.com/wpf-ui"
+             mc:Ignorable="d" Padding="5" MaxHeight="80"
+             d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Style>
+        <Style TargetType="UserControl">
+            <Style.Triggers>
+                <DataTrigger Binding="{Binding Status}" Value="{x:Static local:CellStatus.Closed}">
+                    <Setter Property="Background" Value="Gray"/>
+                </DataTrigger>
+                <DataTrigger Binding="{Binding Status}" Value="{x:Static local:CellStatus.OK}">
+                    <Setter Property="Background" Value="#2D8659"/>
+                    <Setter Property="Foreground" Value="#FFF"/>
+                </DataTrigger>
+                <DataTrigger Binding="{Binding Status}" Value="{x:Static local:CellStatus.NG}">
+                    <Setter Property="Background" Value="#C53030"/>
+                    <Setter Property="Foreground" Value="#FFF"/>
+                </DataTrigger>
+                <DataTrigger Binding="{Binding Status}" Value="{x:Static local:CellStatus.Testing}">
+                    <Setter Property="Background" Value="#3182CE"/>
+                    <Setter Property="Foreground" Value="#FFF"/>
+                </DataTrigger>
+            </Style.Triggers>
+        </Style>
+    </UserControl.Style>
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition/>
+            <RowDefinition/>
+        </Grid.RowDefinitions>
+        <TextBlock FontSize="20" FontWeight="Bold" Text="{Binding Title}"/>
+        <TextBlock Grid.Row="1" FontSize="18" Text="{Binding Status}"/>
+    </Grid>
+</UserControl>
diff --git a/Plugin.BurnIn/ManualDebug/StatusCell.xaml.cs b/Plugin.BurnIn/ManualDebug/StatusCell.xaml.cs
new file mode 100644
index 0000000..75660fd
--- /dev/null
+++ b/Plugin.BurnIn/ManualDebug/StatusCell.xaml.cs
@@ -0,0 +1,71 @@
+锘縰sing CommunityToolkit.Mvvm.ComponentModel;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+
+namespace Plugin.BurnIn
+{
+    public enum CellStatus
+    {
+        Testing = 0,
+        OK = 1,
+        NG = 2,
+        Closed = 99,
+        Open = 100,
+        Waiting = 101
+    }
+
+    public class CellStatusConverter : IValueConverter
+    {
+        public static CellStatusConverter Instance = new CellStatusConverter();
+
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (value is bool b)
+            {
+                return b ? CellStatus.Open : CellStatus.Closed;
+            }
+            return CellStatus.Closed;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return null;
+        }
+    }
+
+    /// <summary>
+    /// ManualCell.xaml 鐨勪氦浜掗�昏緫
+    /// </summary>
+    [ObservableObject]
+    public partial class StatusCell : UserControl
+    {
+        [ObservableProperty]
+        private string title;
+
+        public static readonly DependencyProperty StatusProperty = DependencyProperty.Register(
+                            "Status",
+                            typeof(CellStatus),
+                            typeof(StatusCell),
+                            new PropertyMetadata(CellStatus.Closed));
+
+        public CellStatus Status
+        {
+            get => (CellStatus)GetValue(StatusProperty);
+            set
+            {
+                SetValue(StatusProperty, value);
+            }
+        }
+
+        [ObservableProperty]
+        private int index;
+
+        public StatusCell()
+        {
+            this.DataContext = this;
+            InitializeComponent();
+        }
+    }
+}
diff --git a/Plugin.BurnIn/Plugin.BurnIn.csproj b/Plugin.BurnIn/Plugin.BurnIn.csproj
index 3be23dc..8a28ded 100644
--- a/Plugin.BurnIn/Plugin.BurnIn.csproj
+++ b/Plugin.BurnIn/Plugin.BurnIn.csproj
@@ -8,6 +8,9 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <UseWPF>true</UseWPF>
     <Platforms>AnyCPU;x64</Platforms>
+    <AssemblyVersion>1.0.0.2</AssemblyVersion>
+    <FileVersion>1.0.0.2</FileVersion>
+    <IncludeSymbols>False</IncludeSymbols>
   </PropertyGroup>
 
   <ItemGroup>
@@ -30,7 +33,6 @@
     <ProjectReference Include="..\PLCHelper\PLCHelper.csproj" />
     <ProjectReference Include="..\Plugin.TsSupport\Plugin.TsSupport.csproj" />
     <ProjectReference Include="..\SimpleUtil\HMI.LogUtil\HMI.LogUtil.csproj" />
-    <ProjectReference Include="..\Util.ManualDebug\Util.ManualDebug.csproj" />
   </ItemGroup>
 
   <ItemGroup>
@@ -62,6 +64,12 @@
   </ItemGroup>
 
   <ItemGroup>
+    <Compile Update="ManualDebug\StatusCell.xaml.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Update="ManualDebug\StatusBtn.xaml.cs">
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Update="TestResultView.xaml.cs">
       <SubType>Code</SubType>
     </Compile>
diff --git a/Plugin.BurnIn/Scanner.xaml.cs b/Plugin.BurnIn/Scanner.xaml.cs
index ae98c61..1a05db9 100644
--- a/Plugin.BurnIn/Scanner.xaml.cs
+++ b/Plugin.BurnIn/Scanner.xaml.cs
@@ -390,7 +390,7 @@
             try
             {
                 targetCellInfo = null;
-                serialPort.Dispose();
+                serialPort?.Dispose();
                 serialPort = null;
             }
             catch (Exception ex)
diff --git a/Plugin.BurnIn/SingleCell.xaml.cs b/Plugin.BurnIn/SingleCell.xaml.cs
index 8fafd4f..165bfde 100644
--- a/Plugin.BurnIn/SingleCell.xaml.cs
+++ b/Plugin.BurnIn/SingleCell.xaml.cs
@@ -521,16 +521,21 @@
             //waterChart?.AddData("姘寸娓╁害", temp);
             //waterChart?.AddData("鍥炴按娓╁害", backTemp);
             //waterChart?.AddData("娴侀噺", pressure);
+            var time = DateTime.Now;
+            charts[0].AddData("姘寸娓╁害", time, temp);
+            charts[0].AddData("鍥炴按娓╁害", time, backTemp);
+            charts[0].AddData("娴侀噺", time, pressure);
         }
 
         public void AddElectricData(double data)
         {
+            charts[1].AddData("鐢垫祦", DateTime.Now, data);
             //electricChart.AddData("", data);
         }
 
         public void AddVData(double data)
         {
-            //vChart.AddData("", data);
+            charts[2].AddData("鐢靛帇", DateTime.Now, data);
         }
 
         public void ClearChart()
@@ -1059,15 +1064,16 @@
                 return;
             }
             string modelPath = table.parent.testModelFile;
-            int dutNo = table.index * table.cellCount + this.index;
-            var win = new ManualDebugWindow(manualDebugSeq, modelPath)
+            var win = new ManualDebugWindow(manualDebugSeq, modelPath, false)
             {
                 Title = $"{this.title}鎵嬪姩璋冭瘯",
+
                 Owner = Window.GetWindow(this),
                 OvenIndex = this.table.index,
                 OvenName = this.table.title,
+                CellCount = this.table.cells.Length,
 
-                CellIndex = dutNo,
+                CellIndex = this.index,
                 CellName = this.title
             };
             win.ShowDialog();
diff --git a/Plugin.BurnIn/TestResultView.xaml.cs b/Plugin.BurnIn/TestResultView.xaml.cs
index f58724d..9d26b74 100644
--- a/Plugin.BurnIn/TestResultView.xaml.cs
+++ b/Plugin.BurnIn/TestResultView.xaml.cs
@@ -245,7 +245,7 @@
         {
             foreach (var oven in tables)
             {
-                executionWrapper?.SetStationGlobalValue<string>($"StationHMI.UUTHMI[{oven.index}].Name", 1, oven.Name);
+                executionWrapper?.SetStationGlobalValue<string>($"StationHMI.UUTHMI[{oven.index}].Name", 1, oven.title);
             }
             executionWrapper?.CommitToDisk(false);
         }
@@ -271,7 +271,7 @@
         {
             try
             {
-                executionWrapper?.SetStationGlobalValue<bool>("StationState.StopTest", 0, true, true);
+                executionWrapper?.SetStationGlobalValue<bool>("StationHMI.AllStop", 0, true, true);
 
                 try
                 {
@@ -453,6 +453,7 @@
                     tables[ovenIndex].ClearChartData();
                     return;
                 }
+                
                 if (MethodCode == 11)
                 {
                     /// 娓呴櫎绌翠綅鍙傛暟
diff --git a/Plugin.TestResult/DataTable.xaml.cs b/Plugin.TestResult/DataTable.xaml.cs
index 29d402c..bcff8ec 100644
--- a/Plugin.TestResult/DataTable.xaml.cs
+++ b/Plugin.TestResult/DataTable.xaml.cs
@@ -607,17 +607,18 @@
         {
             infoTable.UpdateNumber(infoTable.okCount + ok, infoTable.ngCount + ng);
 
-            if (ParamSetting.ProbeByModel)
-            {
+            //if (ParamSetting.ProbeByModel)
+            //{
 
-            }
-            else
-            {
-                IniFileHelper.WriteIniData($"Oven_{index}", "Pass", infoTable.okCount.ToString(),
-                   this.CountIniPath);
-                IniFileHelper.WriteIniData($"Oven_{index}", "Fail", infoTable.ngCount.ToString(),
-                    this.CountIniPath);
-            }
+            //}
+            //else
+            //{
+
+            //}
+            IniFileHelper.WriteIniData($"Oven_{index}", "Pass", infoTable.okCount.ToString(),
+                  this.CountIniPath);
+            IniFileHelper.WriteIniData($"Oven_{index}", "Fail", infoTable.ngCount.ToString(),
+                this.CountIniPath);
         }
 
         /// <summary>
diff --git a/Plugin.TsExecution/SingleControl.xaml b/Plugin.TsExecution/SingleControl.xaml
index 16720c0..b40655c 100644
--- a/Plugin.TsExecution/SingleControl.xaml
+++ b/Plugin.TsExecution/SingleControl.xaml
@@ -455,7 +455,13 @@
 VerticalContentAlignment="Center" Content="{DynamicResource Ts.ProbeCount}"/>
                         <Label Padding="0" FontSize="12"  Margin="0,0,15,0"
 VerticalAlignment="Center"
-VerticalContentAlignment="Center" Content="{Binding ProbeCount}"/>
+VerticalContentAlignment="Center">
+                            <TextBlock>
+                                <Run Text="{Binding ProbeCount}"/>
+                                <Run Text="/"/>
+                                <Run Text="{Binding ProbeWarn,Mode=OneWay}"/>
+                            </TextBlock>
+                        </Label>
 
                         <StackPanel x:Name="probeWarnPanel" Orientation="Horizontal" Visibility="Collapsed">
                             <Label x:Name="alarmLabel" Padding="0" FontSize="12" 
@@ -463,7 +469,7 @@
 VerticalContentAlignment="Center" Content="{DynamicResource Ts.ProbeAlarmCount}"/>
                             <Label x:Name="alarmValue" Padding="0" FontSize="12" 
 VerticalAlignment="Center"
-VerticalContentAlignment="Center" Content="{Binding ProbeWarn}"/>
+VerticalContentAlignment="Center" Content="{Binding ProbeWarn,Mode=OneWay}"/>
                         </StackPanel>
 
                         <Button FontSize="12" Style="{StaticResource LinkButton}" 
diff --git a/Plugin.TsExecution/SingleControl.xaml.cs b/Plugin.TsExecution/SingleControl.xaml.cs
index 373fcd4..35ceb3b 100644
--- a/Plugin.TsExecution/SingleControl.xaml.cs
+++ b/Plugin.TsExecution/SingleControl.xaml.cs
@@ -5,6 +5,7 @@
 using HMI.Util;
 using NationalInstruments.TestStand.Interop.API;
 using NPOI.HSSF.UserModel;
+using NPOI.SS.Formula.Functions;
 using NPOI.SS.UserModel;
 using Plugin.TsExecution.Entity;
 using System;
@@ -180,6 +181,16 @@
             set
             {
                 Set(ref _probeCount, value);
+                try
+                {
+                    if (ProbeWarn <= 0) probeCountAlarm.Visibility = Visibility.Collapsed;
+                    else if (value >= ProbeWarn) probeCountAlarm.Visibility = Visibility.Visible;
+                    else probeCountAlarm.Visibility = Visibility.Collapsed;
+                }
+                catch
+                {
+
+                }
             }
         }
 
@@ -222,7 +233,15 @@
             }
         }
 
-        public int ProbeWarn { get; private set; }
+        private int _probeWarn;
+        public int ProbeWarn
+        {
+            get => _probeWarn;
+            private set
+            {
+                Set(ref _probeWarn, value);
+            }
+        }
 
         private bool isAutoMode;
         public bool IsAutoMode
@@ -246,9 +265,9 @@
                 Interval = 100
             };
             refreshTimer.Elapsed += RefreshTimer_Elapsed;
-            RefreshProbeCount(null);
             ReadCounter();
             InitializeComponent();
+            RefreshProbeCount(null);
             try
             {
                 var value = ParameterManager.GetCommonParameterByName("AutoTestMode");
@@ -653,10 +672,6 @@
             /// 鍐欏埌閰嶇疆鏂囦欢
             IniFileHelper.WriteIniData("Socket" + this.index.ToString(), "ProbeCount", count.ToString(), this.CountIniPath);
             ProbeCount = count;
-
-            //if (ProbeWarn <= 0) probeCountAlarm.Visibility = Visibility.Collapsed;
-            //else if (count >= ProbeWarn) probeCountAlarm.Visibility = Visibility.Visible;
-            //else probeCountAlarm.Visibility = Visibility.Collapsed;
         }
 
         public void RefreshProduct(ProductData product)
diff --git a/SimpleUtil/HMI.Simple.Util/DataSender.cs b/SimpleUtil/HMI.Simple.Util/DataSender.cs
new file mode 100644
index 0000000..bc22380
--- /dev/null
+++ b/SimpleUtil/HMI.Simple.Util/DataSender.cs
@@ -0,0 +1,103 @@
+锘縰sing System;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+
+namespace HMI.Simple.Util
+{
+    public class DataSender
+    {
+        private string _ip;
+        private int _port;
+        private bool _isConnected = false; // 鏄惁杩炴帴
+        private Socket _clientSocket; // 濂楁帴瀛�
+        private Thread _receiveThread = null; // 鎺ユ敹绾跨▼
+        private volatile bool needRecieve = true;
+
+        public event EventHandler<string> ExecuteMessageChanged;
+
+        public DataSender(string ip, int port)
+        {
+            this._ip = ip;
+            this._port = port;
+        }
+
+        public void Connect()
+        {
+            try
+            {
+                _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+                IPAddress ipaddress = IPAddress.Parse(this._ip);
+                IPEndPoint endpoint = new IPEndPoint(ipaddress, _port);
+                _clientSocket.Connect(endpoint);
+                _isConnected = true;
+                _receiveThread = new Thread(Received);
+                _receiveThread.IsBackground = true;
+                _receiveThread.Start();
+            }
+            catch (Exception ex)
+            {
+                needRecieve = false;
+                _receiveThread?.Abort();
+                _receiveThread = null;
+                _clientSocket.Close();
+                _isConnected = false;
+                throw ex;
+            }
+        }
+
+        public void Disconnect()
+        {
+            needRecieve = false;
+            _clientSocket.Close();
+            _receiveThread?.Abort();
+            _receiveThread = null;
+            _isConnected = false;
+        }
+
+        private void Send(string data)
+        {
+            byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(data);
+            _clientSocket.Send(arrClientSendMsg);
+        }
+
+        private void Received()
+        {
+            //while (needRecieve)
+            //{
+            //    byte[] arrRecMsg = new byte[1024 * 1024];
+            //    int length = _clientSocket.Receive(arrRecMsg);
+            //    string strRecMsg = Encoding.UTF8.GetString(arrRecMsg, 0, length);
+            //    ExecuteMessageChanged?.Invoke(this, strRecMsg);
+            //    Thread.Sleep(100);
+            //}
+        }
+
+
+        public bool SendStep(int ovenIndex, int cellIndex,
+            string name, string send, string value, string unit, string upper, string lower, string result, string time,
+            out string errorMsg)
+        {
+
+            errorMsg = null;
+            try
+            {
+                if (!_isConnected)
+                {
+                    errorMsg = "Not Connected";
+                    return false;
+                }
+
+                string msg = $"{ovenIndex};{cellIndex};{name},{send},{value},{unit},{upper},{lower},{result},{time}\n";
+                Send(msg);
+                return true;
+            }
+            catch (Exception ex)
+            {
+                errorMsg = ex.Message;
+                return false;
+            }
+        }
+    }
+}
diff --git a/SimpleUtil/HMI.Simple.Util/HMI.Simple.Util.csproj b/SimpleUtil/HMI.Simple.Util/HMI.Simple.Util.csproj
index 831cee3..7298ac0 100644
--- a/SimpleUtil/HMI.Simple.Util/HMI.Simple.Util.csproj
+++ b/SimpleUtil/HMI.Simple.Util/HMI.Simple.Util.csproj
@@ -95,6 +95,7 @@
     <Compile Include="ProductUtil.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="SqliteHelper.cs" />
+    <Compile Include="DataSender.cs" />
     <Compile Include="XmlHelper.cs" />
   </ItemGroup>
   <ItemGroup>

--
Gitblit v1.9.1