将Feature/XP.Common和Feature/XP.Hardware分支合并至Develop/XP.forHardwareAndCommon,完善XPapp注册和相关硬件类库通用类库功能。
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
using Prism.Ioc;
|
||||
using Prism.Modularity;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Resources;
|
||||
using XP.Common.Localization;
|
||||
using XP.Common.Localization.Interfaces;
|
||||
using XP.Hardware.Plc.Abstractions;
|
||||
using XP.Hardware.Plc.Core;
|
||||
using XP.Hardware.Plc.Services;
|
||||
using XP.Hardware.PLC.Configs;
|
||||
using XP.Hardware.PLC.Helpers;
|
||||
using XP.Hardware.PLC.Services;
|
||||
using XP.Hardware.PLC.Views;
|
||||
|
||||
namespace XP.Hardware.PLC
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC 模块,负责向依赖注入容器注册 PLC 相关服务 | PLC module, responsible for registering PLC-related services to the DI container
|
||||
/// </summary>
|
||||
public class PLCModule : IModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 模块初始化方法 | Module initialization method
|
||||
/// </summary>
|
||||
/// <param name="containerProvider">容器提供者 | Container provider</param>
|
||||
public void OnInitialized(IContainerProvider containerProvider)
|
||||
{
|
||||
// 注册模块级多语言资源到 Fallback Chain | Register module-level localization resources to Fallback Chain
|
||||
var localizationService = containerProvider.Resolve<ILocalizationService>();
|
||||
var resourceManager = new ResourceManager(
|
||||
"XP.Hardware.PLC.Resources.Resources",
|
||||
typeof(PLCModule).Assembly);
|
||||
localizationService.RegisterResourceSource("XP.Hardware.PLC", resourceManager);
|
||||
|
||||
// 初始化 LocalizationHelper,使其通过 ILocalizationService 获取字符串(支持 Fallback Chain)
|
||||
// Initialize LocalizationHelper to use ILocalizationService for string lookup (supports Fallback Chain)
|
||||
LocalizationHelper.Initialize(localizationService);
|
||||
|
||||
// 将写入队列和直接写入通道注册到 PlcService,由 PlcService 统一管理生命周期
|
||||
// Register write queue and direct write channel to PlcService for unified lifecycle management
|
||||
var plcService = containerProvider.Resolve<PlcService>();
|
||||
var writeQueue = containerProvider.Resolve<PlcWriteQueue>();
|
||||
// SignalDataService 持有的 directWriteChannel 由 DI 在构造时注入,这里再 Resolve 一个给 PlcService 管理连接
|
||||
// 但 SignalDataService 已经拿到了同一个 IPlcClient 瞬态实例(不同实例),所以需要让 SignalDataService 的通道和 PlcService 管理的是同一个
|
||||
// 解决方案:从 SignalDataService 获取其 directWriteChannel 引用
|
||||
var signalDataService = containerProvider.Resolve<ISignalDataService>() as SignalDataService;
|
||||
plcService.RegisterWriteComponents(writeQueue, signalDataService?.DirectWriteChannel);
|
||||
|
||||
// 自动加载信号定义文件 | Auto-load signal definitions
|
||||
try
|
||||
{
|
||||
var xmlPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PlcAddrDfn.xml");
|
||||
if (File.Exists(xmlPath))
|
||||
{
|
||||
plcService.LoadSignalDefinitions(xmlPath);
|
||||
System.Console.WriteLine($"[PLCModule] 信号定义已加载: {xmlPath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Console.WriteLine($"[PLCModule] 警告: PlcAddrDfn.xml 未找到: {xmlPath}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Console.WriteLine($"[PLCModule] 加载信号定义异常: {ex.Message}");
|
||||
}
|
||||
|
||||
// 自动连接 PLC | Auto-connect PLC
|
||||
try
|
||||
{
|
||||
var configLoader = containerProvider.Resolve<ConfigLoader>();
|
||||
var plcConfig = configLoader.LoadPlcConfig();
|
||||
_ = plcService.InitializeAsync(plcConfig);
|
||||
System.Console.WriteLine("[PLCModule] PLC 自动连接已启动");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Console.WriteLine($"[PLCModule] PLC 自动连接异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册类型到依赖注入容器 | Register types to the DI container
|
||||
/// </summary>
|
||||
/// <param name="containerRegistry">容器注册器 | Container registry</param>
|
||||
public void RegisterTypes(IContainerRegistry containerRegistry)
|
||||
{
|
||||
// === IPlcClient 瞬态注册策略说明 | IPlcClient Transient Registration Strategy ===
|
||||
// IPlcClient 注册为瞬态,每次 Resolve 创建独立的 S7PlcClient 实例。
|
||||
// 各单例服务在首次创建时各自获取独立的 IPlcClient 实例:
|
||||
// - PlcService → 主通讯通道,用于周期性批量读取 | Main channel for periodic bulk reads
|
||||
// - PlcWriteQueue → 写入队列通道,用于顺序写入 | Write queue channel for sequential writes
|
||||
// - SignalDataService → 直接写入通道(Direct_Write_Channel),用于高优先级写入+回读校验 | Direct write channel for high-priority write + read-back verify
|
||||
// 三个通道相互独立,避免并发竞争 | Three independent channels to avoid contention
|
||||
containerRegistry.Register<IPlcClient, S7PlcClient>();
|
||||
|
||||
// 注册 PLC 服务为单例(依赖:IPlcClient, ILoggerService, XmlSignalParser)
|
||||
// Register PLC service as singleton (deps: IPlcClient, ILoggerService, XmlSignalParser)
|
||||
containerRegistry.RegisterSingleton<PlcService>();
|
||||
|
||||
// 注册 IPlcService 接口映射到同一个 PlcService 单例,供跨模块使用
|
||||
// Register IPlcService interface mapping to the same PlcService singleton for cross-module usage
|
||||
containerRegistry.Register<IPlcService>(c => c.Resolve<PlcService>());
|
||||
|
||||
// 注册配置加载器(瞬态)| Register configuration loader (transient)
|
||||
containerRegistry.Register<ConfigLoader>();
|
||||
|
||||
// 注册 PLC 测试工具窗口(瞬态)| Register PLC Test Bench Window (transient)
|
||||
containerRegistry.Register<PlcTestBenchWindow>();
|
||||
|
||||
// 注册 XML 信号解析器(瞬态)| Register XML signal parser (transient)
|
||||
containerRegistry.Register<XmlSignalParser>();
|
||||
|
||||
// 注册 PLC 信号地址定义编辑器窗口(瞬态)| Register PLC Address Config Editor Window (transient)
|
||||
containerRegistry.Register<PlcAddrConfigEditorWindow>();
|
||||
|
||||
// 注册 PLC 写入队列为单例(依赖:IPlcClient, ILoggerService)
|
||||
// Register PLC write queue as singleton (deps: IPlcClient, ILoggerService)
|
||||
containerRegistry.RegisterSingleton<PlcWriteQueue>();
|
||||
|
||||
// 注册信号数据交互服务为单例(依赖:PlcService, PlcWriteQueue, IPlcClient, ILoggerService)
|
||||
// Register signal data service as singleton (deps: PlcService, PlcWriteQueue, IPlcClient, ILoggerService)
|
||||
containerRegistry.RegisterSingleton<ISignalDataService, SignalDataService>();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user