Files
XplorePlane/XP.Hardware.Detector/Services/DetectorService.cs
T

585 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Threading;
using System.Threading.Tasks;
using Prism.Events;
using XP.Hardware.Detector.Abstractions;
using XP.Hardware.Detector.Abstractions.Enums;
using XP.Hardware.Detector.Config;
using XP.Hardware.Detector.Factories;
using XP.Common.Logging.Interfaces;
namespace XP.Hardware.Detector.Services
{
/// <summary>
/// 探测器服务实现 | Detector service implementation
/// 单例模式,封装业务逻辑,屏蔽厂商差异
/// </summary>
public class DetectorService : IDetectorService, IDisposable
{
private readonly IDetectorFactory _factory;
private readonly IEventAggregator _eventAggregator;
private readonly ILoggerService _logger;
private readonly object _lock = new object();
private IAreaDetector _detector;
private DetectorConfig _config;
private DetectorResult _lastError;
private bool _disposed = false;
/// <summary>
/// 当前探测器状态 | Current detector status
/// </summary>
public DetectorStatus Status
{
get
{
lock (_lock)
{
return _detector?.Status ?? DetectorStatus.Uninitialized;
}
}
}
/// <summary>
/// 当前探测器类型 | Current detector type
/// </summary>
public DetectorType? Type
{
get
{
lock (_lock)
{
return _detector?.Type;
}
}
}
/// <summary>
/// 探测器是否已连接 | Whether detector is connected
/// </summary>
public bool IsConnected
{
get
{
lock (_lock)
{
return _detector != null && _detector.Status != DetectorStatus.Uninitialized;
}
}
}
/// <summary>
/// 构造函数 | Constructor
/// </summary>
/// <param name="factory">探测器工厂 | Detector factory</param>
/// <param name="eventAggregator">事件聚合器 | Event aggregator</param>
/// <param name="logger">日志服务 | Logger service</param>
public DetectorService(IDetectorFactory factory, IEventAggregator eventAggregator, ILoggerService logger = null)
{
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
_logger = logger?.ForModule("DetectorService");
_logger?.Info("DetectorService 实例已创建 | DetectorService instance created");
}
/// <summary>
/// 初始化探测器 | Initialize detector
/// </summary>
/// <param name="cancellationToken">取消令牌 | Cancellation token</param>
/// <returns>操作结果 | Operation result</returns>
public async Task<DetectorResult> InitializeAsync(CancellationToken cancellationToken = default)
{
// 若已连接,先断开再重连 | If already connected, disconnect first then reconnect
bool alreadyConnected;
lock (_lock) { alreadyConnected = _detector != null; }
if (alreadyConnected)
{
_logger?.Info("探测器已连接,先断开再重新初始化 | Detector already connected, disconnecting before reinitializing");
await DisconnectAsync();
}
try
{
_logger?.Info("开始初始化探测器服务 | Starting to initialize detector service");
// 加载配置 | Load configuration
_logger?.Debug("加载配置文件 | Loading configuration file");
var configResult = ConfigLoader.LoadConfiguration();
if (!configResult.IsSuccess)
{
_lastError = configResult;
_logger?.Error(null, $"加载配置失败 | Failed to load configuration: {configResult.ErrorMessage}");
return configResult;
}
_logger?.Info($"配置加载成功,探测器类型:{configResult.Data.Type} | Configuration loaded successfully, detector type: {configResult.Data.Type}");
// 保存配置引用 | Save config reference
_config = configResult.Data;
// 创建探测器实例 | Create detector instance
_logger?.Debug("创建探测器实例 | Creating detector instance");
var createResult = _factory.CreateDetector(configResult.Data);
if (!createResult.IsSuccess)
{
_lastError = createResult;
_logger?.Error(createResult.Exception, $"创建探测器实例失败 | Failed to create detector instance: {createResult.ErrorMessage}");
return DetectorResult.Failure(createResult.ErrorMessage, createResult.Exception, createResult.ErrorCode);
}
lock (_lock)
{
_detector = createResult.Data;
}
// 初始化探测器 | Initialize detector
_logger?.Debug("初始化探测器硬件 | Initializing detector hardware");
var initResult = await _detector.InitializeAsync(cancellationToken);
if (!initResult.IsSuccess)
{
_lastError = initResult;
_logger?.Error(initResult.Exception, $"初始化探测器硬件失败 | Failed to initialize detector hardware: {initResult.ErrorMessage}");
}
else
{
_logger?.Info("探测器服务初始化成功 | Detector service initialized successfully");
}
return initResult;
}
catch (Exception ex)
{
var errorMsg = $"初始化服务失败 | Failed to initialize service: {ex.Message}";
_logger?.Error(ex, errorMsg);
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 断开探测器连接 | Disconnect detector
/// </summary>
public async Task<DetectorResult> DisconnectAsync()
{
try
{
IAreaDetector detector;
lock (_lock)
{
detector = _detector;
if (detector == null)
{
_logger?.Warn("探测器未连接,无需断开 | Detector not connected, no need to disconnect");
return DetectorResult.Success("探测器未连接 | Detector not connected");
}
}
_logger?.Info("开始断开探测器连接 | Starting to disconnect detector");
// 如果正在采集,先停止 | If acquiring, stop first
if (detector.Status == DetectorStatus.Acquiring)
{
_logger?.Info("探测器正在采集,先停止采集 | Detector is acquiring, stopping first");
await detector.StopAcquisitionAsync();
}
// 释放探测器资源 | Dispose detector resources
lock (_lock)
{
_detector?.Dispose();
_detector = null;
}
_config = null;
_logger?.Info("探测器已断开连接 | Detector disconnected");
return DetectorResult.Success("探测器已断开连接 | Detector disconnected");
}
catch (Exception ex)
{
var errorMsg = $"断开探测器连接异常 | Disconnect detector exception: {ex.Message}";
_logger?.Error(ex, errorMsg);
// 强制清理 | Force cleanup
lock (_lock)
{
_detector?.Dispose();
_detector = null;
}
_config = null;
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 启动连续采集 | Start continuous acquisition
/// </summary>
/// <param name="cancellationToken">取消令牌 | Cancellation token</param>
/// <returns>操作结果 | Operation result</returns>
public async Task<DetectorResult> StartAcquisitionAsync(CancellationToken cancellationToken = default)
{
try
{
_logger?.Info("服务层:启动连续采集 | Service layer: Starting continuous acquisition");
var detector = GetDetectorOrThrow();
var result = await detector.StartAcquisitionAsync(cancellationToken);
if (!result.IsSuccess)
{
_lastError = result;
_logger?.Error(result.Exception, $"启动采集失败 | Failed to start acquisition: {result.ErrorMessage}");
}
return result;
}
catch (Exception ex)
{
var errorMsg = $"服务层启动采集异常 | Service layer start acquisition exception: {ex.Message}";
_logger?.Error(ex, errorMsg);
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 停止采集 | Stop acquisition
/// </summary>
/// <param name="cancellationToken">取消令牌 | Cancellation token</param>
/// <returns>操作结果 | Operation result</returns>
public async Task<DetectorResult> StopAcquisitionAsync(CancellationToken cancellationToken = default)
{
try
{
_logger?.Info("服务层:停止采集 | Service layer: Stopping acquisition");
var detector = GetDetectorOrThrow();
var result = await detector.StopAcquisitionAsync(cancellationToken);
if (!result.IsSuccess)
{
_lastError = result;
_logger?.Error(result.Exception, $"停止采集失败 | Failed to stop acquisition: {result.ErrorMessage}");
}
return result;
}
catch (Exception ex)
{
var errorMsg = $"服务层停止采集异常 | Service layer stop acquisition exception: {ex.Message}";
_logger?.Error(ex, errorMsg);
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 单帧采集 | Single frame acquisition
/// </summary>
/// <param name="cancellationToken">取消令牌 | Cancellation token</param>
/// <returns>操作结果 | Operation result</returns>
public async Task<DetectorResult> AcquireSingleFrameAsync(CancellationToken cancellationToken = default)
{
try
{
_logger?.Debug("服务层:单帧采集 | Service layer: Single frame acquisition");
var detector = GetDetectorOrThrow();
var result = await detector.AcquireSingleFrameAsync(cancellationToken);
if (!result.IsSuccess)
{
_lastError = result;
_logger?.Error(result.Exception, $"单帧采集失败 | Failed to acquire single frame: {result.ErrorMessage}");
}
return result;
}
catch (Exception ex)
{
var errorMsg = $"服务层单帧采集异常 | Service layer single frame acquisition exception: {ex.Message}";
_logger?.Error(ex, errorMsg);
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 暗场校正 | Dark field correction
/// </summary>
/// <param name="frameCount">采集帧数 | Frame count</param>
/// <param name="cancellationToken">取消令牌 | Cancellation token</param>
/// <returns>操作结果 | Operation result</returns>
public async Task<DetectorResult> DarkCorrectionAsync(int frameCount = 10, CancellationToken cancellationToken = default)
{
try
{
_logger?.Info("服务层:执行暗场校正,帧数:{FrameCount} | Service layer: Executing dark correction, frame count: {FrameCount}", frameCount);
var detector = GetDetectorOrThrow();
var result = await detector.DarkCorrectionAsync(frameCount, cancellationToken);
if (!result.IsSuccess)
{
_lastError = result;
_logger?.Error(result.Exception, "暗场校正失败:{Message} | Dark correction failed: {Message}", result.ErrorMessage);
}
return result;
}
catch (Exception ex)
{
var errorMsg = $"服务层暗场校正异常 | Service layer dark correction exception: {ex.Message}";
_logger?.Error(ex, errorMsg);
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 增益校正(亮场校正)| Gain correction (bright field correction)
/// </summary>
/// <param name="frameCount">采集帧数 | Frame count</param>
/// <param name="cancellationToken">取消令牌 | Cancellation token</param>
/// <returns>操作结果 | Operation result</returns>
public async Task<DetectorResult> GainCorrectionAsync(int frameCount = 10, CancellationToken cancellationToken = default)
{
try
{
_logger?.Info("服务层:执行亮场校正,帧数:{FrameCount} | Service layer: Executing gain correction, frame count: {FrameCount}", frameCount);
var detector = GetDetectorOrThrow();
var result = await detector.GainCorrectionAsync(frameCount, cancellationToken);
if (!result.IsSuccess)
{
_lastError = result;
_logger?.Error(result.Exception, "亮场校正失败:{Message} | Gain correction failed: {Message}", result.ErrorMessage);
}
return result;
}
catch (Exception ex)
{
var errorMsg = $"服务层亮场校正异常 | Service layer gain correction exception: {ex.Message}";
_logger?.Error(ex, errorMsg);
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 坏像素校正 | Bad pixel correction
/// </summary>
/// <param name="cancellationToken">取消令牌 | Cancellation token</param>
/// <returns>操作结果 | Operation result</returns>
public async Task<DetectorResult> BadPixelCorrectionAsync(CancellationToken cancellationToken = default)
{
try
{
_logger?.Info("服务层:执行坏像素校正 | Service layer: Executing bad pixel correction");
var detector = GetDetectorOrThrow();
var result = await detector.BadPixelCorrectionAsync(cancellationToken);
if (!result.IsSuccess)
{
_lastError = result;
_logger?.Error(result.Exception, "坏像素校正失败:{Message} | Bad pixel correction failed: {Message}", result.ErrorMessage);
}
return result;
}
catch (Exception ex)
{
var errorMsg = $"服务层坏像素校正异常 | Service layer bad pixel correction exception: {ex.Message}";
_logger?.Error(ex, errorMsg);
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 执行自动校正(暗场+增益+坏像素)| Execute auto correction (dark + gain + bad pixel)
/// </summary>
/// <param name="frameCount">采集帧数 | Frame count</param>
/// <param name="cancellationToken">取消令牌 | Cancellation token</param>
/// <returns>操作结果 | Operation result</returns>
public async Task<DetectorResult> AutoCorrectionAsync(int frameCount = 10, CancellationToken cancellationToken = default)
{
try
{
_logger?.Info("服务层:执行自动校正,帧数:{FrameCount} | Service layer: Executing auto correction, frame count: {FrameCount}", frameCount);
var detector = GetDetectorOrThrow();
var result = await detector.AutoCorrectionAsync(frameCount, cancellationToken);
if (!result.IsSuccess)
{
_lastError = result;
_logger?.Error(result.Exception, "自动校正失败:{Message} | Auto correction failed: {Message}", result.ErrorMessage);
}
return result;
}
catch (Exception ex)
{
var errorMsg = $"服务层自动校正异常 | Service layer auto correction exception: {ex.Message}";
_logger?.Error(ex, errorMsg);
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 应用探测器参数(Binning/PGA/帧率统一下发)| Apply detector parameters (Binning/PGA/FrameRate)
/// </summary>
public async Task<DetectorResult> ApplyParametersAsync(int binningIndex, int pga, decimal frameRate, CancellationToken cancellationToken = default)
{
try
{
_logger?.Info("服务层:应用参数,Binning={Binning}PGA={PGA},帧率={FrameRate} | Service layer: Applying parameters",
binningIndex, pga, frameRate);
var detector = GetDetectorOrThrow();
// 通过 IVarexDetector 接口下发参数 | Apply parameters via IVarexDetector interface
if (detector is IVarexDetector varexDetector)
{
// 设置 Binning | Set binning
var binningResult = await varexDetector.SetBinningModeAsync((BinningMode)binningIndex);
if (!binningResult.IsSuccess)
{
_lastError = binningResult;
return binningResult;
}
// 设置增益(PGA| Set gain (PGA)
var gainResult = await varexDetector.SetGainModeAsync((GainMode)pga);
if (!gainResult.IsSuccess)
{
_lastError = gainResult;
return gainResult;
}
// 设置曝光时间(帧率→微秒:1000*1000/帧率)| Set exposure time (frame rate → microseconds)
uint exposureUs = frameRate > 0 ? (uint)(1_000_000m / frameRate) : 66667;
var exposureResult = await varexDetector.SetExposureTimeAsync(exposureUs);
if (!exposureResult.IsSuccess)
{
_lastError = exposureResult;
return exposureResult;
}
_logger?.Info("参数应用成功 | Parameters applied successfully");
return DetectorResult.Success("参数应用成功 | Parameters applied successfully");
}
return DetectorResult.Failure("当前探测器不支持参数下发 | Current detector does not support parameter application");
}
catch (Exception ex)
{
var errorMsg = $"服务层应用参数异常 | Service layer apply parameters exception: {ex.Message}";
_logger?.Error(ex, errorMsg);
var errorResult = DetectorResult.Failure(errorMsg, ex, -1);
_lastError = errorResult;
return errorResult;
}
}
/// <summary>
/// 保存当前配置到文件 | Save current configuration to file
/// </summary>
public void SaveParameters(int binningIndex, int pga, decimal frameRate, int avgFrames)
{
try
{
_logger?.Info("保存探测器参数,Binning={Binning}PGA={PGA},帧率={FrameRate},帧合并={AvgFrames} | Saving detector parameters",
binningIndex, pga, frameRate, avgFrames);
ConfigLoader.SaveParameters(binningIndex, pga, frameRate, avgFrames);
_logger?.Info("探测器参数保存成功 | Detector parameters saved successfully");
}
catch (Exception ex)
{
_logger?.Error(ex, "保存探测器参数失败:{Message} | Failed to save detector parameters: {Message}", ex.Message);
}
}
/// <summary>
/// 获取探测器信息 | Get detector information
/// </summary>
/// <returns>探测器信息 | Detector information</returns>
public DetectorInfo GetInfo()
{
var detector = GetDetectorOrThrow();
return detector.GetInfo();
}
/// <summary>
/// 获取最后的错误信息 | Get last error information
/// </summary>
/// <returns>错误结果 | Error result</returns>
public DetectorResult GetLastError()
{
return _lastError ?? DetectorResult.Success();
}
/// <summary>
/// 获取当前探测器配置 | Get current detector configuration
/// 未初始化时尝试从配置文件加载(仅读取配置,不创建探测器实例)
/// </summary>
public DetectorConfig GetCurrentConfig()
{
if (_config != null) return _config;
// 未初始化时,尝试从配置文件加载以提供 UI 选项 | If not initialized, try loading from config for UI options
try
{
var configResult = ConfigLoader.LoadConfiguration();
if (configResult.IsSuccess)
{
_config = configResult.Data;
return _config;
}
}
catch
{
// 忽略加载异常,返回 null | Ignore load exception, return null
}
return null;
}
/// <summary>
/// 获取探测器实例或抛出异常 | Get detector instance or throw exception
/// </summary>
/// <returns>探测器实例 | Detector instance</returns>
/// <exception cref="InvalidOperationException">探测器未初始化 | Detector not initialized</exception>
private IAreaDetector GetDetectorOrThrow()
{
lock (_lock)
{
if (_detector == null)
{
throw new InvalidOperationException("探测器未初始化,请先调用 InitializeAsync | Detector not initialized, please call InitializeAsync first");
}
return _detector;
}
}
/// <summary>
/// 释放资源 | Dispose resources
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// 释放资源 | Dispose resources
/// </summary>
/// <param name="disposing">是否释放托管资源 | Whether to dispose managed resources</param>
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// 释放托管资源 | Release managed resources
lock (_lock)
{
_detector?.Dispose();
_detector = null;
}
}
_disposed = true;
}
}
}
}