From a62b6cbc8fdafc250c4a844706f1b5e3977d8d48 Mon Sep 17 00:00:00 2001 From: hsc Date: Thu, 11 Jun 2026 17:25:59 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E5=A4=87=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DeviceCommand/Base/Serial_Port.cs | 3 +- DeviceCommand/Base/TCP.cs | 3 +- DeviceCommand/DeviceCommand.csproj | 1 + DeviceCommand/Devices/IT7800E.cs | 1 + DeviceCommand/Devices/N36200.cs | 1 + DeviceCommand/Devices/N36600.cs | 1 + DeviceCommand/Devices/N69200.cs | 1 + DeviceCommand/Devices/SDS2000X_HD.cs | 1 + DeviceCommand/Devices/SPAW7000.cs | 1 + .../ViewModels/AutomatedTestingViewModel.cs | 8 + MainModule/Views/AutomatedTestingView.xaml | 5 + Model/Model.csproj | 1 + .../Base => Model/Models}/SerialPortConfig.cs | 2 +- .../Base => Model/Models}/TcpConfig.cs | 2 +- UIShare/GlobalVariable/DeviceManager.cs | 148 ++++++++++++++---- 15 files changed, 144 insertions(+), 35 deletions(-) rename {DeviceCommand/Base => Model/Models}/SerialPortConfig.cs (96%) rename {DeviceCommand/Base => Model/Models}/TcpConfig.cs (94%) diff --git a/DeviceCommand/Base/Serial_Port.cs b/DeviceCommand/Base/Serial_Port.cs index 6dd8ea8..9b4e0ba 100644 --- a/DeviceCommand/Base/Serial_Port.cs +++ b/DeviceCommand/Base/Serial_Port.cs @@ -1,4 +1,5 @@ -using System; +using Model.Models; +using System; using System.IO.Ports; using System.Text; using System.Threading; diff --git a/DeviceCommand/Base/TCP.cs b/DeviceCommand/Base/TCP.cs index e4292db..0f7d067 100644 --- a/DeviceCommand/Base/TCP.cs +++ b/DeviceCommand/Base/TCP.cs @@ -1,4 +1,5 @@ -using System; +using Model.Models; +using System; using System.IO; using System.Net.Sockets; using System.Text; diff --git a/DeviceCommand/DeviceCommand.csproj b/DeviceCommand/DeviceCommand.csproj index d9b2b2a..ca7efa5 100644 --- a/DeviceCommand/DeviceCommand.csproj +++ b/DeviceCommand/DeviceCommand.csproj @@ -13,6 +13,7 @@ + diff --git a/DeviceCommand/Devices/IT7800E.cs b/DeviceCommand/Devices/IT7800E.cs index 0f8e32c..dee4377 100644 --- a/DeviceCommand/Devices/IT7800E.cs +++ b/DeviceCommand/Devices/IT7800E.cs @@ -1,5 +1,6 @@ using Common.Attributes; using DeviceCommand.Base; +using Model.Models; using System; using System.Globalization; using System.Threading; diff --git a/DeviceCommand/Devices/N36200.cs b/DeviceCommand/Devices/N36200.cs index c4f4eb4..dda310e 100644 --- a/DeviceCommand/Devices/N36200.cs +++ b/DeviceCommand/Devices/N36200.cs @@ -1,5 +1,6 @@ using Common.Attributes; using DeviceCommand.Base; +using Model.Models; using System; using System.Globalization; using System.Threading; diff --git a/DeviceCommand/Devices/N36600.cs b/DeviceCommand/Devices/N36600.cs index 33f562d..0ab64d3 100644 --- a/DeviceCommand/Devices/N36600.cs +++ b/DeviceCommand/Devices/N36600.cs @@ -1,5 +1,6 @@ using Common.Attributes; using DeviceCommand.Base; +using Model.Models; using System; using System.ComponentModel; using System.Globalization; diff --git a/DeviceCommand/Devices/N69200.cs b/DeviceCommand/Devices/N69200.cs index 2d85091..36484ec 100644 --- a/DeviceCommand/Devices/N69200.cs +++ b/DeviceCommand/Devices/N69200.cs @@ -1,5 +1,6 @@ using Common.Attributes; using DeviceCommand.Base; +using Model.Models; using System; using System.Globalization; using System.Threading; diff --git a/DeviceCommand/Devices/SDS2000X_HD.cs b/DeviceCommand/Devices/SDS2000X_HD.cs index ba7bd0f..fb309e1 100644 --- a/DeviceCommand/Devices/SDS2000X_HD.cs +++ b/DeviceCommand/Devices/SDS2000X_HD.cs @@ -1,5 +1,6 @@ using Common.Attributes; using DeviceCommand.Base; +using Model.Models; using System; using System.Globalization; using System.Threading; diff --git a/DeviceCommand/Devices/SPAW7000.cs b/DeviceCommand/Devices/SPAW7000.cs index 712fcc5..1804321 100644 --- a/DeviceCommand/Devices/SPAW7000.cs +++ b/DeviceCommand/Devices/SPAW7000.cs @@ -1,5 +1,6 @@ using Common.Attributes; using DeviceCommand.Base; +using Model.Models; using System; using System.Globalization; using System.Threading; diff --git a/MainModule/ViewModels/AutomatedTestingViewModel.cs b/MainModule/ViewModels/AutomatedTestingViewModel.cs index b444a70..1049d14 100644 --- a/MainModule/ViewModels/AutomatedTestingViewModel.cs +++ b/MainModule/ViewModels/AutomatedTestingViewModel.cs @@ -46,6 +46,7 @@ namespace MainModule.ViewModels public ICommand RefreshCommand { get; set; } public ICommand BackToProtocolCommand { get; set; } + public ICommand LoadedCommand { get; set; } public AutomatedTestingViewModel(IContainerExtension container) : base(container) { @@ -75,8 +76,10 @@ namespace MainModule.ViewModels ParametersManagerVM = _scope.Resolve(); RefreshCommand = new DelegateCommand(OnRefresh); BackToProtocolCommand = new DelegateCommand(OnBackToProtocol); + LoadedCommand = new AsyncDelegateCommand(OnLoad); } + public void Dispose() { // 1. 如果 TestStatus 为空,说明还没走到 OnNavigatedTo 赋值,直接释放 scope 即可 @@ -114,6 +117,11 @@ namespace MainModule.ViewModels } } #region 命令处理与事件 + private async Task OnLoad() + { + await _deviceManager.ConnectAllDevices(); + } + private void OnRefresh() { // 双击:把自己的名字扔出去 diff --git a/MainModule/Views/AutomatedTestingView.xaml b/MainModule/Views/AutomatedTestingView.xaml index 786cd78..2ec97a5 100644 --- a/MainModule/Views/AutomatedTestingView.xaml +++ b/MainModule/Views/AutomatedTestingView.xaml @@ -15,6 +15,11 @@ + + + + + + diff --git a/DeviceCommand/Base/SerialPortConfig.cs b/Model/Models/SerialPortConfig.cs similarity index 96% rename from DeviceCommand/Base/SerialPortConfig.cs rename to Model/Models/SerialPortConfig.cs index d1dbd39..2ef0d87 100644 --- a/DeviceCommand/Base/SerialPortConfig.cs +++ b/Model/Models/SerialPortConfig.cs @@ -1,6 +1,6 @@ using System.IO.Ports; -namespace DeviceCommand.Base +namespace Model.Models { /// /// 串口通信参数(DeviceCommand 内部纯数据类,供设备类构造函数使用)。 diff --git a/DeviceCommand/Base/TcpConfig.cs b/Model/Models/TcpConfig.cs similarity index 94% rename from DeviceCommand/Base/TcpConfig.cs rename to Model/Models/TcpConfig.cs index ae1abd3..6982461 100644 --- a/DeviceCommand/Base/TcpConfig.cs +++ b/Model/Models/TcpConfig.cs @@ -1,4 +1,4 @@ -namespace DeviceCommand.Base +namespace Model.Models { /// /// TCP 通信参数(DeviceCommand 内部纯数据类,供设备类构造函数使用)。 diff --git a/UIShare/GlobalVariable/DeviceManager.cs b/UIShare/GlobalVariable/DeviceManager.cs index 6b871d5..3fa58e5 100644 --- a/UIShare/GlobalVariable/DeviceManager.cs +++ b/UIShare/GlobalVariable/DeviceManager.cs @@ -1,5 +1,6 @@ using DeviceCommand.Base; using Logger; +using Model.Models; using Prism.Ioc; using System; using System.Collections.Generic; @@ -29,29 +30,7 @@ namespace UIShare.GlobalVariable { _systemConfig = systemConfig; InitDevices(); - } - - /// - /// 扫描 所在程序集中所有可实例化的实现类, - /// 以类型名为键建立映射。这样新增设备类无需修改 DeviceManager。 - /// - private static IReadOnlyDictionary BuildDeviceTypeMap() - { - try - { - return typeof(IBaseInterface).Assembly - .GetTypes() - .Where(t => t.IsClass && !t.IsAbstract && typeof(IBaseInterface).IsAssignableFrom(t)) - .ToDictionary(t => t.Name, t => t, StringComparer.OrdinalIgnoreCase); - } - catch (ReflectionTypeLoadException ex) - { - LoggerHelper.Error($"扫描设备类型失败:{ex.Message}"); - return new Dictionary(StringComparer.OrdinalIgnoreCase); - } - } - private void InitDevices() { DeviceMap = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -98,10 +77,121 @@ namespace UIShare.GlobalVariable } } - /// - /// 实例化 TCP 类设备:将 转为 POCO, - /// 调用设备类的 (TcpConfig) 构造函数。 - /// + public async Task ConnectAllDevices(CancellationToken ct = default) + { + if (_systemConfig?.DeviceList == null || DeviceMap.Count == 0) return; + + var tasks = new List(); + foreach (var info in _systemConfig.DeviceList) + { + if (info == null || !info.IsEnabled) continue; + if (string.IsNullOrWhiteSpace(info.DeviceName)) continue; + if (!DeviceMap.TryGetValue(info.DeviceName, out var device)) continue; + + tasks.Add(ConnectInternalAsync(info, device, ct)); + } + + await Task.WhenAll(tasks); + } + + + public async Task ConnectSpecifiedDevice(string deviceName, CancellationToken ct = default) + { + if (string.IsNullOrWhiteSpace(deviceName)) + { + LoggerHelper.Warn("ConnectSpecifiedDevice:设备名为空。"); + return; + } + + if (!DeviceMap.TryGetValue(deviceName, out var device)) + { + LoggerHelper.Warn($"ConnectSpecifiedDevice:未找到设备 [{deviceName}]。"); + return; + } + + var info = _systemConfig?.DeviceList? + .FirstOrDefault(d => d != null && string.Equals(d.DeviceName, deviceName, StringComparison.OrdinalIgnoreCase)); + + await ConnectInternalAsync(info, device, ct); + } + + + private async Task ConnectInternalAsync(DeviceInfoVM? info, IBaseInterface device, CancellationToken ct) + { + string name = info?.DeviceName ?? device.GetType().Name; + string conn = info?.ConnectionType ?? "?"; + + try + { + if (device.IsConnected) + { + if (info != null) info.IsConnected = true; + LoggerHelper.Info($"设备 [{name}] 已连接,跳过。"); + return; + } + + bool ok = conn switch + { + "Tcp" => await ConnectTcpAsync(name, device, ct), + "Serial" => await ConnectSerialAsync(name, device, ct), + _ => false + }; + + if (info != null) info.IsConnected = ok; + + if (ok) + LoggerHelper.Info($"设备 [{name}/{conn}] 连接成功。"); + else + LoggerHelper.Warn($"设备 [{name}/{conn}] 连接失败。"); + } + catch (OperationCanceledException) + { + if (info != null) info.IsConnected = false; + LoggerHelper.Warn($"设备 [{name}/{conn}] 连接已取消。"); + } + catch (Exception ex) + { + if (info != null) info.IsConnected = false; + var inner = ex.InnerException?.Message ?? ex.Message; + LoggerHelper.ErrorWithNotify($"设备 [{name}/{conn}] 连接异常:{inner}"); + } + } + + private static async Task ConnectTcpAsync(string name, IBaseInterface device, CancellationToken ct) + { + if (device is not ITcp tcp) + { + LoggerHelper.Warn($"设备 [{name}] 配置为 Tcp 但未实现 ITcp,实际类型为 {device.GetType().Name}。"); + return false; + } + return await tcp.ConnectAsync(ct); + } + + private static async Task ConnectSerialAsync(string name, IBaseInterface device, CancellationToken ct) + { + if (device is not ISerialPort sp) + { + LoggerHelper.Warn($"设备 [{name}] 配置为 Serial 但未实现 ISerialPort,实际类型为 {device.GetType().Name}。"); + return false; + } + return await sp.ConnectAsync(ct); + } + #region 辅助方法 + private static IReadOnlyDictionary BuildDeviceTypeMap() + { + try + { + return typeof(IBaseInterface).Assembly + .GetTypes() + .Where(t => t.IsClass && !t.IsAbstract && typeof(IBaseInterface).IsAssignableFrom(t)) + .ToDictionary(t => t.Name, t => t, StringComparer.OrdinalIgnoreCase); + } + catch (ReflectionTypeLoadException ex) + { + LoggerHelper.Error($"扫描设备类型失败:{ex.Message}"); + return new Dictionary(StringComparer.OrdinalIgnoreCase); + } + } private static IBaseInterface? CreateTcpDevice(Type type, TcpConfigVM? vm) { vm ??= new TcpConfigVM(); @@ -114,11 +204,6 @@ namespace UIShare.GlobalVariable }; return Activator.CreateInstance(type, cfg) as IBaseInterface; } - - /// - /// 实例化串口类设备:将 转为 POCO, - /// StopBits / Parity 从字符串解析为枚举,调用设备类的 (SerialPortConfig) 构造函数。 - /// private static IBaseInterface? CreateSerialDevice(Type type, SerialPortConfigVM? vm) { vm ??= new SerialPortConfigVM(); @@ -134,5 +219,6 @@ namespace UIShare.GlobalVariable }; return Activator.CreateInstance(type, cfg) as IBaseInterface; } + #endregion } }