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
}
}