diff --git a/DeviceCommand/Base/SerialPortConfig.cs b/DeviceCommand/Base/SerialPortConfig.cs
new file mode 100644
index 0000000..d1dbd39
--- /dev/null
+++ b/DeviceCommand/Base/SerialPortConfig.cs
@@ -0,0 +1,27 @@
+using System.IO.Ports;
+
+namespace DeviceCommand.Base
+{
+ ///
+ /// 串口通信参数(DeviceCommand 内部纯数据类,供设备类构造函数使用)。
+ /// 与 UIShare.UIViewModel.SerialPortConfigVM 字段一一对应,
+ /// StopBits / Parity 在此处使用 System.IO.Ports 强类型枚举,
+ /// 由 DeviceManager 从字符串解析后填入。
+ ///
+ public class SerialPortConfig
+ {
+ public string PortName { get; set; } = "COM1";
+
+ public int BaudRate { get; set; } = 9600;
+
+ public int DataBits { get; set; } = 8;
+
+ public StopBits StopBits { get; set; } = StopBits.One;
+
+ public Parity Parity { get; set; } = Parity.None;
+
+ public int ReadTimeout { get; set; } = 3000;
+
+ public int WriteTimeout { get; set; } = 3000;
+ }
+}
diff --git a/DeviceCommand/Base/Serial_Port.cs b/DeviceCommand/Base/Serial_Port.cs
index 9c0ed0f..6dd8ea8 100644
--- a/DeviceCommand/Base/Serial_Port.cs
+++ b/DeviceCommand/Base/Serial_Port.cs
@@ -25,6 +25,15 @@ namespace DeviceCommand.Base
_serialPort = new SerialPort();
}
+ ///
+ /// 通过 一次性配置串口通信参数。
+ ///
+ public Serial_Port(SerialPortConfig config) : this()
+ {
+ if (config == null) return;
+ ConfigureDevice(config.PortName, config.BaudRate, config.DataBits, config.StopBits, config.Parity, config.ReadTimeout, config.WriteTimeout);
+ }
+
public void ConfigureDevice(string portName, int baudRate, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None, int readTimeout = 3000, int writeTimeout = 3000)
{
PortName = portName;
diff --git a/DeviceCommand/Base/TCP.cs b/DeviceCommand/Base/TCP.cs
index 28f5621..e4292db 100644
--- a/DeviceCommand/Base/TCP.cs
+++ b/DeviceCommand/Base/TCP.cs
@@ -23,6 +23,15 @@ namespace DeviceCommand.Base
_tcpClient = new TcpClient();
}
+ ///
+ /// 通过 一次性配置 TCP 通信参数。
+ ///
+ public Tcp(TcpConfig config) : this()
+ {
+ if (config == null) return;
+ ConfigureDevice(config.IPAddress, config.Port, config.SendTimeout, config.ReceiveTimeout);
+ }
+
public void ConfigureDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
{
IPAddress = ipAddress;
diff --git a/DeviceCommand/Base/TcpConfig.cs b/DeviceCommand/Base/TcpConfig.cs
new file mode 100644
index 0000000..ae1abd3
--- /dev/null
+++ b/DeviceCommand/Base/TcpConfig.cs
@@ -0,0 +1,17 @@
+namespace DeviceCommand.Base
+{
+ ///
+ /// TCP 通信参数(DeviceCommand 内部纯数据类,供设备类构造函数使用)。
+ /// 与 UIShare.UIViewModel.TcpConfigVM 字段一一对应,由 DeviceManager 在实例化时填充。
+ ///
+ public class TcpConfig
+ {
+ public string IPAddress { get; set; } = "127.0.0.1";
+
+ public int Port { get; set; } = 502;
+
+ public int SendTimeout { get; set; } = 3000;
+
+ public int ReceiveTimeout { get; set; } = 3000;
+ }
+}
diff --git a/DeviceCommand/Devices/IT7800E.cs b/DeviceCommand/Devices/IT7800E.cs
index ec57a1d..0f8e32c 100644
--- a/DeviceCommand/Devices/IT7800E.cs
+++ b/DeviceCommand/Devices/IT7800E.cs
@@ -14,11 +14,10 @@ namespace DeviceCommand.Device
private const string ScpiDelimiter = "\n";
///
- /// 构造函数:初始化 IT7800E 交直流电源通信参数
+ /// 构造函数:传入 一次性初始化 IT7800E 交直流电源通信参数。
///
- public IT7800E(string ipAddress, int port, int sendTimeout, int receiveTimeout)
+ public IT7800E(TcpConfig config) : base(config)
{
- ConfigureDevice(ipAddress, port, sendTimeout, receiveTimeout);
}
#region 1. IEEE 488.2 公共命令
diff --git a/DeviceCommand/Devices/N36200.cs b/DeviceCommand/Devices/N36200.cs
index 99dac04..c4f4eb4 100644
--- a/DeviceCommand/Devices/N36200.cs
+++ b/DeviceCommand/Devices/N36200.cs
@@ -14,11 +14,10 @@ namespace DeviceCommand.Device
private const string ScpiDelimiter = "\n";
///
- /// 构造函数:初始化 N36200/N36300 设备通信参数
+ /// 构造函数:传入 一次性初始化 N36200/N36300 设备通信参数。
///
- public N36200(string ipAddress, int port, int sendTimeout, int receiveTimeout)
+ public N36200(TcpConfig config) : base(config)
{
- ConfigureDevice(ipAddress, port, sendTimeout, receiveTimeout);
}
#region 3.1. IEEE 488.2 公共命令
diff --git a/DeviceCommand/Devices/N36600.cs b/DeviceCommand/Devices/N36600.cs
index 6579900..33f562d 100644
--- a/DeviceCommand/Devices/N36600.cs
+++ b/DeviceCommand/Devices/N36600.cs
@@ -22,9 +22,8 @@ namespace DeviceCommand.Device
// 手册第 4 页明确规定:每条命令后面都要加结束符 0x0A (\n)
private const string SCPIDelimiter = "\n";
- public N36600(string ipAddress, int port, int sendTimeout, int receiveTimeout)
+ public N36600(TcpConfig config) : base(config)
{
- ConfigureDevice(ipAddress, port, sendTimeout, receiveTimeout);
}
///
diff --git a/DeviceCommand/Devices/N69200.cs b/DeviceCommand/Devices/N69200.cs
index 2b88a79..2d85091 100644
--- a/DeviceCommand/Devices/N69200.cs
+++ b/DeviceCommand/Devices/N69200.cs
@@ -14,11 +14,10 @@ namespace DeviceCommand.Device
private const string ScpiDelimiter = "\n";
///
- /// 构造函数:初始化 N69200 电子负载通信参数
+ /// 构造函数:传入 一次性初始化 N69200 电子负载通信参数。
///
- public N69200(string ipAddress, int port, int sendTimeout, int receiveTimeout)
+ public N69200(TcpConfig config) : base(config)
{
- ConfigureDevice(ipAddress, port, sendTimeout, receiveTimeout);
}
#region 3.1. IEEE 488.2 公共命令
diff --git a/DeviceCommand/Devices/SDS2000X_HD.cs b/DeviceCommand/Devices/SDS2000X_HD.cs
index e44dbb0..ba7bd0f 100644
--- a/DeviceCommand/Devices/SDS2000X_HD.cs
+++ b/DeviceCommand/Devices/SDS2000X_HD.cs
@@ -14,11 +14,11 @@ namespace DeviceCommand.Device
private const string ScpiDelimiter = "\n";
///
- /// 构造函数:初始化示波器通信参数 (鼎阳示波器网口 Socket 默认端口通常为 5025)
+ /// 构造函数:传入 一次性初始化示波器通信参数。
+ /// 鼎阳示波器网口 Socket 默认端口通常为 5025,请在配置中设置。
///
- public SDS2000X_HD(string ipAddress, int port = 5025, int sendTimeout = 3000, int receiveTimeout = 3000)
+ public SDS2000X_HD(TcpConfig config) : base(config)
{
- ConfigureDevice(ipAddress, port, sendTimeout, receiveTimeout);
}
#region 1. IEEE 488.2 公共命令
diff --git a/DeviceCommand/Devices/SPAW7000.cs b/DeviceCommand/Devices/SPAW7000.cs
index 3bed253..712fcc5 100644
--- a/DeviceCommand/Devices/SPAW7000.cs
+++ b/DeviceCommand/Devices/SPAW7000.cs
@@ -14,11 +14,10 @@ namespace DeviceCommand.Device
private const string ScpiDelimiter = "\n";
///
- /// 构造函数:初始化 SPAW7000 功率分析记录仪通信参数
+ /// 构造函数:传入 一次性初始化 SPAW7000 功率分析记录仪通信参数。
///
- public SPAW7000(string ipAddress, int port, int sendTimeout, int receiveTimeout)
+ public SPAW7000(TcpConfig config) : base(config)
{
- ConfigureDevice(ipAddress, port, sendTimeout, receiveTimeout);
}
#region 1. IEEE 488.2 公共命令
diff --git a/MainModule/ViewModels/AutomatedTestingViewModel.cs b/MainModule/ViewModels/AutomatedTestingViewModel.cs
index 3392937..d9f4a7d 100644
--- a/MainModule/ViewModels/AutomatedTestingViewModel.cs
+++ b/MainModule/ViewModels/AutomatedTestingViewModel.cs
@@ -47,7 +47,7 @@ namespace MainModule.ViewModels
public ICommand RefreshCommand { get; set; }
public ICommand BackToProtocolCommand { get; set; }
- public AutomatedTestingViewModel(IContainerProvider container) : base(container)
+ public AutomatedTestingViewModel(IContainerExtension container) : base(container)
{
// 每个 AutomatedTestingViewModel 实例创建独立的容器作用域
_scope = container.CreateScope();
@@ -55,7 +55,7 @@ namespace MainModule.ViewModels
// 在该作用域内解析 ScopedContext —— 当前作用域唯一
_scopedContext = _scope.Resolve();
_stepRunning = _scope.Resolve();
- _systemConfig = _scope.Resolve();;
+ _systemConfig = _scope.Resolve();
// 关键:从同一个 _scope 解析 5 个子 VM,DI 会把同一个 ScopedContext 注入它们
CommandTreeVM = _scope.Resolve();
StepsManagerVM = _scope.Resolve();
@@ -64,7 +64,6 @@ namespace MainModule.ViewModels
ParametersManagerVM = _scope.Resolve();
RefreshCommand = new DelegateCommand(OnRefresh);
BackToProtocolCommand = new DelegateCommand(OnBackToProtocol);
-
}
public void Dispose()
diff --git a/UIShare/GlobalVariable/DeviceManager.cs b/UIShare/GlobalVariable/DeviceManager.cs
index b69f0f7..a2dc989 100644
--- a/UIShare/GlobalVariable/DeviceManager.cs
+++ b/UIShare/GlobalVariable/DeviceManager.cs
@@ -1,45 +1,140 @@
using DeviceCommand.Base;
-using DeviceCommand.Device;
+using Logger;
using Prism.Ioc;
using System;
using System.Collections.Generic;
+using System.IO.Ports;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.Reflection;
+using UIShare.UIViewModel;
namespace UIShare.GlobalVariable
{
+ ///
+ /// 设备管理器:根据 反射实例化所有启用的设备,
+ /// 通过 多态统一管理,避免为每种设备单独硬编码字段。
+ ///
public class DeviceManager
{
public SystemConfig _systemConfig { get; set; }
- public IContainerProvider _containerProvider { get; set; }
- public IT7800E _iT7800E { get; set; }
- public N36200 _n36200 { get; set; }
- public N36600 _n36600 { get; set; }
- public N69200 _n69200 { get; set; }
- public SDS2000X_HD _sDS2000X_HD { get; set; }
- public SPAW7000 _sPAW7000 { get; set; }
- public IList DeviceList { get; set; }
- public DeviceManager(IContainerProvider containerProvider,SystemConfig systemConfig)
+ public IList DeviceList { get; private set; } = new List();
+
+ /// 按 DeviceName 索引的设备字典,便于业务层按名取实例。
+ public IDictionary DeviceMap { get; private set; }
+ = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ /// 类名 → Type 的反射缓存(仅扫描一次)。
+ private static readonly IReadOnlyDictionary _deviceTypeMap = BuildDeviceTypeMap();
+
+ public DeviceManager(SystemConfig systemConfig)
{
- _containerProvider = containerProvider;
_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()
{
- foreach(var Config in _systemConfig.DeviceList)
+ DeviceMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ if (_systemConfig?.DeviceList == null) return;
+
+ foreach (var config in _systemConfig.DeviceList)
{
- if (Config.ConnectionType == "Tcp")
- {
+ if (config == null || !config.IsEnabled) continue;
- }
- else if (Config.ConnectionType == "Serial")
+ if (string.IsNullOrWhiteSpace(config.DeviceType) ||
+ !_deviceTypeMap.TryGetValue(config.DeviceType, out var deviceType))
{
+ LoggerHelper.Warn($"未识别的设备类型 [{config.DeviceType}],已跳过 [{config.DeviceName}]。");
+ continue;
+ }
+ try
+ {
+ IBaseInterface? instance = config.ConnectionType switch
+ {
+ "Tcp" => CreateTcpDevice(deviceType, config.TcpConfig),
+ "Serial" => CreateSerialDevice(deviceType, config.SerialPortConfig),
+ _ => null
+ };
+
+ if (instance == null)
+ {
+ LoggerHelper.Warn($"设备 [{config.DeviceName}] 连接方式 [{config.ConnectionType}] 不支持,已跳过。");
+ continue;
+ }
+
+ DeviceList.Add(instance);
+ if (!string.IsNullOrWhiteSpace(config.DeviceName))
+ {
+ DeviceMap[config.DeviceName] = instance;
+ }
+
+ LoggerHelper.Info($"已加载设备 [{config.DeviceName} / {config.DeviceType} / {config.ConnectionType}]");
+ }
+ catch (Exception ex)
+ {
+ var inner = ex.InnerException?.Message ?? ex.Message;
+ LoggerHelper.ErrorWithNotify($"设备 [{config.DeviceName}] 实例化失败:{inner}");
}
}
}
+
+ ///
+ /// 实例化 TCP 类设备:将 转为 POCO,
+ /// 调用设备类的 (TcpConfig) 构造函数。
+ ///
+ private static IBaseInterface? CreateTcpDevice(Type type, TcpConfigVM? vm)
+ {
+ vm ??= new TcpConfigVM();
+ var cfg = new TcpConfig
+ {
+ IPAddress = vm.IPAddress,
+ Port = vm.Port,
+ SendTimeout = vm.SendTimeout,
+ ReceiveTimeout = vm.ReceiveTimeout
+ };
+ return Activator.CreateInstance(type, cfg) as IBaseInterface;
+ }
+
+ ///
+ /// 实例化串口类设备:将 转为 POCO,
+ /// StopBits / Parity 从字符串解析为枚举,调用设备类的 (SerialPortConfig) 构造函数。
+ ///
+ private static IBaseInterface? CreateSerialDevice(Type type, SerialPortConfigVM? vm)
+ {
+ vm ??= new SerialPortConfigVM();
+ var cfg = new SerialPortConfig
+ {
+ PortName = vm.PortName,
+ BaudRate = vm.BaudRate,
+ DataBits = vm.DataBits,
+ StopBits = Enum.TryParse(vm.StopBits, true, out var sb) ? sb : StopBits.One,
+ Parity = Enum.TryParse(vm.Parity, true, out var pa) ? pa : Parity.None,
+ ReadTimeout = vm.ReadTimeout,
+ WriteTimeout = vm.WriteTimeout
+ };
+ return Activator.CreateInstance(type, cfg) as IBaseInterface;
+ }
}
}