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.Common.Logging.Interfaces; namespace XP.Hardware.Detector.Implementations { /// /// 软件模拟探测器 | Software simulated detector /// 无需真实硬件,定时发布合成的 16-bit 灰度帧,用于集成链路验证。 /// 帧内容:渐变灰度 + 帧号水印,便于肉眼确认帧序列。 /// public sealed class SimulatedDetector : AreaDetectorBase { private readonly SimulatedDetectorConfig _config; private readonly ILoggerService _logger; private CancellationTokenSource _acquisitionCts; private Task _acquisitionTask; private int _frameNumber; public override DetectorType Type => DetectorType.Simulated; public SimulatedDetector(SimulatedDetectorConfig config, IEventAggregator eventAggregator, ILoggerService logger = null) : base(eventAggregator) { _config = config ?? throw new ArgumentNullException(nameof(config)); _logger = logger?.ForModule("SimulatedDetector"); _logger?.Info("[SimulatedDetector] 实例已创建,分辨率 {W}x{H},帧率 {FPS} fps", _config.Width, _config.Height, _config.FrameRateFps); } // ── 模板方法实现 ────────────────────────────────────────────────── protected override Task InitializeInternalAsync(CancellationToken cancellationToken) { _logger?.Info("[SimulatedDetector] 初始化完成(无硬件操作)"); return Task.FromResult(DetectorResult.Success("模拟探测器初始化成功")); } protected override Task StartAcquisitionInternalAsync(CancellationToken cancellationToken) { _acquisitionCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); _acquisitionTask = Task.Run(() => AcquisitionLoopAsync(_acquisitionCts.Token), _acquisitionCts.Token); _logger?.Info("[SimulatedDetector] 连续采集已启动"); return Task.FromResult(DetectorResult.Success("模拟采集已启动")); } protected override async Task StopAcquisitionInternalAsync(CancellationToken cancellationToken) { _acquisitionCts?.Cancel(); if (_acquisitionTask != null) { try { await _acquisitionTask.ConfigureAwait(false); } catch (OperationCanceledException) { } } _acquisitionCts?.Dispose(); _acquisitionCts = null; _acquisitionTask = null; _logger?.Info("[SimulatedDetector] 连续采集已停止"); return DetectorResult.Success("模拟采集已停止"); } protected override Task AcquireSingleFrameInternalAsync(CancellationToken cancellationToken) { PublishSyntheticFrame(); _logger?.Info("[SimulatedDetector] 单帧采集完成,帧号 {N}", _frameNumber); return Task.FromResult(DetectorResult.Success("单帧采集成功")); } protected override Task DarkCorrectionInternalAsync(int frameCount, CancellationToken cancellationToken) => Task.FromResult(DetectorResult.Success("模拟暗场校正完成")); protected override Task GainCorrectionInternalAsync(int frameCount, CancellationToken cancellationToken) => Task.FromResult(DetectorResult.Success("模拟亮场校正完成")); protected override Task AutoCorrectionInternalAsync(int frameCount, CancellationToken cancellationToken) => Task.FromResult(DetectorResult.Success("模拟自动校正完成")); protected override Task BadPixelCorrectionInternalAsync(CancellationToken cancellationToken) => Task.FromResult(DetectorResult.Success("模拟坏像素校正完成")); protected override Task ApplyParametersInternalAsync(int binningIndex, int pga, decimal frameRate, CancellationToken cancellationToken) { _logger?.Info("[SimulatedDetector] 应用参数: Binning={Binning}, PGA={PGA}, FrameRate={FPS}", binningIndex, pga, frameRate); return Task.FromResult(DetectorResult.Success("模拟探测器参数应用成功")); } public override DetectorInfo GetInfo() => new DetectorInfo { Type = DetectorType.Simulated, Model = "SimulatedDetector", SerialNumber = "SIM-0001", FirmwareVersion = "1.0.0", MaxWidth = (uint)_config.Width, MaxHeight = (uint)_config.Height, PixelSize = 0.139, BitDepth = 16 }; // ── 内部实现 ────────────────────────────────────────────────────── private async Task AcquisitionLoopAsync(CancellationToken ct) { var intervalMs = (int)(1000.0 / Math.Max(1, _config.FrameRateFps)); _logger?.Info("[SimulatedDetector] 采集循环启动,间隔 {Interval} ms", intervalMs); try { while (!ct.IsCancellationRequested) { PublishSyntheticFrame(); await Task.Delay(intervalMs, ct).ConfigureAwait(false); } } catch (OperationCanceledException) { // 正常退出 } catch (Exception ex) { _logger?.Error(ex, "[SimulatedDetector] 采集循环异常退出"); } _logger?.Info("[SimulatedDetector] 采集循环已退出"); } /// /// 生成并发布一帧合成图像。 /// 内容:水平渐变灰度(0–65535),每行叠加帧号偏移,形成滚动条纹效果。 /// private void PublishSyntheticFrame() { int n = Interlocked.Increment(ref _frameNumber); int w = _config.Width; int h = _config.Height; var pixels = new ushort[w * h]; int offset = (n * 64) % 65536; // 每帧偏移,产生滚动效果 for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { // 水平渐变 + 帧偏移 int value = (int)((double)x / w * 65535) + offset; pixels[y * w + x] = (ushort)(value & 0xFFFF); } } var args = new ImageCapturedEventArgs { ImageData = pixels, Width = (uint)w, Height = (uint)h, FrameNumber = n, CaptureTime = DateTime.Now, ExposureTime = 0 }; //_logger?.Info("[SimulatedDetector] 发布合成帧 #{N},分辨率 {W}x{H}", n, w, h); PublishImageCaptured(args); } protected override void Dispose(bool disposing) { if (disposing) { _acquisitionCts?.Cancel(); _acquisitionCts?.Dispose(); } base.Dispose(disposing); } } }