997 lines
43 KiB
C#
997 lines
43 KiB
C#
using Prism.Events;
|
||
using System;
|
||
using System.Threading.Tasks;
|
||
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;
|
||
|
||
namespace XP.Hardware.RaySource.Services
|
||
{
|
||
/// <summary>
|
||
/// 射线源业务服务实现类 | X-Ray Source Business Service Implementation
|
||
/// 单例模式,调度工厂+业务规则校验+事件驱动 | Singleton pattern, factory dispatch + business rule validation + event-driven
|
||
/// </summary>
|
||
public class RaySourceService : IRaySourceService
|
||
{
|
||
private readonly IRaySourceFactory _factory;
|
||
private readonly RaySourceConfig _config;
|
||
private readonly IEventAggregator _eventAggregator;
|
||
private readonly ILoggerService _logger;
|
||
private readonly IFilamentLifetimeService _filamentLifetimeService;
|
||
private IXRaySource _currentSource;
|
||
private bool _isDisposed = false;
|
||
private readonly object _lockObj = new object();
|
||
|
||
/// <summary>
|
||
/// 上一次灯丝记录对应的射线状态(用于去重,防止设备推送抖动)| Last filament recording status (for dedup, prevents device push jitter)
|
||
/// </summary>
|
||
private RaySourceStatus? _lastFilamentRecordedStatus;
|
||
|
||
/// <summary>
|
||
/// 当前射线源实例 | Current X-ray source instance
|
||
/// </summary>
|
||
public IXRaySource CurrentSource => _currentSource;
|
||
|
||
/// <summary>
|
||
/// 是否已初始化(且连接正常)| Is initialized (and connected)
|
||
/// </summary>
|
||
public bool IsInitialized => _isInitializedFlag && _currentSource != null;
|
||
|
||
private bool _isInitializedFlag = false;
|
||
|
||
/// <summary>
|
||
/// 是否射线开启(由 CurrentStatus 派生,Opened 即为 true)| Is X-ray on (derived from CurrentStatus, true when Opened)
|
||
/// </summary>
|
||
public bool IsXRayOn => CurrentStatus == RaySourceStatus.Opened;
|
||
|
||
/// <summary>
|
||
/// 射线源是否已建立完整连接(由设备层 RaySourceConnected 推送确认)| Whether RaySource has established full connection (confirmed by device RaySourceConnected push)
|
||
/// </summary>
|
||
public bool IsConnected => _currentSource?.IsConnected ?? false;
|
||
|
||
/// <summary>
|
||
/// 当前射线源状态 | Current X-ray source status
|
||
/// </summary>
|
||
public RaySourceStatus CurrentStatus { get; private set; } = RaySourceStatus.Unavailable;
|
||
|
||
/// <summary>
|
||
/// 构造函数 | Constructor
|
||
/// </summary>
|
||
public RaySourceService(
|
||
IRaySourceFactory factory,
|
||
RaySourceConfig config,
|
||
IEventAggregator eventAggregator,
|
||
ILoggerService logger,
|
||
IFilamentLifetimeService filamentLifetimeService)
|
||
{
|
||
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
|
||
_config = config ?? throw new ArgumentNullException(nameof(config));
|
||
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
|
||
_logger = (logger ?? throw new ArgumentNullException(nameof(logger))).ForModule("RaySource.Service");
|
||
_filamentLifetimeService = filamentLifetimeService ?? throw new ArgumentNullException(nameof(filamentLifetimeService));
|
||
|
||
_logger.Info("射线源服务已创建 | RaySource service created");
|
||
|
||
// 订阅射线源状态变更事件(处理状态同步和异常断联)| Subscribe to ray source status changed event
|
||
_eventAggregator.GetEvent<RaySourceStatusChangedEvent>().Subscribe(OnRaySourceStatusChangedFromDevice);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化射线源(射线源类型从配置文件读取)| Initialize X-ray source (source type read from configuration)
|
||
/// </summary>
|
||
public XRayResult Initialize()
|
||
{
|
||
var sourceType = _config.SourceType;
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始初始化射线源,类型: {SourceType} | Starting X-ray source initialization, type: {SourceType}", sourceType);
|
||
|
||
if (IsInitialized)
|
||
{
|
||
_logger.Warn("射线源已初始化,请勿重复初始化 | X-ray source already initialized");
|
||
return XRayResult.Error("射线源已初始化,请勿重复初始化");
|
||
}
|
||
|
||
// 验证配置 | Validate configuration
|
||
_logger.Debug("验证配置参数 | Validating configuration parameters");
|
||
var (isValid, errorMessage) = _config.Validate();
|
||
if (!isValid)
|
||
{
|
||
_logger.Error(null, "配置验证失败: {ErrorMessage} | Configuration validation failed: {ErrorMessage}", errorMessage);
|
||
return XRayResult.Error($"配置验证失败: {errorMessage}");
|
||
}
|
||
|
||
// 复用已有实例或创建新实例 | Reuse existing instance or create new one
|
||
if (_currentSource == null)
|
||
{
|
||
_logger.Debug("创建射线源实例: {SourceType} | Creating X-ray source instance: {SourceType}", sourceType);
|
||
_currentSource = _factory.CreateRaySource(sourceType);
|
||
if (_currentSource == null)
|
||
{
|
||
_logger.Error(null, "创建射线源实例失败: {SourceType} | Failed to create X-ray source instance: {SourceType}", sourceType);
|
||
return XRayResult.Error($"创建射线源实例失败: {sourceType}");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_logger.Debug("复用已有射线源实例 | Reusing existing X-ray source instance");
|
||
}
|
||
|
||
// 初始化射线源 | Initialize X-ray source
|
||
_logger.Info("调用射线源初始化方法 | Calling X-ray source initialization method");
|
||
var result = _currentSource.Initialize();
|
||
if (result.Success)
|
||
{
|
||
_isInitializedFlag = true;
|
||
_logger.Info("射线源初始化成功: {SourceType} | X-ray source initialized successfully: {SourceType}", sourceType);
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "射线源初始化失败: {ErrorMessage} | X-ray source initialization failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var errorMsg = $"初始化异常: {ex.Message}";
|
||
_logger.Error(ex, "射线源初始化异常: {Message} | X-ray source initialization exception: {Message}", ex.Message);
|
||
_eventAggregator.GetEvent<ErrorOccurredEvent>().Publish(errorMsg);
|
||
return XRayResult.Error(errorMsg);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 连接 PVI 变量并启动实时状态通讯 | Connect PVI variables and start real-time status communication
|
||
/// 必须在 Initialize 成功后、TurnOn 之前调用 | Must be called after Initialize succeeds and before TurnOn
|
||
/// </summary>
|
||
public XRayResult ConnectVariables()
|
||
{
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法连接变量 | X-ray source not initialized, cannot connect variables");
|
||
return XRayResult.Error("射线源未初始化,无法连接变量");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始连接 PVI 变量 | Starting PVI variable connection");
|
||
var result = _currentSource.ConnectVariables();
|
||
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("PVI 变量连接命令已发送,等待设备层确认 | PVI variable connection command sent, waiting for device confirmation");
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "PVI 变量连接失败: {ErrorMessage} | PVI variable connection failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var errorMsg = $"连接变量异常: {ex.Message}";
|
||
_logger.Error(ex, "连接变量异常: {Message} | Connect variables exception: {Message}", ex.Message);
|
||
_eventAggregator.GetEvent<ErrorOccurredEvent>().Publish(errorMsg);
|
||
return XRayResult.Error(errorMsg);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 开启射线 | Turn on X-ray
|
||
/// </summary>
|
||
public XRayResult TurnOn()
|
||
{
|
||
// 业务规则校验:未初始化禁止操作 | Business rule: operation forbidden if not initialized
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法开启射线 | X-ray source not initialized, cannot turn on");
|
||
return XRayResult.Error("射线源未初始化,无法开启射线");
|
||
}
|
||
|
||
// 快速检查:已开启则直接返回,避免不必要的锁竞争 | Quick check: return early if already opened
|
||
if (CurrentStatus == RaySourceStatus.Opened)
|
||
{
|
||
_logger.Warn("射线已处于开启状态,忽略重复请求 | X-ray already opened, ignoring duplicate request");
|
||
return XRayResult.Ok("射线已开启");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
// 获取锁后再次检查状态,防止重复开启 | Double-check status after acquiring lock
|
||
if (CurrentStatus == RaySourceStatus.Opened)
|
||
{
|
||
_logger.Warn("射线已处于开启状态,忽略重复请求 | X-ray already opened, ignoring duplicate request");
|
||
return XRayResult.Ok("射线已开启");
|
||
}
|
||
|
||
_logger.Info("开始开启射线 | Starting to turn on X-ray");
|
||
var result = _currentSource.TurnOn();
|
||
|
||
if (result.Success)
|
||
{
|
||
CurrentStatus = RaySourceStatus.Opened;
|
||
_logger.Info("射线开启成功,状态更新为 Opened | X-ray turned on successfully, status updated to Opened");
|
||
_eventAggregator.GetEvent<RaySourceStatusChangedEvent>().Publish(CurrentStatus);
|
||
// 灯丝记录由 OnRaySourceStatusChangedFromDevice 统一处理,避免重复调用
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "射线开启失败: {ErrorMessage} | X-ray turn on failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "开启射线异常: {Message} | Exception turning on X-ray: {Message}", ex.Message);
|
||
throw;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭射线 | Turn off X-ray
|
||
/// </summary>
|
||
public XRayResult TurnOff()
|
||
{
|
||
// 业务规则校验:未初始化禁止操作 | Business rule: operation forbidden if not initialized
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法关闭射线 | X-ray source not initialized, cannot turn off");
|
||
return XRayResult.Error("射线源未初始化,无法关闭射线");
|
||
}
|
||
|
||
// 快速检查:已关闭则直接返回,避免不必要的锁竞争 | Quick check: return early if already closed
|
||
if (CurrentStatus == RaySourceStatus.Closed)
|
||
{
|
||
_logger.Warn("射线已处于关闭状态,忽略重复请求 | X-ray already closed, ignoring duplicate request");
|
||
return XRayResult.Ok("射线已关闭");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
// 获取锁后再次检查状态,防止重复关闭 | Double-check status after acquiring lock
|
||
if (CurrentStatus == RaySourceStatus.Closed)
|
||
{
|
||
_logger.Warn("射线已处于关闭状态,忽略重复请求 | X-ray already closed, ignoring duplicate request");
|
||
return XRayResult.Ok("射线已关闭");
|
||
}
|
||
|
||
_logger.Info("开始关闭射线 | Starting to turn off X-ray");
|
||
var result = _currentSource.TurnOff();
|
||
|
||
if (result.Success)
|
||
{
|
||
CurrentStatus = RaySourceStatus.Closed;
|
||
_logger.Info("射线关闭成功,状态更新为 Closed | X-ray turned off successfully, status updated to Closed");
|
||
_eventAggregator.GetEvent<RaySourceStatusChangedEvent>().Publish(CurrentStatus);
|
||
// 灯丝记录由 OnRaySourceStatusChangedFromDevice 统一处理,避免重复调用
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "射线关闭失败: {ErrorMessage} | X-ray turn off failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "关闭射线异常: {Message} | Exception turning off X-ray: {Message}", ex.Message);
|
||
throw;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 断开射线源连接(保留实例以便重连)| Disconnect X-ray source (retain instance for reconnection)
|
||
/// </summary>
|
||
public XRayResult Disconnect()
|
||
{
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始断开射线源连接 | Starting X-ray source disconnection");
|
||
|
||
if (_currentSource == null)
|
||
{
|
||
_logger.Warn("射线源实例不存在,无需断开 | X-ray source instance does not exist, no need to disconnect");
|
||
_isInitializedFlag = false;
|
||
CurrentStatus = RaySourceStatus.Unavailable;
|
||
_eventAggregator.GetEvent<RaySourceStatusChangedEvent>().Publish(CurrentStatus);
|
||
return XRayResult.Ok("射线源已断开");
|
||
}
|
||
|
||
// 同步调用 CloseOff 进行优雅关闭 | Call CloseOff for graceful shutdown
|
||
try
|
||
{
|
||
var closeResult = _currentSource.CloseOff();
|
||
if (!closeResult.Success)
|
||
{
|
||
_logger.Warn("优雅关闭返回失败: {ErrorMessage} | Graceful shutdown returned failure: {ErrorMessage}", closeResult.ErrorMessage);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Warn("优雅关闭异常: {Message} | Graceful shutdown exception: {Message}", ex.Message);
|
||
}
|
||
|
||
// 不 Dispose 实例,保留 PVI Service 以便重连 | Don't dispose instance, retain PVI Service for reconnection
|
||
_isInitializedFlag = false;
|
||
CurrentStatus = RaySourceStatus.Unavailable;
|
||
|
||
// 断开连接时停止灯丝使用记录 | Stop filament usage recording on disconnect
|
||
if (_filamentLifetimeService.IsInitialized && _filamentLifetimeService.IsFilamentOn)
|
||
{
|
||
_filamentLifetimeService.StopFilamentUsage();
|
||
_lastFilamentRecordedStatus = RaySourceStatus.Unavailable;
|
||
}
|
||
|
||
_logger.Info("射线源连接已断开,状态更新为 Unavailable | X-ray source disconnected, status updated to Unavailable");
|
||
_eventAggregator.GetEvent<RaySourceStatusChangedEvent>().Publish(CurrentStatus);
|
||
return XRayResult.Ok();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var errorMsg = $"断开连接异常: {ex.Message}";
|
||
_logger.Error(ex, "射线源断开连接异常: {Message} | X-ray source disconnection exception: {Message}", ex.Message);
|
||
_eventAggregator.GetEvent<ErrorOccurredEvent>().Publish(errorMsg);
|
||
return XRayResult.Error(errorMsg);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 紧急关闭(最高优先级,强制中断所有操作)| Emergency shutdown (highest priority, force interrupt all operations)
|
||
/// </summary>
|
||
public XRayResult EmergencyShutdown()
|
||
{
|
||
try
|
||
{
|
||
_logger.Warn("执行紧急关闭程序 | Executing emergency shutdown");
|
||
|
||
if (_currentSource != null)
|
||
{
|
||
// 先关闭射线 | Turn off X-ray first
|
||
_logger.Info("紧急关闭:关闭射线 | Emergency shutdown: turning off X-ray");
|
||
_currentSource.TurnOff();
|
||
|
||
// 完全关闭设备 | Fully shut down device
|
||
_logger.Info("紧急关闭:完全关闭设备 | Emergency shutdown: fully shutting down device");
|
||
_currentSource.CloseOff();
|
||
}
|
||
|
||
_isInitializedFlag = false;
|
||
CurrentStatus = RaySourceStatus.Unavailable;
|
||
|
||
// 紧急关闭时停止灯丝使用记录 | Stop filament usage recording on emergency shutdown
|
||
if (_filamentLifetimeService.IsInitialized && _filamentLifetimeService.IsFilamentOn)
|
||
{
|
||
_filamentLifetimeService.StopFilamentUsage();
|
||
_lastFilamentRecordedStatus = RaySourceStatus.Unavailable;
|
||
}
|
||
|
||
_logger.Info("紧急关闭完成,状态更新为 Unavailable | Emergency shutdown completed, status updated to Unavailable");
|
||
_eventAggregator.GetEvent<RaySourceStatusChangedEvent>().Publish(CurrentStatus);
|
||
_eventAggregator.GetEvent<OperationResultEvent>()
|
||
.Publish(new OperationResultData("紧急关闭", true, "紧急关闭完成"));
|
||
|
||
return XRayResult.Ok("紧急关闭完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var errorMsg = $"紧急关闭异常: {ex.Message}";
|
||
_logger.Error(ex, "紧急关闭异常: {Message} | Emergency shutdown exception: {Message}", ex.Message);
|
||
_eventAggregator.GetEvent<ErrorOccurredEvent>().Publish(errorMsg);
|
||
return XRayResult.Error(errorMsg);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置电压 | Set voltage
|
||
/// </summary>
|
||
public XRayResult SetVoltage(float voltage)
|
||
{
|
||
// 业务规则校验:未初始化禁止操作 | Business rule: operation forbidden if not initialized
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法设置电压 | X-ray source not initialized, cannot set voltage");
|
||
return XRayResult.Error("射线源未初始化,无法设置电压");
|
||
}
|
||
|
||
// 参数范围校验 | Parameter range validation
|
||
if (voltage < _config.MinVoltage || voltage > _config.MaxVoltage)
|
||
{
|
||
_logger.Warn("电压参数超出范围: {Voltage}kV,有效范围: {Min}-{Max}kV | Voltage out of range: {Voltage}kV, valid range: {Min}-{Max}kV", voltage, _config.MinVoltage, _config.MaxVoltage);
|
||
return XRayResult.Error($"电压参数超出范围:{_config.MinVoltage}-{_config.MaxVoltage}kV");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("设置电压: {Voltage}kV | Setting voltage: {Voltage}kV", voltage);
|
||
var result = _currentSource.SetVoltage(voltage);
|
||
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("电压设置成功: {Voltage}kV | Voltage set successfully: {Voltage}kV", voltage);
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "电压设置失败: {ErrorMessage} | Voltage setting failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "设置电压异常: {Message} | Exception setting voltage: {Message}", ex.Message);
|
||
throw;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置电流 | Set current
|
||
/// </summary>
|
||
public XRayResult SetCurrent(float current)
|
||
{
|
||
// 业务规则校验:未初始化禁止操作 | Business rule: operation forbidden if not initialized
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法设置电流 | X-ray source not initialized, cannot set current");
|
||
return XRayResult.Error("射线源未初始化,无法设置电流");
|
||
}
|
||
|
||
// 参数范围校验 | Parameter range validation
|
||
if (current < _config.MinCurrent || current > _config.MaxCurrent)
|
||
{
|
||
_logger.Warn("电流参数超出范围: {Current}μA,有效范围: {Min}-{Max}μA | Current out of range: {Current}μA, valid range: {Min}-{Max}μA", current, _config.MinCurrent, _config.MaxCurrent);
|
||
return XRayResult.Error($"电流参数超出范围:{_config.MinCurrent}-{_config.MaxCurrent}μA");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("设置电流: {Current}μA | Setting current: {Current}μA", current);
|
||
var result = _currentSource.SetCurrent(current);
|
||
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("电流设置成功: {Current}μA | Current set successfully: {Current}μA", current);
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "电流设置失败: {ErrorMessage} | Current setting failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "设置电流异常: {Message} | Exception setting current: {Message}", ex.Message);
|
||
throw;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取实际电压 | Read actual voltage
|
||
/// </summary>
|
||
public XRayResult ReadVoltage()
|
||
{
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法读取电压 | X-ray source not initialized, cannot read voltage");
|
||
return XRayResult.Error("射线源未初始化");
|
||
}
|
||
|
||
try
|
||
{
|
||
_logger.Debug("读取实际电压 | Reading actual voltage");
|
||
var result = _currentSource.ReadVoltage();
|
||
|
||
if (result.Success)
|
||
{
|
||
_logger.Debug("电压读取成功: {Data}kV | Voltage read successfully: {Data}kV", result.Data);
|
||
}
|
||
else
|
||
{
|
||
_logger.Warn("电压读取失败: {ErrorMessage} | Voltage reading failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "读取电压异常: {Message} | Exception reading voltage: {Message}", ex.Message);
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取实际电流 | Read actual current
|
||
/// </summary>
|
||
public XRayResult ReadCurrent()
|
||
{
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法读取电流 | X-ray source not initialized, cannot read current");
|
||
return XRayResult.Error("射线源未初始化");
|
||
}
|
||
|
||
try
|
||
{
|
||
_logger.Debug("读取实际电流 | Reading actual current");
|
||
var result = _currentSource.ReadCurrent();
|
||
|
||
if (result.Success)
|
||
{
|
||
_logger.Debug("电流读取成功: {Data}μA | Current read successfully: {Data}μA", result.Data);
|
||
}
|
||
else
|
||
{
|
||
_logger.Warn("电流读取失败: {ErrorMessage} | Current reading failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "读取电流异常: {Message} | Exception reading current: {Message}", ex.Message);
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取系统状态 | Read system status
|
||
/// </summary>
|
||
public XRayResult ReadSystemStatus()
|
||
{
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法读取系统状态 | X-ray source not initialized, cannot read system status");
|
||
return XRayResult.Error("射线源未初始化");
|
||
}
|
||
|
||
try
|
||
{
|
||
_logger.Debug("读取系统状态 | Reading system status");
|
||
return _currentSource.ReadSystemStatus();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "读取系统状态异常: {Message} | Exception reading system status: {Message}", ex.Message);
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查错误 | Check errors
|
||
/// </summary>
|
||
public XRayResult CheckErrors()
|
||
{
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法检查错误 | X-ray source not initialized, cannot check errors");
|
||
return XRayResult.Error("射线源未初始化");
|
||
}
|
||
|
||
try
|
||
{
|
||
_logger.Debug("检查错误状态 | Checking error status");
|
||
return _currentSource.CheckErrors();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "检查错误异常: {Message} | Exception checking errors: {Message}", ex.Message);
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清除错误 | Clear errors
|
||
/// </summary>
|
||
public XRayResult ClearErrors()
|
||
{
|
||
if (!IsInitialized || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未初始化,无法清除错误 | X-ray source not initialized, cannot clear errors");
|
||
return XRayResult.Error("射线源未初始化");
|
||
}
|
||
|
||
try
|
||
{
|
||
_logger.Info("开始清除错误 | Starting to clear errors");
|
||
|
||
_eventAggregator.GetEvent<OperationResultEvent>()
|
||
.Publish(new OperationResultData("清除错误", true));
|
||
|
||
_logger.Info("错误清除完成 | Errors cleared successfully");
|
||
return XRayResult.Ok("错误已清除");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var errorMsg = $"清除错误失败: {ex.Message}";
|
||
_logger.Error(ex, "清除错误异常: {Message} | Exception clearing errors: {Message}", ex.Message);
|
||
_eventAggregator.GetEvent<ErrorOccurredEvent>().Publish(errorMsg);
|
||
return XRayResult.Error(errorMsg);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// TXI 开启 | TXI On
|
||
/// </summary>
|
||
public XRayResult TxiOn()
|
||
{
|
||
if (!IsConnected || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未连接,无法执行 TXI ON | X-ray source not connected, cannot execute TXI ON");
|
||
return XRayResult.Error("射线源未连接");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始执行 TXI ON | Starting TXI ON");
|
||
var result = _currentSource.TxiOn();
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("TXI ON 执行成功 | TXI ON executed successfully");
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "TXI ON 执行失败: {ErrorMessage} | TXI ON failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "TXI ON 异常: {Message} | TXI ON exception: {Message}", ex.Message);
|
||
return XRayResult.Error($"TXI ON 异常:{ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// TXI 关闭 | TXI Off
|
||
/// </summary>
|
||
public XRayResult TxiOff()
|
||
{
|
||
if (!IsConnected || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未连接,无法执行 TXI OFF | X-ray source not connected, cannot execute TXI OFF");
|
||
return XRayResult.Error("射线源未连接");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始执行 TXI OFF | Starting TXI OFF");
|
||
var result = _currentSource.TxiOff();
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("TXI OFF 执行成功 | TXI OFF executed successfully");
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "TXI OFF 执行失败: {ErrorMessage} | TXI OFF failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "TXI OFF 异常: {Message} | TXI OFF exception: {Message}", ex.Message);
|
||
return XRayResult.Error($"TXI OFF 异常:{ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 暖机设置 | Warm-up setting
|
||
/// </summary>
|
||
public XRayResult WarmUp()
|
||
{
|
||
if (!IsConnected || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未连接,无法执行暖机 | X-ray source not connected, cannot execute warm-up");
|
||
return XRayResult.Error("射线源未连接");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始执行暖机设置 | Starting warm-up setting");
|
||
var result = _currentSource.WarmUp();
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("暖机设置已发送 | Warm-up setting sent successfully");
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "暖机设置失败: {ErrorMessage} | Warm-up setting failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "暖机设置异常: {Message} | Warm-up setting exception: {Message}", ex.Message);
|
||
return XRayResult.Error($"暖机设置异常:{ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 训机设置 | Training setting
|
||
/// </summary>
|
||
public XRayResult Training()
|
||
{
|
||
if (!IsConnected || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未连接,无法执行训机 | X-ray source not connected, cannot execute training");
|
||
return XRayResult.Error("射线源未连接");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始执行训机设置 | Starting training setting");
|
||
var result = _currentSource.Training();
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("训机设置已发送 | Training setting sent successfully");
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "训机设置失败: {ErrorMessage} | Training setting failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "训机设置异常: {Message} | Training setting exception: {Message}", ex.Message);
|
||
return XRayResult.Error($"训机设置异常:{ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 灯丝校准 | Filament calibration
|
||
/// </summary>
|
||
public XRayResult FilamentCalibration()
|
||
{
|
||
if (!IsConnected || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未连接,无法执行灯丝校准 | X-ray source not connected, cannot execute filament calibration");
|
||
return XRayResult.Error("射线源未连接");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始执行灯丝校准 | Starting filament calibration");
|
||
var result = _currentSource.FilamentCalibration();
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("灯丝校准已发送 | Filament calibration sent successfully");
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "灯丝校准失败: {ErrorMessage} | Filament calibration failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "灯丝校准异常: {Message} | Filament calibration exception: {Message}", ex.Message);
|
||
return XRayResult.Error($"灯丝校准异常:{ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 全部电压自动定心 | Auto-center all voltages
|
||
/// </summary>
|
||
public XRayResult AutoCenter()
|
||
{
|
||
if (!IsConnected || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未连接,无法执行自动定心 | X-ray source not connected, cannot execute auto-center");
|
||
return XRayResult.Error("射线源未连接");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始执行全部电压自动定心 | Starting auto-center all voltages");
|
||
var result = _currentSource.AutoCenter();
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("自动定心已发送 | Auto-center sent successfully");
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "自动定心失败: {ErrorMessage} | Auto-center failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "自动定心异常: {Message} | Auto-center exception: {Message}", ex.Message);
|
||
return XRayResult.Error($"自动定心异常:{ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置功率模式 | Set power mode
|
||
/// </summary>
|
||
/// <param name="mode">功率模式值:1=Micro Focus,2=High Power</param>
|
||
public XRayResult SetPowerMode(int mode)
|
||
{
|
||
if (!IsConnected || _currentSource == null)
|
||
{
|
||
_logger.Warn("射线源未连接,无法设置功率模式 | X-ray source not connected, cannot set power mode");
|
||
return XRayResult.Error("射线源未连接");
|
||
}
|
||
|
||
lock (_lockObj)
|
||
{
|
||
try
|
||
{
|
||
_logger.Info("开始设置功率模式: Mode={Mode} | Starting to set power mode: Mode={Mode}", mode);
|
||
var result = _currentSource.SetPowerMode(mode);
|
||
if (result.Success)
|
||
{
|
||
_logger.Info("功率模式设置成功: Mode={Mode} | Power mode set successfully: Mode={Mode}", mode);
|
||
}
|
||
else
|
||
{
|
||
_logger.Error(null, "功率模式设置失败: {ErrorMessage} | Power mode setting failed: {ErrorMessage}", result.ErrorMessage);
|
||
}
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "功率模式设置异常: {Message} | Power mode setting exception: {Message}", ex.Message);
|
||
return XRayResult.Error($"功率模式设置异常:{ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步执行初始化 + 连接变量的完整流程 | Async full sequence: Initialize + ConnectVariables
|
||
/// </summary>
|
||
public async Task<XRayResult> InitializeAndConnectAsync()
|
||
{
|
||
return await Task.Run(() =>
|
||
{
|
||
try
|
||
{
|
||
// 步骤1:初始化 | Step 1: Initialize
|
||
if (!IsInitialized)
|
||
{
|
||
_logger.Info("自动初始化:执行 Initialize | Auto-init: executing Initialize");
|
||
var initResult = Initialize();
|
||
if (!initResult.Success)
|
||
{
|
||
_logger.Warn("自动初始化失败: {Error} | Auto-initialization failed: {Error}", initResult.ErrorMessage);
|
||
return initResult;
|
||
}
|
||
_logger.Info("自动初始化成功 | Auto-initialization succeeded");
|
||
}
|
||
|
||
// 步骤2:连接变量 | Step 2: Connect Variables
|
||
if (!IsConnected)
|
||
{
|
||
_logger.Info("自动连接变量:执行 ConnectVariables | Auto-init: executing ConnectVariables");
|
||
var connectResult = ConnectVariables();
|
||
if (!connectResult.Success)
|
||
{
|
||
_logger.Warn("自动连接变量失败: {Error} | Auto connect variables failed: {Error}", connectResult.ErrorMessage);
|
||
return connectResult;
|
||
}
|
||
_logger.Info("自动连接变量成功 | Auto connect variables succeeded");
|
||
}
|
||
|
||
_logger.Info("自动初始化流程完成 | Auto-initialization sequence completed");
|
||
return XRayResult.Ok();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "自动初始化流程异常: {Message} | Auto-initialization sequence exception: {Message}", ex.Message);
|
||
return XRayResult.Error($"自动初始化异常: {ex.Message}");
|
||
}
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 射线源状态变更事件处理(设备层回调)| Ray source status changed event handler (device callback)
|
||
/// </summary>
|
||
private void OnRaySourceStatusChangedFromDevice(RaySourceStatus newStatus)
|
||
{
|
||
// 更新当前状态(IsXRayOn 由 CurrentStatus 自动派生)| Update current status (IsXRayOn is auto-derived from CurrentStatus)
|
||
CurrentStatus = newStatus;
|
||
_logger.Info("服务层状态更新: {Status} | Service layer status updated: {Status}", newStatus);
|
||
|
||
// 根据射线源状态变更记录灯丝使用(带去重,防止设备推送抖动)| Record filament usage with dedup
|
||
if (_filamentLifetimeService.IsInitialized && newStatus != _lastFilamentRecordedStatus)
|
||
{
|
||
if (newStatus == RaySourceStatus.Opened && !_filamentLifetimeService.IsFilamentOn)
|
||
{
|
||
if (_filamentLifetimeService.StartFilamentUsage())
|
||
_lastFilamentRecordedStatus = newStatus;
|
||
}
|
||
else if (newStatus != RaySourceStatus.Opened && _filamentLifetimeService.IsFilamentOn)
|
||
{
|
||
if (_filamentLifetimeService.StopFilamentUsage())
|
||
_lastFilamentRecordedStatus = newStatus;
|
||
}
|
||
}
|
||
|
||
if (newStatus == RaySourceStatus.Unavailable && _isInitializedFlag)
|
||
{
|
||
// 异常断联处理 | Handle unexpected disconnection
|
||
_logger.Error(null, "服务层检测到连接丢失(状态变为 Unavailable)| Service layer detected connection lost (status changed to Unavailable)");
|
||
_isInitializedFlag = false;
|
||
|
||
// 通知 UI 更新状态 | Notify UI to update status
|
||
_eventAggregator.GetEvent<StatusUpdatedEvent>().Publish(new SystemStatusData
|
||
{
|
||
IsXRayOn = false,
|
||
ActualVoltage = 0,
|
||
ActualCurrent = 0
|
||
});
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 释放资源 | Dispose resources
|
||
/// </summary>
|
||
public void Dispose()
|
||
{
|
||
if (_isDisposed)
|
||
return;
|
||
|
||
try
|
||
{
|
||
// 先执行紧急关闭 | Execute emergency shutdown first
|
||
EmergencyShutdown();
|
||
|
||
// 释放射线源实例 | Dispose X-ray source instance
|
||
_currentSource?.Dispose();
|
||
_currentSource = null;
|
||
|
||
_isDisposed = true;
|
||
_logger.Info("服务层资源已释放 | Service layer resources disposed");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Warn("服务层资源释放异常: {Message} | Service layer resource disposal exception: {Message}", ex.Message);
|
||
}
|
||
}
|
||
}
|
||
}
|