设备数量不对等适配
This commit is contained in:
@@ -19,6 +19,7 @@ namespace UIShare.GlobalVariable
|
|||||||
{
|
{
|
||||||
private object _lockObj = new object();
|
private object _lockObj = new object();
|
||||||
public SystemConfig _systemConfig { get; set; }
|
public SystemConfig _systemConfig { get; set; }
|
||||||
|
private readonly GlobalInfo _globalInfo;
|
||||||
|
|
||||||
/// <summary>按 DeviceName 索引的设备字典,便于业务层按名取实例。</summary>
|
/// <summary>按 DeviceName 索引的设备字典,便于业务层按名取实例。</summary>
|
||||||
public IDictionary<string, IBaseInterface> DeviceMap { get; private set; }
|
public IDictionary<string, IBaseInterface> DeviceMap { get; private set; }
|
||||||
@@ -27,11 +28,33 @@ namespace UIShare.GlobalVariable
|
|||||||
/// <summary>类名 → Type 的反射缓存(仅扫描一次)。</summary>
|
/// <summary>类名 → Type 的反射缓存(仅扫描一次)。</summary>
|
||||||
private static readonly IReadOnlyDictionary<string, Type> _deviceTypeMap = BuildDeviceTypeMap();
|
private static readonly IReadOnlyDictionary<string, Type> _deviceTypeMap = BuildDeviceTypeMap();
|
||||||
|
|
||||||
public DeviceManager(SystemConfig systemConfig)
|
public DeviceManager(SystemConfig systemConfig, GlobalInfo globalInfo)
|
||||||
{
|
{
|
||||||
_systemConfig = systemConfig;
|
_systemConfig = systemConfig;
|
||||||
|
_globalInfo = globalInfo;
|
||||||
InitDevices();
|
InitDevices();
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 根据设备配置提取唯一的硬件指纹字符串。
|
||||||
|
/// <para>Tcp → "Tcp:IP:Port";Serial → "Serial:PortName";无法识别则返回空字符串。</para>
|
||||||
|
/// </summary>
|
||||||
|
private static string ExtractHardwareFingerprint(DeviceInfoVM config)
|
||||||
|
{
|
||||||
|
if (string.Equals(config.ConnectionType, "Tcp", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& config.TcpConfig != null)
|
||||||
|
{
|
||||||
|
return $"Tcp:{config.TcpConfig.IPAddress}:{config.TcpConfig.Port}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(config.ConnectionType, "Serial", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& config.SerialPortConfig != null)
|
||||||
|
{
|
||||||
|
return $"Serial:{config.SerialPortConfig.PortName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
private void InitDevices()
|
private void InitDevices()
|
||||||
{
|
{
|
||||||
DeviceMap = new Dictionary<string, IBaseInterface>(StringComparer.OrdinalIgnoreCase);
|
DeviceMap = new Dictionary<string, IBaseInterface>(StringComparer.OrdinalIgnoreCase);
|
||||||
@@ -51,24 +74,41 @@ namespace UIShare.GlobalVariable
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IBaseInterface? instance = config.ConnectionType switch
|
// 第一步:提取硬件指纹,为空则跳过
|
||||||
|
var fingerprint = ExtractHardwareFingerprint(config);
|
||||||
|
if (string.IsNullOrEmpty(fingerprint))
|
||||||
{
|
{
|
||||||
"Tcp" => CreateTcpDevice(deviceType, config.TcpConfig),
|
LoggerHelper.Warn($"设备 [{config.DeviceName}] 无法提取硬件指纹(连接方式={config.ConnectionType}),已跳过。");
|
||||||
"Serial" => CreateSerialDevice(deviceType, config.SerialPortConfig),
|
continue;
|
||||||
_ => null
|
}
|
||||||
|
|
||||||
|
// 第二步:原子化获取或添加 Lazy 包装盒,确保同一指纹全局只创建一个实例
|
||||||
|
var lazy = _globalInfo.HardwarePool.GetOrAdd(fingerprint, key => new Lazy<IBaseInterface>(() =>
|
||||||
|
{
|
||||||
|
return config.ConnectionType switch
|
||||||
|
{
|
||||||
|
"Tcp" => CreateTcpDevice(deviceType, config.TcpConfig)!,
|
||||||
|
"Serial" => CreateSerialDevice(deviceType, config.SerialPortConfig)!,
|
||||||
|
_ => null!
|
||||||
};
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 第三步:安全拆盒,Lazy 内部线程锁保证只实例化一次
|
||||||
|
var instance = lazy.Value;
|
||||||
|
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
{
|
{
|
||||||
LoggerHelper.Warn($"设备 [{config.DeviceName}] 连接方式 [{config.ConnectionType}] 不支持,已跳过。");
|
LoggerHelper.Warn($"设备 [{config.DeviceName}] 连接方式 [{config.ConnectionType}] 不支持,已跳过。");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 第四步:绑定逻辑名 → 同一物理设备可被多个台架名称映射
|
||||||
if (!string.IsNullOrWhiteSpace(config.DeviceName))
|
if (!string.IsNullOrWhiteSpace(config.DeviceName))
|
||||||
{
|
{
|
||||||
DeviceMap[config.DeviceName] = instance;
|
DeviceMap[config.DeviceName] = instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoggerHelper.Info($"已加载设备 [{config.DeviceName} / {config.DeviceType} / {config.ConnectionType}]");
|
LoggerHelper.Info($"已加载设备 [{config.DeviceName} / {config.DeviceType} / {config.ConnectionType}] 指纹={fingerprint}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using DeviceCommand.Base;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -13,6 +15,10 @@ namespace UIShare.GlobalVariable
|
|||||||
public Dictionary<string,StepRunning> StepRunningDic { get; set; }
|
public Dictionary<string,StepRunning> StepRunningDic { get; set; }
|
||||||
public Dictionary<string, SystemConfig> ConfigDic { get; set; }
|
public Dictionary<string, SystemConfig> ConfigDic { get; set; }
|
||||||
public Dictionary<string, IScopedProvider> ScopeDic { get; set; }
|
public Dictionary<string, IScopedProvider> ScopeDic { get; set; }
|
||||||
|
|
||||||
|
/// <summary>硬件指纹 → 设备实例的并发池,确保同一物理硬件全局只创建一个驱动实例。</summary>
|
||||||
|
public ConcurrentDictionary<string, Lazy<IBaseInterface>> HardwarePool { get; set; }
|
||||||
|
|
||||||
public String UserName { get; set; } = "Not Logged in";
|
public String UserName { get; set; } = "Not Logged in";
|
||||||
public bool IsAdmin { get; set; } = true;
|
public bool IsAdmin { get; set; } = true;
|
||||||
public string CurrentOpeningScope;
|
public string CurrentOpeningScope;
|
||||||
@@ -35,6 +41,7 @@ namespace UIShare.GlobalVariable
|
|||||||
StepRunningDic = new();
|
StepRunningDic = new();
|
||||||
ConfigDic = new();
|
ConfigDic = new();
|
||||||
ScopeDic = new();
|
ScopeDic = new();
|
||||||
|
HardwarePool = new ConcurrentDictionary<string, Lazy<IBaseInterface>>(StringComparer.OrdinalIgnoreCase);
|
||||||
CurrentScope = "default";
|
CurrentScope = "default";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user