Files
XplorePlane/XP.Hardware.RaySource/Documents/GUIDENCE.md
T

21 KiB
Raw Blame History

X 射线源模块使用指南 | X-Ray Source Module Usage Guide

1. 模块概述 | Module Overview

XP.Hardware.RaySource 是 XplorePlane X 射线检测系统的核心硬件控制模块,负责与工业 X 射线源设备进行通讯和控制。该模块采用策略模式设计,通过 Named Pipe IPC 进程隔离架构与 .NET Framework 4.8 Host 子进程通信,支持多种 X 射线源型号的统一管理。

核心特性 | Key Features

  • 支持多种 X 射线源型号(当前支持 Comet 225kV
  • 基于 Named Pipe IPC 的进程隔离架构(.NET 8 ↔ .NET Framework 4.8
  • 完整的设备生命周期管理(初始化、连接变量、暖机、训机、灯丝校准、自动定心、开关射线)
  • 电压电流精确控制(20-225kV / 10-1000μA
  • TXI 开关控制、功率模式切换(Micro Focus / High Power
  • 实时状态监控和错误检测
  • 灯丝寿命管理(使用时长记录、累计统计、预警提醒)
  • 基于 Prism 事件聚合器的松耦合通讯
  • 安全机制:紧急关闭优先级、参数范围验证、双重检查锁定

2. 模块注册 | Module Registration

X 射线源模块已通过 Prism 的模块化系统注册,在应用启动时自动加载。

在 App.xaml.cs 中注册

using Prism.Modularity;
using XP.Hardware.RaySource.Module;

protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
    // 注册 X 射线源模块 | Register X-Ray Source module
    moduleCatalog.AddModule<RaySourceModule>();
    
    base.ConfigureModuleCatalog(moduleCatalog);
}

模块自动注册的服务

服务 类型 生命周期 说明
RaySourceConfig 实例 单例 配置对象(从 App.config 加载)
IRaySourceFactoryRaySourceFactory 接口→实现 单例 射线源工厂
IRaySourceServiceRaySourceService 接口→实现 单例 射线源业务服务
IFilamentLifetimeServiceFilamentLifetimeService 接口→实现 单例 灯丝寿命管理服务

模块初始化行为

模块 OnInitialized 时会自动执行:

  1. 初始化灯丝寿命服务(建表、异常恢复、重算累计寿命)
  2. 检查灯丝寿命预警(≥90% 弹出模态对话框)

3. 配置文件设置 | Configuration File Setup

App.config 中添加 X 射线源配置:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!-- 射线源类型 | Ray Source Type -->
    <add key="RaySource:SourceType" value="Comet225" />
    
    <!-- PVI 通讯参数 | PVI Communication Parameters -->
    <add key="RaySource:PlcIpAddress" value="192.168.12.10" />
    <add key="RaySource:PlcPort" value="11159" />
    <add key="RaySource:StationNumber" value="1" />
    <add key="RaySource:PortNumber" value="11" />
    <add key="RaySource:CpuName" value="cpu" />
    <add key="RaySource:ConnectionTimeout" value="5000" />
    
    <!-- 硬件参数范围 | Hardware Parameter Ranges -->
    <add key="RaySource:MinVoltage" value="20" />
    <add key="RaySource:MaxVoltage" value="225" />
    <add key="RaySource:MinCurrent" value="10" />
    <add key="RaySource:MaxCurrent" value="1000" />
    
    <!-- 操作超时配置 | Operation Timeout Configuration -->
    <add key="RaySource:InitializationTimeout" value="30000" />
    <add key="RaySource:WarmUpTimeout" value="300000" />
    <add key="RaySource:StartUpTimeout" value="180000" />
    <add key="RaySource:AutoCenterTimeout" value="120000" />
    <add key="RaySource:FilamentAdjustTimeout" value="120000" />
    <add key="RaySource:GeneralOperationTimeout" value="10000" />
    
    <!-- 灯丝寿命管理配置 | Filament Lifetime Management Configuration -->
    <add key="RaySource:SerialNumber" value="SN08602861" />
    <add key="RaySource:TotalLifeThreshold" value="1000" />
  </appSettings>
</configuration>

4. 在 ViewModel 中使用 | Usage in ViewModel

4.1 注入服务

using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using XP.Common.Logging.Interfaces;
using XP.Hardware.RaySource.Abstractions;
using XP.Hardware.RaySource.Abstractions.Enums;
using XP.Hardware.RaySource.Abstractions.Events;
using XP.Hardware.RaySource.Config;
using XP.Hardware.RaySource.Services;

namespace YourNamespace.ViewModels
{
    public class YourViewModel : BindableBase
    {
        private readonly IRaySourceService _raySourceService;
        private readonly IEventAggregator _eventAggregator;
        private readonly ILoggerService _logger;

        public YourViewModel(
            IRaySourceService raySourceService,
            IEventAggregator eventAggregator,
            ILoggerService logger)
        {
            _raySourceService = raySourceService;
            _eventAggregator = eventAggregator;
            _logger = logger.ForModule("YourViewModel");
            
            // 订阅事件 | Subscribe to events
            SubscribeEvents();
        }
        
        private void SubscribeEvents()
        {
            _eventAggregator.GetEvent<RaySourceStatusChangedEvent>()
                .Subscribe(OnRaySourceStatusChanged, ThreadOption.UIThread);
            
            _eventAggregator.GetEvent<StatusUpdatedEvent>()
                .Subscribe(OnStatusUpdated, ThreadOption.UIThread);
            
            _eventAggregator.GetEvent<ErrorOccurredEvent>()
                .Subscribe(OnErrorOccurred, ThreadOption.UIThread);
            
            _eventAggregator.GetEvent<OperationResultEvent>()
                .Subscribe(OnOperationResult, ThreadOption.UIThread);
            
            _eventAggregator.GetEvent<VariablesConnectedEvent>()
                .Subscribe(OnVariablesConnected, ThreadOption.UIThread);
        }
        
        private void OnRaySourceStatusChanged(RaySourceStatus newStatus)
        {
            _logger.Info("射线源状态变化: {Status}", newStatus);
        }
        
        private void OnStatusUpdated(SystemStatusData data)
        {
            _logger.Debug("状态更新: 电压={Voltage}kV, 电流={Current}μA", 
                data.ActualVoltage, data.ActualCurrent);
        }
        
        private void OnErrorOccurred(string errorMessage)
        {
            _logger.Error(null, "错误发生: {Error}", errorMessage);
        }
        
        private void OnOperationResult(OperationResultData data)
        {
            _logger.Info("操作 {Op} {Result}: {Msg}", 
                data.OperationName, data.IsSuccess ? "成功" : "失败", data.Message);
        }
        
        private void OnVariablesConnected(bool isConnected)
        {
            _logger.Info("变量连接状态: {Connected}", isConnected);
        }
    }
}

4.2 初始化射线源

// 方式一:分步初始化 | Step-by-step initialization
public void InitializeRaySource()
{
    // 步骤1:初始化(启动 Host 进程,建立 IPC 连接)
    XRayResult result = _raySourceService.Initialize();
    if (!result.Success)
    {
        _logger.Error(null, "初始化失败: {Error}", result.ErrorMessage);
        return;
    }
    
    // 步骤2:连接变量(创建和激活 PVI 变量)
    XRayResult connectResult = _raySourceService.ConnectVariables();
    if (!connectResult.Success)
    {
        _logger.Error(null, "连接变量失败: {Error}", connectResult.ErrorMessage);
    }
}

// 方式二:异步一键初始化 | Async one-step initialization
public async Task AutoInitializeAsync()
{
    XRayResult result = await _raySourceService.InitializeAndConnectAsync();
    if (result.Success)
    {
        _logger.Info("自动初始化完成");
    }
}

4.3 开启/关闭射线

// 开启射线 | Turn on X-ray
public void TurnOnXRay()
{
    if (!_raySourceService.IsInitialized || !_raySourceService.IsConnected)
    {
        _logger.Warn("射线源未就绪");
        return;
    }
    
    XRayResult result = _raySourceService.TurnOn();
    if (result.Success)
    {
        _logger.Info("射线已开启");
    }
}

// 关闭射线 | Turn off X-ray
public void TurnOffXRay()
{
    XRayResult result = _raySourceService.TurnOff();
    if (result.Success)
    {
        _logger.Info("射线已关闭");
    }
}

// 紧急关闭(最高优先级,任何状态下可执行)| Emergency shutdown
public void EmergencyShutdown()
{
    _raySourceService.EmergencyShutdown();
}

// 断开连接(保留实例以便重连)| Disconnect
public void Disconnect()
{
    _raySourceService.Disconnect();
}

5. 电压电流控制 | Voltage and Current Control

// 设置电压(范围由配置文件定义,默认 20-225kV)
XRayResult result = _raySourceService.SetVoltage(100f);

// 设置电流(范围由配置文件定义,默认 10-1000μA)
XRayResult result = _raySourceService.SetCurrent(500f);

// 读取实际电压
XRayResult voltageResult = _raySourceService.ReadVoltage();
if (voltageResult.Success)
{
    float voltage = voltageResult.GetFloat();
}

// 读取实际电流
XRayResult currentResult = _raySourceService.ReadCurrent();
if (currentResult.Success)
{
    float current = currentResult.GetFloat();
}

6. 设备操作 | Device Operations

// TXI 开启/关闭
_raySourceService.TxiOn();
_raySourceService.TxiOff();

// 暖机
_raySourceService.WarmUp();

// 训机
_raySourceService.Training();

// 灯丝校准
_raySourceService.FilamentCalibration();

// 全部电压自动定心
_raySourceService.AutoCenter();

// 设置功率模式(1=Micro Focus2=High Power
_raySourceService.SetPowerMode(1);  // 微焦点模式
_raySourceService.SetPowerMode(2);  // 高功率模式

注意:TXI、暖机、训机、灯丝校准、自动定心、功率模式切换等操作需要射线源已连接变量(IsConnected == true)。


7. 状态监控和错误处理 | Status Monitoring and Error Handling

7.1 读取系统状态

XRayResult result = _raySourceService.ReadSystemStatus();
if (result.Success && result.Data is SystemStatusData statusData)
{
    // statusData 包含全量状态信息:
    // - SetVoltage / ActualVoltage(设定/实际电压)
    // - SetCurrent / ActualCurrent(设定/实际电流)
    // - IsXRayOn(射线开启状态)
    // - WarmUpStatus / VacuumStatus / StartUpStatus(暖机/真空/启动状态)
    // - AutoCenterStatus / FilamentAdjustStatus(自动定心/灯丝调整状态)
    // - IsInterlockActive(连锁状态)
    // - WatchdogStatus / PowerMode / TxiStatus(看门狗/功率模式/TXI状态)
}

7.2 检查和清除错误

// 检查错误
XRayResult errorResult = _raySourceService.CheckErrors();

// 清除错误
XRayResult clearResult = _raySourceService.ClearErrors();

7.3 状态属性

bool isInitialized = _raySourceService.IsInitialized;  // 是否已初始化
bool isConnected = _raySourceService.IsConnected;       // PVI 变量是否已连接
bool isXRayOn = _raySourceService.IsXRayOn;             // 射线是否开启
RaySourceStatus status = _raySourceService.CurrentStatus; // 当前状态(三态)

8. Prism 事件通讯 | Prism Event Communication

模块使用 Prism 事件聚合器实现跨模块通讯,支持以下事件:

8.1 射线源状态变化事件

_eventAggregator.GetEvent<RaySourceStatusChangedEvent>()
    .Subscribe(OnRaySourceStatusChanged, ThreadOption.UIThread);

private void OnRaySourceStatusChanged(RaySourceStatus newStatus)
{
    // newStatus: Unavailable(-1) / Closed(0) / Opened(1)
    switch (newStatus)
    {
        case RaySourceStatus.Unavailable:
            // 射线源不可用(未初始化或连接丢失)
            break;
        case RaySourceStatus.Closed:
            // 射线源已连接,射线关闭
            break;
        case RaySourceStatus.Opened:
            // 射线源已连接,射线开启
            break;
    }
}

8.2 系统状态更新事件

_eventAggregator.GetEvent<StatusUpdatedEvent>()
    .Subscribe(OnStatusUpdated, ThreadOption.UIThread);

private void OnStatusUpdated(SystemStatusData data)
{
    // 全量状态数据,由 Host 进程定期推送
    float actualVoltage = data.ActualVoltage;
    float actualCurrent = data.ActualCurrent;
    bool isXRayOn = data.IsXRayOn;
    string warmUpStatus = data.WarmUpStatus;
    // ... 更多字段见 SystemStatusData 定义
}

8.3 错误事件

_eventAggregator.GetEvent<ErrorOccurredEvent>()
    .Subscribe(OnErrorOccurred, ThreadOption.UIThread);

private void OnErrorOccurred(string errorMessage)
{
    _logger.Error(null, "射线源错误: {Error}", errorMessage);
}

8.4 操作结果事件

_eventAggregator.GetEvent<OperationResultEvent>()
    .Subscribe(OnOperationResult, ThreadOption.UIThread);

private void OnOperationResult(OperationResultData data)
{
    // data.OperationName - 操作名称
    // data.IsSuccess - 是否成功
    // data.Message - 结果消息
}

8.5 PVI 变量连接状态事件

_eventAggregator.GetEvent<VariablesConnectedEvent>()
    .Subscribe(OnVariablesConnected, ThreadOption.UIThread);

private void OnVariablesConnected(bool isConnected)
{
    // true = PVI 变量已连接,射线源准备就绪
    // false = PVI 变量已断开
}

9. 灯丝寿命管理 | Filament Lifetime Management

9.1 自动联动

灯丝寿命管理与射线源开关自动联动:

  • 射线源开启(TurnOn)→ 自动开始记录灯丝使用时长
  • 射线源关闭(TurnOff / Disconnect / EmergencyShutdown)→ 自动停止记录并累加统计
  • 异常断联 → 下次初始化时自动恢复未关闭的记录

9.2 手动查询

// 获取实时累计使用秒数(含当前运行时长)
double totalSeconds = _filamentLifetimeService.GetCurrentTotalLifeSeconds();

// 获取寿命百分比(0-100
double percentage = _filamentLifetimeService.GetLifetimePercentage();

// 获取阈值秒数
double thresholdSeconds = _filamentLifetimeService.GetThresholdSeconds();

// 检查是否需要预警(≥90%
bool shouldWarn = _filamentLifetimeService.ShouldShowLifetimeWarning();

9.3 数据持久化

灯丝寿命数据通过 SQLite 持久化,包含两张表:

  • RaySourceFilamentLifetimeStatistics:累计统计表(按序列号唯一)
  • RaySourceFilamentUsageLogs:使用流水表(每次开关记录一条)

10. 在应用退出时释放资源 | Release Resources on Application Exit

protected override void OnExit(ExitEventArgs e)
{
    Log.Information("XplorePlane 主应用退出");

    // 释放射线源资源 | Release X-ray source resources
    try
    {
        var raySourceService = Container.Resolve<IRaySourceService>();
        raySourceService?.Dispose();
        Log.Information("射线源资源已成功释放");
    }
    catch (Exception ex)
    {
        Log.Error(ex, "射线源资源释放失败,忽略该错误继续退出");
    }

    Log.CloseAndFlush();
    base.OnExit(e);
}

11. 安全机制 | Safety Mechanisms

11.1 参数范围验证

// 服务层自动校验参数范围,超出范围返回错误结果
XRayResult result = _raySourceService.SetVoltage(300f); // 超出 225kV 上限
// result.Success == false
// result.ErrorMessage == "电压参数超出范围:20-225kV"

11.2 紧急关闭优先级

紧急关闭具有最高优先级,可以在任何状态下执行:

// 紧急关闭:依次关闭射线 → 完全关闭设备 → 状态重置为 Unavailable
_raySourceService.EmergencyShutdown();

11.3 业务规则校验

  • 未初始化禁止操作(所有操作前检查 IsInitialized
  • 防重复开启/关闭(双重检查锁定模式)
  • 异常断联自动检测(状态变为 Unavailable 时重置标志位)

11.4 实时调节支持

连接射线源后,无论射线是否开启,都可以实时调节电压和电流。


12. 异常处理 | Exception Handling

12.1 XRayResult 结果处理

所有操作返回 XRayResult 对象:

XRayResult result = _raySourceService.TurnOn();

if (result.Success)
{
    var data = result.Data;       // 获取返回数据
}
else
{
    string error = result.ErrorMessage; // 获取错误消息
    _logger.Error(null, "操作失败: {Error}", error);
}

12.2 IPC 通信异常

当 Host 进程崩溃或管道断开时:

  • CometIpcClient 设置 _isPipeConnected = false,阻止后续命令发送
  • 返回 null 响应,服务层转换为错误结果
  • 推送 Disconnected 状态,触发 UI 更新

13. 日志记录 | Logging

模块使用 ILoggerService 进行结构化日志记录:

// 各层日志模块名称
_logger = logger.ForModule("RaySource.Service");    // 服务层
_logger = logger.ForModule("RaySource.Factory");    // 工厂层
_logger = logger.ForModule<Comet225RaySource>();     // 适配器层
_logger = logger.ForModule<CometIpcClient>();        // IPC 客户端
_logger = logger.ForModule<CometHostManager>();      // Host 管理器
_logger = logger.ForModule("RaySource.ViewModel");   // 操作视图模型
_logger = logger.ForModule("RaySource.ConfigVM");    // 配置视图模型
_logger = logger.ForModule<FilamentLifetimeService>(); // 灯丝寿命服务

日志级别

  • Debug: 详细调试信息(IPC 消息收发、电压电流读取等)
  • Info: 一般信息(初始化成功、射线开启、状态变更等)
  • Warn: 警告信息(参数超出范围、重复操作、异常恢复等)
  • Error: 错误信息(操作失败、通讯异常、IPC 超时等)
  • Fatal: 致命错误(系统崩溃等)

14. 故障排查 | Troubleshooting

14.1 初始化失败

可能原因:

  • Host 可执行文件未找到(检查 {主程序目录}/Host/XP.Hardware.RaySource.Comet.Host.exe
  • PLC IP 地址或端口配置错误
  • PLC 未启动或网络不通
  • Named Pipe 连接超时
  • 残留的 Host 进程未清理

解决方案:

  1. 确认 Host 可执行文件和 BR.AN.PviServices.dll 已正确部署
  2. 检查 App.config 中的 PLC 连接参数
  3. 使用 ping 命令测试 PLC 网络连接
  4. 查看日志中 Host 进程 PID 和管道连接状态
  5. 手动终止残留的 XP.Hardware.RaySource.Comet.Host.exe 进程

14.2 射线无法开启

可能原因:

  • 射线源未初始化或变量未连接
  • 设备处于错误状态
  • 互锁信号未满足

解决方案:

  1. 确认 IsInitialized == trueIsConnected == true
  2. 调用 CheckErrors() 检查错误状态
  3. 检查设备互锁信号

14.3 电压电流设置失败

可能原因:

  • 参数超出配置范围
  • 射线源未初始化
  • IPC 管道已断开

解决方案:

  1. 验证参数在有效范围内
  2. 检查 IsInitialized 状态
  3. 查看日志中 IPC 通信状态

14.4 Host 进程异常退出

可能原因:

  • BR.AN.PviServices.dll 缺失或版本不匹配
  • PVI Service 未正确安装
  • Host 进程内存异常

解决方案:

  1. 检查 Host 目录下 DLL 文件完整性
  2. 确认 B&R Automation Studio 和 PVI Services 已安装
  3. 查看 Host 进程 stderr 日志输出

14.5 灯丝寿命数据异常

可能原因:

  • SerialNumber 配置为空
  • SQLite 数据库文件损坏
  • 异常断电导致未关闭记录

解决方案:

  1. 确认 App.configRaySource:SerialNumber 已配置
  2. 检查数据库文件完整性
  3. 服务初始化时会自动恢复未关闭记录(标记为异常中断,DurationSeconds=0

15. 注意事项 | Notes

  1. 线程安全: IRaySourceService 是单例,内部使用 lock 保护关键操作
  2. 同步 API: 所有 IXRaySourceIRaySourceService 方法为同步方法,ViewModel 中通过 Task.Run 包装避免阻塞 UI
  3. InitializeAndConnectAsync: 唯一的异步便捷方法,内部通过 Task.Run 包装同步调用
  4. 实时调节: 连接后可随时调节电压电流,无论射线是否开启
  5. 资源释放: 应用退出时务必调用 Dispose() 释放资源(会触发紧急关闭和 Host 进程终止)
  6. 事件订阅: 记得在 ViewModel 销毁时取消事件订阅
  7. 配置验证: 启动前自动验证配置参数的有效性
  8. 日志记录: 所有关键操作都有详细的结构化日志记录
  9. 错误处理: 始终检查 XRayResult.Success 并处理错误
  10. Host 进程: CometHostManager 会自动清理残留进程并管理 Host 生命周期

16. 文档索引 | Documentation Index


最后更新 | Last Updated: 2026-03-26