using DeviceCommand.Base;
using Logger;
using Model.Models;
using Prism.Ioc;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
using UIShare.UIViewModel;
namespace UIShare.GlobalVariable
{
///
/// 设备管理器:根据 反射实例化所有启用的设备,
/// 通过 多态统一管理,避免为每种设备单独硬编码字段。
///
public class DeviceManager
{
private object _lockObj = new object();
public SystemConfig _systemConfig { get; set; }
/// 按 DeviceName 索引的设备字典,便于业务层按名取实例。
public IDictionary DeviceMap { get; private set; }
= new Dictionary(StringComparer.OrdinalIgnoreCase);
/// 类名 → Type 的反射缓存(仅扫描一次)。
private static readonly IReadOnlyDictionary _deviceTypeMap = BuildDeviceTypeMap();
public DeviceManager(SystemConfig systemConfig)
{
_systemConfig = systemConfig;
InitDevices();
}
private void InitDevices()
{
DeviceMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
if (_systemConfig?.DeviceList == null) return;
foreach (var config in _systemConfig.DeviceList)
{
if (config == null || !config.IsEnabled) continue;
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;
}
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}");
}
}
}
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);
}
///
/// 异步关闭指定设备,释放底层连接并更新 UI 状态
///
public async Task CloseDeviceAsync(string deviceName)
{
if (string.IsNullOrWhiteSpace(deviceName)) return;
IBaseInterface? device;
DeviceInfoVM? info;
lock (_lockObj)
{
if (!DeviceMap.TryGetValue(deviceName, out device)) return;
info = _systemConfig?.DeviceList?
.FirstOrDefault(d => d != null && string.Equals(d.DeviceName, deviceName, StringComparison.OrdinalIgnoreCase));
}
await CloseInternalAsync(info, device);
}
///
/// 异步关闭所有设备
///
public async Task CloseAllDevicesAsync()
{
List tasks = new List();
lock (_lockObj)
{
if (DeviceMap.Count == 0) return;
foreach (var kvp in DeviceMap)
{
string deviceName = kvp.Key;
var device = kvp.Value;
var info = _systemConfig?.DeviceList?
.FirstOrDefault(d => d != null && string.Equals(d.DeviceName, deviceName, StringComparison.OrdinalIgnoreCase));
tasks.Add(CloseInternalAsync(info, device));
}
}
await Task.WhenAll(tasks);
LoggerHelper.Info("所有设备已执行关闭操作。");
}
#region 辅助方法
private async Task CloseInternalAsync(DeviceInfoVM? info, IBaseInterface device)
{
string name = info?.DeviceName ?? device.GetType().Name;
string conn = info?.ConnectionType ?? "?";
try
{
// 如果设备本身已经是断开状态,直接更新 UI 并返回
if (!device.IsConnected)
{
if (info != null) info.IsConnected = false;
LoggerHelper.Info($"设备 [{name}] 本就处于断开状态。");
return;
}
await Task.Run(() => device.Close());
LoggerHelper.Info($"设备 [{name}/{conn}] 已成功关闭连接。");
}
catch (Exception ex)
{
var inner = ex.InnerException?.Message ?? ex.Message;
LoggerHelper.Error($"设备 [{name}/{conn}] 关闭连接时出现异常: {inner}");
}
finally
{
// 无论关闭时是否抛出异常,均强制同步 UI 状态为未连接
if (info != null)
{
info.IsConnected = false;
}
}
}
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);
}
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();
var cfg = new TcpConfig
{
IPAddress = vm.IPAddress,
Port = vm.Port,
SendTimeout = vm.SendTimeout,
ReceiveTimeout = vm.ReceiveTimeout
};
return Activator.CreateInstance(type, cfg) as IBaseInterface;
}
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;
}
#endregion
}
}