From 2d7cf17a3b9863bd683593fa2775362e7aeb8746 Mon Sep 17 00:00:00 2001 From: QI Mingxuan Date: Thu, 21 May 2026 13:19:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A2=E6=B5=8B=E5=99=A8XP.Hardware.Detector?= =?UTF-8?q?=E7=B1=BB=E5=BA=93=E4=B8=BA=E4=BA=86=E6=9B=B4=E5=A5=BD=E9=9B=86?= =?UTF-8?q?=E6=88=90=E6=96=B0=E7=9A=84=E6=8E=A2=E6=B5=8B=E5=99=A8=EF=BC=8C?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=8E=A5=E5=8F=A3=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?DetectorService=E9=87=8D=E6=9E=84=E4=B8=BA=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=8E=A5=E5=8F=A3=EF=BC=9B=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=9A=97=E5=9C=BA=E6=A0=A1=E6=AD=A3=E5=92=8C=E4=BA=AE?= =?UTF-8?q?=E5=9C=BA=E6=A0=A1=E6=AD=A3=E5=B8=A7=E6=95=B0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=EF=BC=88=E9=BB=98=E8=AE=A4=2064=EF=BC=8C?= =?UTF-8?q?=E8=8C=83=E5=9B=B4=201-128=EF=BC=89=EF=BC=8Cconfig=20=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E6=A0=A1=E6=AD=A3=E5=B8=A7=E6=95=B0=EF=BC=9B=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=8E=A2=E6=B5=8B=E5=99=A8IsConnected?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E7=8A=B6=E6=80=81=E7=9A=84=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Abstractions/AreaDetectorBase.cs | 39 ++++++ .../Abstractions/CorrectionCapabilities.cs | 49 ++++++++ .../Abstractions/IAreaDetector.cs | 21 ++++ XP.Hardware.Detector/Config/ConfigLoader.cs | 10 ++ XP.Hardware.Detector/Config/DetectorConfig.cs | 10 ++ .../Implementations/IRayDetector.cs | 9 ++ .../Implementations/VarexDetector.cs | 109 +++++++++++++++++ .../Services/DetectorService.cs | 115 ++++++++++-------- .../Services/IDetectorService.cs | 6 + .../ViewModels/DetectorConfigViewModel.cs | 25 ++-- .../Views/DetectorConfigView.xaml | 3 + XplorePlane/App.config | 6 +- 12 files changed, 333 insertions(+), 69 deletions(-) create mode 100644 XP.Hardware.Detector/Abstractions/CorrectionCapabilities.cs diff --git a/XP.Hardware.Detector/Abstractions/AreaDetectorBase.cs b/XP.Hardware.Detector/Abstractions/AreaDetectorBase.cs index 8964a33..258021d 100644 --- a/XP.Hardware.Detector/Abstractions/AreaDetectorBase.cs +++ b/XP.Hardware.Detector/Abstractions/AreaDetectorBase.cs @@ -386,6 +386,44 @@ namespace XP.Hardware.Detector.Abstractions /// public abstract DetectorInfo GetInfo(); + /// + /// 应用探测器参数 | Apply detector parameters + /// + public async Task ApplyParametersAsync(int binningIndex, int pga, decimal frameRate, CancellationToken cancellationToken = default) + { + if (Status != DetectorStatus.Ready) + { + return DetectorResult.Failure($"探测器状态不正确,当前状态:{Status} | Detector status incorrect, current status: {Status}"); + } + + try + { + return await ApplyParametersInternalAsync(binningIndex, pga, frameRate, cancellationToken); + } + catch (Exception ex) + { + var errorResult = DetectorResult.Failure($"应用参数异常 | Apply parameters exception: {ex.Message}", ex); + PublishError(errorResult); + return errorResult; + } + } + + /// + /// 获取校正能力描述(子类可重写)| Get correction capabilities (subclass can override) + /// + public virtual CorrectionCapabilities GetCorrectionCapabilities() + { + return new CorrectionCapabilities(); + } + + /// + /// 显式失效校正数据(子类可重写)| Explicitly invalidate correction data (subclass can override) + /// + public virtual void InvalidateCorrectionData() + { + // 默认空实现,子类按需重写 | Default empty implementation, subclass overrides as needed + } + // 模板方法,由子类实现 | Template methods, implemented by derived classes protected abstract Task InitializeInternalAsync(CancellationToken cancellationToken); protected abstract Task StartAcquisitionInternalAsync(CancellationToken cancellationToken); @@ -395,6 +433,7 @@ namespace XP.Hardware.Detector.Abstractions protected abstract Task GainCorrectionInternalAsync(int frameCount, CancellationToken cancellationToken); protected abstract Task AutoCorrectionInternalAsync(int frameCount, CancellationToken cancellationToken); protected abstract Task BadPixelCorrectionInternalAsync(CancellationToken cancellationToken); + protected abstract Task ApplyParametersInternalAsync(int binningIndex, int pga, decimal frameRate, CancellationToken cancellationToken); /// /// 更新状态并发布事件 | Update status and publish event diff --git a/XP.Hardware.Detector/Abstractions/CorrectionCapabilities.cs b/XP.Hardware.Detector/Abstractions/CorrectionCapabilities.cs new file mode 100644 index 0000000..3136fb1 --- /dev/null +++ b/XP.Hardware.Detector/Abstractions/CorrectionCapabilities.cs @@ -0,0 +1,49 @@ +namespace XP.Hardware.Detector.Abstractions +{ + /// + /// 校正能力描述 | Correction capabilities description + /// 描述探测器支持的校正行为和参数范围,不同探测器可返回不同配置 + /// + public class CorrectionCapabilities + { + /// + /// 是否需要在校正前停止采集 | Whether to stop acquisition before correction + /// + public bool RequiresStopBeforeCorrection { get; set; } = true; + + /// + /// 是否需要在暗场校正前应用参数 | Whether to apply parameters before dark correction + /// + public bool RequiresParameterApplyBeforeDark { get; set; } = true; + + /// + /// 亮场校正后是否自动执行坏像素校正 | Auto bad pixel correction after gain correction + /// + public bool AutoBadPixelAfterGain { get; set; } = true; + + /// + /// 停止采集后等待时间(ms)| Post-stop delay (ms) + /// + public int PostStopDelayMs { get; set; } = 500; + + /// + /// 暗场校正帧数(从配置文件加载)| Dark correction frame count (loaded from config) + /// + public int DarkFrameCount { get; set; } = 64; + + /// + /// 亮场校正帧数(从配置文件加载)| Gain correction frame count (loaded from config) + /// + public int GainFrameCount { get; set; } = 64; + + /// + /// 校正帧数最小值 | Correction frame count minimum + /// + public int FrameCountMin { get; set; } = 1; + + /// + /// 校正帧数最大值 | Correction frame count maximum + /// + public int FrameCountMax { get; set; } = 128; + } +} diff --git a/XP.Hardware.Detector/Abstractions/IAreaDetector.cs b/XP.Hardware.Detector/Abstractions/IAreaDetector.cs index 527742d..6c10e20 100644 --- a/XP.Hardware.Detector/Abstractions/IAreaDetector.cs +++ b/XP.Hardware.Detector/Abstractions/IAreaDetector.cs @@ -85,5 +85,26 @@ namespace XP.Hardware.Detector.Abstractions /// /// 探测器信息 | Detector information DetectorInfo GetInfo(); + + /// + /// 应用探测器参数(Binning/PGA/帧率)| Apply detector parameters (Binning/PGA/FrameRate) + /// + /// Binning 索引 | Binning index + /// PGA 灵敏度值 | PGA sensitivity value + /// 帧率 | Frame rate + /// 取消令牌 | Cancellation token + /// 操作结果 | Operation result + Task ApplyParametersAsync(int binningIndex, int pga, decimal frameRate, CancellationToken cancellationToken = default); + + /// + /// 获取校正能力描述 | Get correction capabilities + /// + /// 校正能力描述 | Correction capabilities + CorrectionCapabilities GetCorrectionCapabilities(); + + /// + /// 显式失效校正数据(参数变更后调用)| Explicitly invalidate correction data (called after parameter change) + /// + void InvalidateCorrectionData(); } } diff --git a/XP.Hardware.Detector/Config/ConfigLoader.cs b/XP.Hardware.Detector/Config/ConfigLoader.cs index bc9d512..f5b2537 100644 --- a/XP.Hardware.Detector/Config/ConfigLoader.cs +++ b/XP.Hardware.Detector/Config/ConfigLoader.cs @@ -48,6 +48,16 @@ namespace XP.Hardware.Detector.Config config.SavePath = ConfigurationManager.AppSettings["Detector:SavePath"] ?? Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images"); config.AutoSave = bool.TryParse(ConfigurationManager.AppSettings["Detector:AutoSave"], out var autoSave) && autoSave; + // 加载校正帧数配置(钳位到 1-128)| Load correction frame count config (clamp to 1-128) + if (int.TryParse(ConfigurationManager.AppSettings["Detector:Correction:DarkFrameCount"], out var darkFrames)) + { + config.DarkCorrectionFrameCount = Math.Clamp(darkFrames, 1, 128); + } + if (int.TryParse(ConfigurationManager.AppSettings["Detector:Correction:GainFrameCount"], out var gainFrames)) + { + config.GainCorrectionFrameCount = Math.Clamp(gainFrames, 1, 128); + } + // 验证配置 | Validate configuration var validationResult = ValidateConfiguration(config); if (!validationResult.IsSuccess) diff --git a/XP.Hardware.Detector/Config/DetectorConfig.cs b/XP.Hardware.Detector/Config/DetectorConfig.cs index d0c437d..813fe8c 100644 --- a/XP.Hardware.Detector/Config/DetectorConfig.cs +++ b/XP.Hardware.Detector/Config/DetectorConfig.cs @@ -34,6 +34,16 @@ namespace XP.Hardware.Detector.Config /// public bool AutoSave { get; set; } + /// + /// 暗场校正帧数(1-128,默认 64)| Dark correction frame count (1-128, default 64) + /// + public int DarkCorrectionFrameCount { get; set; } = 64; + + /// + /// 亮场校正帧数(1-128,默认 64)| Gain correction frame count (1-128, default 64) + /// + public int GainCorrectionFrameCount { get; set; } = 64; + /// /// 获取支持的 Binning 选项(显示名称 → 索引)| Get supported binning options (display name → index) /// 子类可重写以提供不同的选项列表 diff --git a/XP.Hardware.Detector/Implementations/IRayDetector.cs b/XP.Hardware.Detector/Implementations/IRayDetector.cs index 1a6c501..36fcbcd 100644 --- a/XP.Hardware.Detector/Implementations/IRayDetector.cs +++ b/XP.Hardware.Detector/Implementations/IRayDetector.cs @@ -111,6 +111,15 @@ namespace XP.Hardware.Detector.Implementations throw new NotImplementedException("iRay 探测器坏像素校正尚未实现 | iRay detector bad pixel correction not implemented yet"); } + /// + /// 应用参数(内部实现)| Apply parameters (internal implementation) + /// + protected override Task ApplyParametersInternalAsync(int binningIndex, int pga, decimal frameRate, CancellationToken cancellationToken) + { + // TODO: 实现 iRay 探测器参数应用逻辑 | Implement iRay detector parameter application logic + throw new NotImplementedException("iRay 探测器参数应用尚未实现 | iRay detector parameter application not implemented yet"); + } + /// /// 获取探测器信息 | Get detector information /// diff --git a/XP.Hardware.Detector/Implementations/VarexDetector.cs b/XP.Hardware.Detector/Implementations/VarexDetector.cs index 8dc1891..45419d1 100644 --- a/XP.Hardware.Detector/Implementations/VarexDetector.cs +++ b/XP.Hardware.Detector/Implementations/VarexDetector.cs @@ -1155,6 +1155,115 @@ namespace XP.Hardware.Detector.Implementations #endregion + #region 统一接口实现 | Unified Interface Implementations + + /// + /// 应用参数内部实现 | Apply parameters internal implementation + /// + protected override Task ApplyParametersInternalAsync(int binningIndex, int pga, decimal frameRate, CancellationToken cancellationToken) + { + return Task.Run(() => + { + try + { + _logger?.Info($"应用参数:Binning={binningIndex},PGA={pga},帧率={frameRate} | Applying parameters: Binning={binningIndex}, PGA={pga}, FrameRate={frameRate}"); + + // 设置 Binning 模式 | Set binning mode + var binningMode = (BinningMode)binningIndex; + var result = XISLApi.Acquisition_SetCameraBinningMode(_hAcqDesc, (uint)binningMode + 1); + if (result != XISLApi.HIS_RETURN.HIS_ALL_OK) + { + return DetectorResult.Failure($"设置 Binning 模式失败 | Failed to set binning mode: {result}"); + } + + // Binning 变化时失效校正数据 | Invalidate correction data on binning change + if (_binningMode != binningMode) + { + _logger?.Info($"Binning 模式从 {_binningMode} 变更为 {binningMode},校正数据已失效 | Binning changed, correction data invalidated"); + InvalidateCorrectionData(); + } + _binningMode = binningMode; + + // 设置增益模式 | Set gain mode + var gainMode = (GainMode)pga; + result = XISLApi.Acquisition_SetCameraGain(_hAcqDesc, (uint)gainMode); + if (result != XISLApi.HIS_RETURN.HIS_ALL_OK) + { + return DetectorResult.Failure($"设置增益模式失败 | Failed to set gain mode: {result}"); + } + + // PGA 变化时失效校正数据 | Invalidate correction data on PGA change + if (_gainMode != gainMode) + { + _logger?.Info($"PGA 从 {_gainMode} 变更为 {gainMode},校正数据已失效 | PGA changed, correction data invalidated"); + InvalidateCorrectionData(); + } + _gainMode = gainMode; + + // 设置曝光时间(帧率→微秒)| Set exposure time (frame rate → microseconds) + uint exposureUs = frameRate > 0 ? (uint)(1_000_000m / frameRate) : 66667; + result = XISLApi.Acquisition_SetTimerSync(_hAcqDesc, ref exposureUs); + if (result != XISLApi.HIS_RETURN.HIS_ALL_OK) + { + return DetectorResult.Failure($"设置曝光时间失败 | Failed to set exposure time: {result}"); + } + _exposureTime = exposureUs; + + _logger?.Info("参数应用成功 | Parameters applied successfully"); + return DetectorResult.Success("参数应用成功 | Parameters applied successfully"); + } + catch (Exception ex) + { + return DetectorResult.Failure($"应用参数异常 | Apply parameters exception: {ex.Message}", ex); + } + }, cancellationToken); + } + + /// + /// 获取 Varex 校正能力描述 | Get Varex correction capabilities + /// + public override CorrectionCapabilities GetCorrectionCapabilities() + { + return new CorrectionCapabilities + { + RequiresStopBeforeCorrection = true, + RequiresParameterApplyBeforeDark = true, + AutoBadPixelAfterGain = true, + PostStopDelayMs = 500, + DarkFrameCount = _config.DarkCorrectionFrameCount, + GainFrameCount = _config.GainCorrectionFrameCount, + FrameCountMin = 1, + FrameCountMax = 128 + }; + } + + /// + /// 失效校正数据(释放校正缓冲区)| Invalidate correction data (free correction buffers) + /// + public override void InvalidateCorrectionData() + { + if (_pOffsetBuffer != IntPtr.Zero) + { + Marshal.FreeHGlobal(_pOffsetBuffer); + _pOffsetBuffer = IntPtr.Zero; + _offsetBufferRows = 0; + _offsetBufferColumns = 0; + } + if (_pGainBuffer != IntPtr.Zero) + { + Marshal.FreeHGlobal(_pGainBuffer); + _pGainBuffer = IntPtr.Zero; + } + if (_pCorrList != IntPtr.Zero) + { + Marshal.FreeHGlobal(_pCorrList); + _pCorrList = IntPtr.Zero; + } + _logger?.Debug("校正数据已失效并释放 | Correction data invalidated and freed"); + } + + #endregion + #region IVarexDetector 接口实现(占位符)| IVarexDetector Interface Implementations (Placeholders) /// diff --git a/XP.Hardware.Detector/Services/DetectorService.cs b/XP.Hardware.Detector/Services/DetectorService.cs index 1e52b02..ccc4fc5 100644 --- a/XP.Hardware.Detector/Services/DetectorService.cs +++ b/XP.Hardware.Detector/Services/DetectorService.cs @@ -62,7 +62,11 @@ namespace XP.Hardware.Detector.Services { lock (_lock) { - return _detector != null && _detector.Status != DetectorStatus.Uninitialized; + if (_detector == null) return false; + var status = _detector.Status; + return status == DetectorStatus.Ready + || status == DetectorStatus.Acquiring + || status == DetectorStatus.Correcting; } } } @@ -509,64 +513,44 @@ namespace XP.Hardware.Detector.Services var detector = GetDetectorOrThrow(); - // 通过 IVarexDetector 接口下发参数 | Apply parameters via IVarexDetector interface - if (detector is IVarexDetector varexDetector) + // 如果正在采集,先停止 | Stop acquisition first if running + bool wasAcquiring = detector.Status == DetectorStatus.Acquiring; + if (wasAcquiring) { - // 如果正在采集,先停止(XISL SDK 不允许采集中修改参数)| Stop acquisition first if running (XISL SDK does not allow parameter changes during acquisition) - bool wasAcquiring = detector.Status == DetectorStatus.Acquiring; - if (wasAcquiring) + _logger?.Info("探测器正在采集,先停止采集再应用参数 | Detector is acquiring, stopping before applying parameters"); + var stopResult = await detector.StopAcquisitionAsync(cancellationToken); + if (!stopResult.IsSuccess) { - _logger?.Info("探测器正在采集,先停止采集再应用参数 | Detector is acquiring, stopping before applying parameters"); - var stopResult = await detector.StopAcquisitionAsync(cancellationToken); - if (!stopResult.IsSuccess) - { - _lastError = stopResult; - _logger?.Error(stopResult.Exception, "停止采集失败,无法应用参数:{Message} | Failed to stop acquisition, cannot apply parameters: {Message}", stopResult.ErrorMessage); - return DetectorResult.Failure($"停止采集失败,无法应用参数 | Failed to stop acquisition, cannot apply parameters: {stopResult.ErrorMessage}"); - } + _lastError = stopResult; + _logger?.Error(stopResult.Exception, "停止采集失败,无法应用参数:{Message} | Failed to stop acquisition, cannot apply parameters: {Message}", stopResult.ErrorMessage); + return DetectorResult.Failure($"停止采集失败,无法应用参数 | Failed to stop acquisition, cannot apply parameters: {stopResult.ErrorMessage}"); } - - // 设置 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; - } - - // 如果之前在采集,恢复采集 | Resume acquisition if it was running before - if (wasAcquiring) - { - _logger?.Info("参数应用完成,恢复连续采集 | Parameters applied, resuming continuous acquisition"); - var startResult = await detector.StartAcquisitionAsync(cancellationToken); - if (!startResult.IsSuccess) - { - _logger?.Warn("恢复采集失败:{Message}(参数已成功应用)| Failed to resume acquisition: {Message} (parameters were applied successfully)", startResult.ErrorMessage); - } - } - - _logger?.Info("参数应用成功 | Parameters applied successfully"); - return DetectorResult.Success("参数应用成功 | Parameters applied successfully"); } - return DetectorResult.Failure("当前探测器不支持参数下发 | Current detector does not support parameter application"); + // 通过统一接口下发参数(不依赖具体探测器类型)| Apply parameters via unified interface (no dependency on specific detector type) + var result = await detector.ApplyParametersAsync(binningIndex, pga, frameRate, cancellationToken); + if (!result.IsSuccess) + { + _lastError = result; + _logger?.Error(result.Exception, "应用参数失败:{Message} | Apply parameters failed: {Message}", result.ErrorMessage); + } + else + { + _logger?.Info("参数应用成功 | Parameters applied successfully"); + } + + // 如果之前在采集,恢复采集 | Resume acquisition if it was running before + if (wasAcquiring) + { + _logger?.Info("参数应用完成,恢复连续采集 | Parameters applied, resuming continuous acquisition"); + var startResult = await detector.StartAcquisitionAsync(cancellationToken); + if (!startResult.IsSuccess) + { + _logger?.Warn("恢复采集失败:{Message}(参数已成功应用)| Failed to resume acquisition: {Message} (parameters were applied successfully)", startResult.ErrorMessage); + } + } + + return result; } catch (Exception ex) { @@ -640,6 +624,29 @@ namespace XP.Hardware.Detector.Services return null; } + /// + /// 获取当前探测器的校正能力描述 | Get correction capabilities of current detector + /// 未初始化时返回基于配置文件的默认值 + /// + public CorrectionCapabilities GetCorrectionCapabilities() + { + lock (_lock) + { + if (_detector != null) + { + return _detector.GetCorrectionCapabilities(); + } + } + + // 未初始化时从配置文件构建默认值 | Build default from config when not initialized + var config = GetCurrentConfig(); + return new CorrectionCapabilities + { + DarkFrameCount = config?.DarkCorrectionFrameCount ?? 64, + GainFrameCount = config?.GainCorrectionFrameCount ?? 64 + }; + } + /// /// 获取探测器实例或抛出异常 | Get detector instance or throw exception /// diff --git a/XP.Hardware.Detector/Services/IDetectorService.cs b/XP.Hardware.Detector/Services/IDetectorService.cs index 17c864f..d563d61 100644 --- a/XP.Hardware.Detector/Services/IDetectorService.cs +++ b/XP.Hardware.Detector/Services/IDetectorService.cs @@ -130,5 +130,11 @@ namespace XP.Hardware.Detector.Services /// /// 探测器配置,未初始化时返回 null | Detector config, null if not initialized DetectorConfig GetCurrentConfig(); + + /// + /// 获取当前探测器的校正能力描述 | Get correction capabilities of current detector + /// + /// 校正能力描述,未初始化时返回默认值 | Correction capabilities, default if not initialized + CorrectionCapabilities GetCorrectionCapabilities(); } } diff --git a/XP.Hardware.Detector/ViewModels/DetectorConfigViewModel.cs b/XP.Hardware.Detector/ViewModels/DetectorConfigViewModel.cs index 0779ccd..5ac2c47 100644 --- a/XP.Hardware.Detector/ViewModels/DetectorConfigViewModel.cs +++ b/XP.Hardware.Detector/ViewModels/DetectorConfigViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.ObjectModel; using System.Linq; using System.Windows; @@ -8,6 +8,7 @@ using Prism.Mvvm; using XP.Common.GeneralForm.Views; using XP.Common.Localization; using XP.Common.Logging.Interfaces; +using XP.Hardware.Detector.Abstractions; using XP.Hardware.Detector.Abstractions.Events; using XP.Hardware.Detector.Abstractions.Enums; using XP.Hardware.Detector.Config; @@ -420,8 +421,10 @@ namespace XP.Hardware.Detector.ViewModels /// private void OnDetectorStatusChanged(DetectorStatus status) { - // 同步连接状态:非 Uninitialized 即视为已连接 | Sync connection status: connected if not Uninitialized - IsConnected = status != DetectorStatus.Uninitialized; + // 同步连接状态:只有 Ready、Acquiring、Correcting 视为已连接 | Only Ready, Acquiring, Correcting are considered connected + IsConnected = status == DetectorStatus.Ready + || status == DetectorStatus.Acquiring + || status == DetectorStatus.Correcting; } /// @@ -476,9 +479,9 @@ namespace XP.Hardware.Detector.ViewModels } /// - /// 校正采集帧数(固定 64 帧,确保校正质量)| Correction frame count (fixed 64 frames for quality) + /// 获取校正帧数(从配置加载)| Get correction frame count (loaded from config) /// - private const int CorrectionFrameCount = 64; + private CorrectionCapabilities GetCorrectionCaps() => _detectorService.GetCorrectionCapabilities(); /// /// 执行暗场校正 | Execute dark correction @@ -500,7 +503,7 @@ namespace XP.Hardware.Detector.ViewModels var binningName = _selectedBinningIndex < BinningItems.Count ? BinningItems[_selectedBinningIndex].DisplayName : "?"; _logger?.Info("开始暗场校正,Binning={Binning},PGA={PGA},帧率={FrameRate},校正帧数={FrameCount} | Starting dark correction", - binningName, _selectedPga, _frameRate, CorrectionFrameCount); + binningName, _selectedPga, _frameRate, GetCorrectionCaps().DarkFrameCount); // 显示进度条窗口 | Show progress window var progressWindow = new ProgressWindow( @@ -536,9 +539,9 @@ namespace XP.Hardware.Detector.ViewModels return; } - // 3. 执行暗场校正(固定 64 帧)| Execute dark correction (fixed 64 frames) + // 3. 执行暗场校正 | Execute dark correction progressWindow.UpdateProgress(LocalizationHelper.Get("Detector_Progress_AcquiringDarkData"), 30); - var result = await _detectorService.DarkCorrectionAsync(CorrectionFrameCount); + var result = await _detectorService.DarkCorrectionAsync(GetCorrectionCaps().DarkFrameCount); if (result.IsSuccess) { @@ -616,7 +619,7 @@ namespace XP.Hardware.Detector.ViewModels var binningName = _selectedBinningIndex < BinningItems.Count ? BinningItems[_selectedBinningIndex].DisplayName : "?"; _logger?.Info("开始亮场校正,Binning={Binning},PGA={PGA},帧率={FrameRate},校正帧数={FrameCount} | Starting light correction", - binningName, _selectedPga, _frameRate, CorrectionFrameCount); + binningName, _selectedPga, _frameRate, GetCorrectionCaps().GainFrameCount); // 显示进度条窗口 | Show progress window var progressWindow = new ProgressWindow( @@ -643,9 +646,9 @@ namespace XP.Hardware.Detector.ViewModels } } - // 1. 执行亮场校正(固定 64 帧)| Execute light correction (fixed 64 frames) + // 1. 执行亮场校正 | Execute light correction progressWindow.UpdateProgress(LocalizationHelper.Get("Detector_Progress_AcquiringLightData"), 20); - var result = await _detectorService.GainCorrectionAsync(CorrectionFrameCount); + var result = await _detectorService.GainCorrectionAsync(GetCorrectionCaps().GainFrameCount); if (result.IsSuccess) { diff --git a/XP.Hardware.Detector/Views/DetectorConfigView.xaml b/XP.Hardware.Detector/Views/DetectorConfigView.xaml index 0891701..2a975a1 100644 --- a/XP.Hardware.Detector/Views/DetectorConfigView.xaml +++ b/XP.Hardware.Detector/Views/DetectorConfigView.xaml @@ -97,6 +97,7 @@ @@ -115,6 +116,7 @@ @@ -129,6 +131,7 @@ diff --git a/XplorePlane/App.config b/XplorePlane/App.config index acb634d..5f1707c 100644 --- a/XplorePlane/App.config +++ b/XplorePlane/App.config @@ -66,7 +66,6 @@ - @@ -78,14 +77,13 @@ - - - + +