From 9d1660270272180cd71147d6ddd53d1382643d2e Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 02 十一月 2026 18:00:14 +0800
Subject: [PATCH] merge: 并入远程 Initial commit 作为历史根节点
---
Aging.Infrastructure/Services/PowerSupplyService.cs | 543 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 543 insertions(+), 0 deletions(-)
diff --git a/Aging.Infrastructure/Services/PowerSupplyService.cs b/Aging.Infrastructure/Services/PowerSupplyService.cs
new file mode 100644
index 0000000..693a312
--- /dev/null
+++ b/Aging.Infrastructure/Services/PowerSupplyService.cs
@@ -0,0 +1,543 @@
+using System.Diagnostics;
+using Aging.Infrastructure.Contracts;
+using log4net;
+
+namespace Aging.Infrastructure.Services
+{
+ /// <summary>
+ /// 鐢垫簮閰嶇疆鍛戒护
+ /// </summary>
+ public sealed class PowerCommand
+ {
+ /// <summary>
+ /// 鐩爣鐢靛帇鍊硷紙鍙�夛紝鍗曚綅: V锛�
+ /// </summary>
+ public double? Voltage { get; set; }
+
+ /// <summary>
+ /// 鐩爣鐢垫祦闄愬埗鍊硷紙鍙�夛紝鍗曚綅: A锛�
+ /// </summary>
+ public double? CurrentLimit { get; set; }
+
+ /// <summary>
+ /// 杈撳嚭寮�鍏崇姸鎬侊紙true=ON, false=OFF, null=涓嶆敼鍙橈級
+ /// </summary>
+ public bool? Output { get; set; }
+ }
+
+ /// <summary>
+ /// 鐢垫簮鎿嶄綔缁撴灉
+ /// </summary>
+ public sealed class PowerOperationResult
+ {
+ /// <summary>
+ /// 鎿嶄綔鏄惁鎴愬姛
+ /// </summary>
+ public bool Success { get; set; }
+
+ /// <summary>
+ /// 瀹炴祴鐢靛帇鍊硷紙鍗曚綅: V锛�
+ /// </summary>
+ public double? MeasuredVoltage { get; set; }
+
+ /// <summary>
+ /// 瀹炴祴鐢垫祦鍊硷紙鍗曚綅: A锛�
+ /// </summary>
+ public double? MeasuredCurrent { get; set; }
+
+ /// <summary>
+ /// 璁惧鍘熷鍝嶅簲瀛楃涓�
+ /// </summary>
+ public string? RawResponse { get; set; }
+
+ /// <summary>
+ /// 閿欒浠g爜
+ /// </summary>
+ public string? ErrorCode { get; set; }
+
+ /// <summary>
+ /// 閿欒淇℃伅
+ /// </summary>
+ public string? ErrorMessage { get; set; }
+
+ /// <summary>
+ /// 鎿嶄綔寤惰繜锛堟绉掞級
+ /// </summary>
+ public double LatencyMs { get; set; }
+
+ /// <summary>
+ /// 鍒涘缓涓�涓垚鍔熺殑缁撴灉
+ /// </summary>
+ public static PowerOperationResult Succeed(double? voltage, double? current, string? rawResponse, double latencyMs)
+ {
+ return new PowerOperationResult
+ {
+ Success = true,
+ MeasuredVoltage = voltage,
+ MeasuredCurrent = current,
+ RawResponse = rawResponse,
+ LatencyMs = latencyMs
+ };
+ }
+
+ /// <summary>
+ /// 鍒涘缓涓�涓け璐ョ殑缁撴灉
+ /// </summary>
+ public static PowerOperationResult Failed(string errorCode, string errorMessage, double latencyMs)
+ {
+ return new PowerOperationResult
+ {
+ Success = false,
+ ErrorCode = errorCode,
+ ErrorMessage = errorMessage,
+ LatencyMs = latencyMs
+ };
+ }
+ }
+
+ /// <summary>
+ /// 鐢垫簮閰嶇疆鏈嶅姟 - 闈㈠悜 Slot 鐨勯珮灞傜數婧愭搷浣溿��
+ /// 閫氳繃 SlotDeviceMappingResolver 瑙f瀽 Slot 鍒板叿浣撹澶囩鐐圭殑鏄犲皠锛�
+ /// 鍗忚皟 ResourceManager 鍜� DeviceManager 瀹屾垚鐢垫簮閰嶇疆銆佹祴閲忓拰鐘舵�佹煡璇€��
+ /// </summary>
+ public sealed class PowerSupplyService
+ {
+ private static readonly ILog Log = LogManager.GetLogger(typeof(PowerSupplyService));
+
+ /// <summary>
+ /// 璧勬簮绠$悊鍣�
+ /// </summary>
+ private readonly IResourceManager _resourceManager;
+
+ /// <summary>
+ /// 璁惧绠$悊鍣�
+ /// </summary>
+ private readonly IDeviceManager _deviceManager;
+
+ /// <summary>
+ /// Slot-璁惧-閫氶亾鏄犲皠瑙f瀽鍣�
+ /// </summary>
+ private readonly SlotDeviceMappingResolver _slotMappingResolver;
+
+ /// <summary>
+ /// 鍒濆鍖栫數婧愰厤缃湇鍔″疄渚�
+ /// </summary>
+ /// <param name="resourceManager">璧勬簮绠$悊鍣�</param>
+ /// <param name="deviceManager">璁惧绠$悊鍣�</param>
+ /// <param name="slotMappingResolver">Slot 鏄犲皠瑙f瀽鍣�</param>
+ public PowerSupplyService(
+ IResourceManager resourceManager,
+ IDeviceManager deviceManager,
+ SlotDeviceMappingResolver slotMappingResolver)
+ {
+ _resourceManager = resourceManager ?? throw new ArgumentNullException(nameof(resourceManager));
+ _deviceManager = deviceManager ?? throw new ArgumentNullException(nameof(deviceManager));
+ _slotMappingResolver = slotMappingResolver ?? throw new ArgumentNullException(nameof(slotMappingResolver));
+ }
+
+ /// <summary>
+ /// 寮傛閰嶇疆 Slot 瀵瑰簲鐨勭數婧愬弬鏁般��
+ /// 鏍规嵁 SlotId 瑙f瀽鏄犲皠鑾峰彇璁惧绔偣锛岄獙璇佽祫婧愰绾﹀悗鍙戦�� SCPI 鍛戒护閰嶇疆鐢垫簮銆�
+ /// </summary>
+ /// <param name="slotId">Slot 鏍囪瘑绗�</param>
+ /// <param name="command">鐢垫簮閰嶇疆鍛戒护</param>
+ /// <param name="owner">鎵�鏈夎�呬护鐗�</param>
+ /// <param name="ct">鍙栨秷浠ょ墝</param>
+ /// <returns>鐢垫簮鎿嶄綔缁撴灉锛屽寘鍚祴閲忓��</returns>
+ public async Task<PowerOperationResult> ConfigureAsync(
+ string slotId, PowerCommand command, ResourceOwnerToken owner, CancellationToken ct)
+ {
+ if (string.IsNullOrWhiteSpace(slotId))
+ throw new ArgumentException("SlotId 涓嶈兘涓虹┖", nameof(slotId));
+ if (command == null)
+ throw new ArgumentNullException(nameof(command));
+ if (owner == null)
+ throw new ArgumentNullException(nameof(owner));
+
+ var stopwatch = Stopwatch.StartNew();
+
+ try
+ {
+ Log.Info($"[PowerSupplyService] 閰嶇疆鐢垫簮: Slot={slotId}, Owner={owner.OwnerId}");
+
+ // 1. 瑙f瀽 Slot 鏄犲皠
+ var endpoint = _slotMappingResolver.ResolveEndpoint(slotId, "PowerSupply");
+ if (endpoint == null)
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] Slot {slotId} 鏈壘鍒� PowerSupply 鏄犲皠");
+ return PowerOperationResult.Failed("MAPPING_NOT_FOUND",
+ $"Slot {slotId} 鏈壘鍒� PowerSupply 绫诲瀷鐨勮澶囨槧灏�", stopwatch.Elapsed.TotalMilliseconds);
+ }
+
+ var resourceKey = endpoint.ToResourceKey();
+
+ // 2. 楠岃瘉棰勭害
+ if (!_resourceManager.ValidateOwner(owner, resourceKey))
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] 鏉冮檺楠岃瘉澶辫触: Slot={slotId}, Device={endpoint.DeviceId}, Owner={owner.OwnerId}");
+ return PowerOperationResult.Failed("PERMISSION_DENIED",
+ $"鎵�鏈夎�� {owner.OwnerId} 鏈绾� Slot {slotId} 瀵瑰簲鐨勮澶� {endpoint.DeviceId} 鎴栦护鐗屽凡杩囨湡",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+
+ // 3. 鑾峰彇绉熺害
+ using var lease = await _resourceManager.AcquireOperationAsync(owner, resourceKey, ct).ConfigureAwait(false);
+
+ // 4. 鑾峰彇璁惧椹卞姩
+ var driver = _deviceManager.GetDriver(endpoint.DeviceId);
+ if (driver == null)
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] 璁惧 {endpoint.DeviceId} 椹卞姩涓嶅瓨鍦�");
+ return PowerOperationResult.Failed("DRIVER_NOT_FOUND",
+ $"璁惧 {endpoint.DeviceId} 鐨勯┍鍔ㄦ湭娉ㄥ唽", stopwatch.Elapsed.TotalMilliseconds);
+ }
+
+ // 5. 鏋勫缓骞跺彂閫� SCPI 鍛戒护
+ var scpiCommands = BuildScpiCommands(command);
+ foreach (var scpiCommand in scpiCommands)
+ {
+ Log.Info($"[PowerSupplyService] 鍙戦�� SCPI 鍛戒护: Device={endpoint.DeviceId}, Command={scpiCommand}");
+ await driver.SendCommandAsync(scpiCommand, ct).ConfigureAwait(false);
+ }
+
+ // 6. 鍥炶娴嬮噺鍊�
+ string rawResponse;
+ try
+ {
+ // 浼樺厛灏濊瘯 MEAS:ALL? 涓�娆℃�ц幏鍙栨墍鏈夋祴閲忓��
+ rawResponse = await driver.QueryAsync("MEAS:ALL?", ct).ConfigureAwait(false);
+ Log.Info($"[PowerSupplyService] MEAS:ALL? 鍝嶅簲: {rawResponse}");
+ }
+ catch
+ {
+ // 濡傛灉 MEAS:ALL? 澶辫触锛屽垎鍒煡璇㈢數鍘嬪拰鐢垫祦
+ Log.Info($"[PowerSupplyService] MEAS:ALL? 澶辫触锛屽皾璇曞垎鍒煡璇� VOLT? 鍜� CURR?");
+ var voltageResponse = await driver.QueryAsync("VOLT?", ct).ConfigureAwait(false);
+ var currentResponse = await driver.QueryAsync("CURR?", ct).ConfigureAwait(false);
+ rawResponse = $"{voltageResponse},{currentResponse}";
+ }
+
+ // 7. 瑙f瀽鍥炶鍊�
+ ParseMeasurementResponse(rawResponse, out var measuredVoltage, out var measuredCurrent);
+
+ stopwatch.Stop();
+ Log.Info($"[PowerSupplyService] 鐢垫簮閰嶇疆瀹屾垚: Slot={slotId}, Device={endpoint.DeviceId}, " +
+ $"V={measuredVoltage}, I={measuredCurrent}, 寤惰繜={stopwatch.Elapsed.TotalMilliseconds:F2}ms");
+
+ return PowerOperationResult.Succeed(measuredVoltage, measuredCurrent, rawResponse,
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (ResourceConflictException ex)
+ {
+ stopwatch.Stop();
+ Log.Error($"[PowerSupplyService] 璧勬簮鍐茬獊: Slot={slotId}, 閿欒: {ex.Message}", ex);
+ return PowerOperationResult.Failed("RESOURCE_CONFLICT", ex.Message, stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (OperationCanceledException)
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] 鐢垫簮閰嶇疆琚彇娑�: Slot={slotId}");
+ return PowerOperationResult.Failed("OPERATION_CANCELLED", "鎿嶄綔宸茶鍙栨秷",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (TimeoutException ex)
+ {
+ stopwatch.Stop();
+ Log.Error($"[PowerSupplyService] 鐢垫簮閰嶇疆瓒呮椂: Slot={slotId}, 閿欒: {ex.Message}", ex);
+ return PowerOperationResult.Failed("TIMEOUT", $"鐢垫簮閰嶇疆瓒呮椂: {ex.Message}",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (Exception ex)
+ {
+ stopwatch.Stop();
+ Log.Error($"[PowerSupplyService] 鐢垫簮閰嶇疆寮傚父: Slot={slotId}, 閿欒: {ex.Message}", ex);
+ return PowerOperationResult.Failed("UNKNOWN_ERROR", $"鐢垫簮閰嶇疆澶辫触: {ex.Message}",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ }
+
+ /// <summary>
+ /// 寮傛娴嬮噺 Slot 瀵瑰簲鐢垫簮鐨勮緭鍑哄�硷紙鐢靛帇銆佺數娴侊級銆�
+ /// 鏍规嵁 SlotId 瑙f瀽鏄犲皠鑾峰彇璁惧绔偣锛屾煡璇㈠疄鏃舵祴閲忓�笺��
+ /// </summary>
+ /// <param name="slotId">Slot 鏍囪瘑绗�</param>
+ /// <param name="owner">鎵�鏈夎�呬护鐗�</param>
+ /// <param name="ct">鍙栨秷浠ょ墝</param>
+ /// <returns>鐢垫簮鎿嶄綔缁撴灉锛屽寘鍚祴閲忓��</returns>
+ public async Task<PowerOperationResult> MeasureAsync(
+ string slotId, ResourceOwnerToken owner, CancellationToken ct)
+ {
+ if (string.IsNullOrWhiteSpace(slotId))
+ throw new ArgumentException("SlotId 涓嶈兘涓虹┖", nameof(slotId));
+ if (owner == null)
+ throw new ArgumentNullException(nameof(owner));
+
+ var stopwatch = Stopwatch.StartNew();
+
+ try
+ {
+ Log.Info($"[PowerSupplyService] 娴嬮噺鐢垫簮: Slot={slotId}, Owner={owner.OwnerId}");
+
+ // 1. 瑙f瀽 Slot 鏄犲皠
+ var endpoint = _slotMappingResolver.ResolveEndpoint(slotId, "PowerSupply");
+ if (endpoint == null)
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] Slot {slotId} 鏈壘鍒� PowerSupply 鏄犲皠");
+ return PowerOperationResult.Failed("MAPPING_NOT_FOUND",
+ $"Slot {slotId} 鏈壘鍒� PowerSupply 绫诲瀷鐨勮澶囨槧灏�", stopwatch.Elapsed.TotalMilliseconds);
+ }
+
+ var resourceKey = endpoint.ToResourceKey();
+
+ // 2. 楠岃瘉棰勭害
+ if (!_resourceManager.ValidateOwner(owner, resourceKey))
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] 鏉冮檺楠岃瘉澶辫触: Slot={slotId}, Device={endpoint.DeviceId}, Owner={owner.OwnerId}");
+ return PowerOperationResult.Failed("PERMISSION_DENIED",
+ $"鎵�鏈夎�� {owner.OwnerId} 鏈绾� Slot {slotId} 瀵瑰簲鐨勮澶� {endpoint.DeviceId} 鎴栦护鐗屽凡杩囨湡",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+
+ // 3. 鑾峰彇绉熺害
+ using var lease = await _resourceManager.AcquireOperationAsync(owner, resourceKey, ct).ConfigureAwait(false);
+
+ // 4. 鑾峰彇璁惧椹卞姩
+ var driver = _deviceManager.GetDriver(endpoint.DeviceId);
+ if (driver == null)
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] 璁惧 {endpoint.DeviceId} 椹卞姩涓嶅瓨鍦�");
+ return PowerOperationResult.Failed("DRIVER_NOT_FOUND",
+ $"璁惧 {endpoint.DeviceId} 鐨勯┍鍔ㄦ湭娉ㄥ唽", stopwatch.Elapsed.TotalMilliseconds);
+ }
+
+ // 5. 鏌ヨ娴嬮噺鍊�
+ string rawResponse;
+ try
+ {
+ rawResponse = await driver.QueryAsync("MEAS:ALL?", ct).ConfigureAwait(false);
+ }
+ catch
+ {
+ var voltageResponse = await driver.QueryAsync("VOLT?", ct).ConfigureAwait(false);
+ var currentResponse = await driver.QueryAsync("CURR?", ct).ConfigureAwait(false);
+ rawResponse = $"{voltageResponse},{currentResponse}";
+ }
+
+ // 6. 瑙f瀽鍥炶鍊�
+ ParseMeasurementResponse(rawResponse, out var measuredVoltage, out var measuredCurrent);
+
+ stopwatch.Stop();
+ Log.Info($"[PowerSupplyService] 娴嬮噺瀹屾垚: Slot={slotId}, Device={endpoint.DeviceId}, " +
+ $"V={measuredVoltage}, I={measuredCurrent}, 寤惰繜={stopwatch.Elapsed.TotalMilliseconds:F2}ms");
+
+ return PowerOperationResult.Succeed(measuredVoltage, measuredCurrent, rawResponse,
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (ResourceConflictException ex)
+ {
+ stopwatch.Stop();
+ Log.Error($"[PowerSupplyService] 璧勬簮鍐茬獊: Slot={slotId}, 閿欒: {ex.Message}", ex);
+ return PowerOperationResult.Failed("RESOURCE_CONFLICT", ex.Message, stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (OperationCanceledException)
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] 娴嬮噺鎿嶄綔琚彇娑�: Slot={slotId}");
+ return PowerOperationResult.Failed("OPERATION_CANCELLED", "鎿嶄綔宸茶鍙栨秷",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (TimeoutException ex)
+ {
+ stopwatch.Stop();
+ Log.Error($"[PowerSupplyService] 娴嬮噺鎿嶄綔瓒呮椂: Slot={slotId}, 閿欒: {ex.Message}", ex);
+ return PowerOperationResult.Failed("TIMEOUT", $"娴嬮噺鎿嶄綔瓒呮椂: {ex.Message}",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (Exception ex)
+ {
+ stopwatch.Stop();
+ Log.Error($"[PowerSupplyService] 娴嬮噺鎿嶄綔寮傚父: Slot={slotId}, 閿欒: {ex.Message}", ex);
+ return PowerOperationResult.Failed("UNKNOWN_ERROR", $"娴嬮噺鎿嶄綔澶辫触: {ex.Message}",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ }
+
+ /// <summary>
+ /// 寮傛鑾峰彇 Slot 瀵瑰簲鐢垫簮鐨勫綋鍓嶇姸鎬侊紙鐢靛帇銆佺數娴併�佽緭鍑哄紑鍏崇姸鎬侊級銆�
+ /// </summary>
+ /// <param name="slotId">Slot 鏍囪瘑绗�</param>
+ /// <param name="owner">鎵�鏈夎�呬护鐗�</param>
+ /// <param name="ct">鍙栨秷浠ょ墝</param>
+ /// <returns>鐢垫簮鎿嶄綔缁撴灉锛屽寘鍚姸鎬佷俊鎭�</returns>
+ public async Task<PowerOperationResult> GetPowerStatusAsync(
+ string slotId, ResourceOwnerToken owner, CancellationToken ct)
+ {
+ if (string.IsNullOrWhiteSpace(slotId))
+ throw new ArgumentException("SlotId 涓嶈兘涓虹┖", nameof(slotId));
+ if (owner == null)
+ throw new ArgumentNullException(nameof(owner));
+
+ var stopwatch = Stopwatch.StartNew();
+
+ try
+ {
+ Log.Info($"[PowerSupplyService] 鏌ヨ鐢垫簮鐘舵��: Slot={slotId}, Owner={owner.OwnerId}");
+
+ // 1. 瑙f瀽 Slot 鏄犲皠
+ var endpoint = _slotMappingResolver.ResolveEndpoint(slotId, "PowerSupply");
+ if (endpoint == null)
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] Slot {slotId} 鏈壘鍒� PowerSupply 鏄犲皠");
+ return PowerOperationResult.Failed("MAPPING_NOT_FOUND",
+ $"Slot {slotId} 鏈壘鍒� PowerSupply 绫诲瀷鐨勮澶囨槧灏�", stopwatch.Elapsed.TotalMilliseconds);
+ }
+
+ var resourceKey = endpoint.ToResourceKey();
+
+ // 2. 楠岃瘉棰勭害
+ if (!_resourceManager.ValidateOwner(owner, resourceKey))
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] 鏉冮檺楠岃瘉澶辫触: Slot={slotId}, Device={endpoint.DeviceId}, Owner={owner.OwnerId}");
+ return PowerOperationResult.Failed("PERMISSION_DENIED",
+ $"鎵�鏈夎�� {owner.OwnerId} 鏈绾� Slot {slotId} 瀵瑰簲鐨勮澶� {endpoint.DeviceId} 鎴栦护鐗屽凡杩囨湡",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+
+ // 3. 鑾峰彇绉熺害
+ using var lease = await _resourceManager.AcquireOperationAsync(owner, resourceKey, ct).ConfigureAwait(false);
+
+ // 4. 鑾峰彇璁惧椹卞姩
+ var driver = _deviceManager.GetDriver(endpoint.DeviceId);
+ if (driver == null)
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] 璁惧 {endpoint.DeviceId} 椹卞姩涓嶅瓨鍦�");
+ return PowerOperationResult.Failed("DRIVER_NOT_FOUND",
+ $"璁惧 {endpoint.DeviceId} 鐨勯┍鍔ㄦ湭娉ㄥ唽", stopwatch.Elapsed.TotalMilliseconds);
+ }
+
+ // 5. 鏌ヨ鐢靛帇銆佺數娴佸拰杈撳嚭鐘舵��
+ var voltageResponse = await driver.QueryAsync("VOLT?", ct).ConfigureAwait(false);
+ var currentResponse = await driver.QueryAsync("CURR?", ct).ConfigureAwait(false);
+ var outputResponse = await driver.QueryAsync("OUTP?", ct).ConfigureAwait(false);
+
+ var rawResponse = $"VOLT={voltageResponse},CURR={currentResponse},OUTP={outputResponse}";
+
+ // 6. 瑙f瀽娴嬮噺鍊�
+ ParseMeasurementResponse($"{voltageResponse},{currentResponse}",
+ out var measuredVoltage, out var measuredCurrent);
+
+ stopwatch.Stop();
+ Log.Info($"[PowerSupplyService] 鐢垫簮鐘舵�佹煡璇㈠畬鎴�: Slot={slotId}, Device={endpoint.DeviceId}, " +
+ $"V={measuredVoltage}, I={measuredCurrent}, OUTP={outputResponse}, " +
+ $"寤惰繜={stopwatch.Elapsed.TotalMilliseconds:F2}ms");
+
+ return new PowerOperationResult
+ {
+ Success = true,
+ MeasuredVoltage = measuredVoltage,
+ MeasuredCurrent = measuredCurrent,
+ RawResponse = rawResponse,
+ LatencyMs = stopwatch.Elapsed.TotalMilliseconds
+ };
+ }
+ catch (ResourceConflictException ex)
+ {
+ stopwatch.Stop();
+ Log.Error($"[PowerSupplyService] 璧勬簮鍐茬獊: Slot={slotId}, 閿欒: {ex.Message}", ex);
+ return PowerOperationResult.Failed("RESOURCE_CONFLICT", ex.Message, stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (OperationCanceledException)
+ {
+ stopwatch.Stop();
+ Log.Warn($"[PowerSupplyService] 鐘舵�佹煡璇㈣鍙栨秷: Slot={slotId}");
+ return PowerOperationResult.Failed("OPERATION_CANCELLED", "鎿嶄綔宸茶鍙栨秷",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (TimeoutException ex)
+ {
+ stopwatch.Stop();
+ Log.Error($"[PowerSupplyService] 鐘舵�佹煡璇㈣秴鏃�: Slot={slotId}, 閿欒: {ex.Message}", ex);
+ return PowerOperationResult.Failed("TIMEOUT", $"鐘舵�佹煡璇㈣秴鏃�: {ex.Message}",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ catch (Exception ex)
+ {
+ stopwatch.Stop();
+ Log.Error($"[PowerSupplyService] 鐘舵�佹煡璇㈠紓甯�: Slot={slotId}, 閿欒: {ex.Message}", ex);
+ return PowerOperationResult.Failed("UNKNOWN_ERROR", $"鐘舵�佹煡璇㈠け璐�: {ex.Message}",
+ stopwatch.Elapsed.TotalMilliseconds);
+ }
+ }
+
+ /// <summary>
+ /// 鏍规嵁鐢垫簮閰嶇疆鍛戒护鏋勫缓 SCPI 鍛戒护鍒楄〃
+ /// </summary>
+ /// <param name="command">鐢垫簮閰嶇疆鍛戒护</param>
+ /// <returns>SCPI 鍛戒护瀛楃涓插垪琛�</returns>
+ private static List<string> BuildScpiCommands(PowerCommand command)
+ {
+ var commands = new List<string>();
+
+ if (command.Voltage.HasValue)
+ {
+ commands.Add($"VOLT {command.Voltage.Value:G}");
+ }
+
+ if (command.CurrentLimit.HasValue)
+ {
+ commands.Add($"CURR {command.CurrentLimit.Value:G}");
+ }
+
+ if (command.Output.HasValue)
+ {
+ commands.Add(command.Output.Value ? "OUTP ON" : "OUTP OFF");
+ }
+
+ return commands;
+ }
+
+ /// <summary>
+ /// 瑙f瀽璁惧杩斿洖鐨勬祴閲忓�煎搷搴斿瓧绗︿覆銆�
+ /// 鏀寔鏍煎紡: "voltage,current" 鎴栧崟涓暟鍊笺��
+ /// </summary>
+ /// <param name="rawResponse">鍘熷鍝嶅簲瀛楃涓�</param>
+ /// <param name="voltage">瑙f瀽鍚庣殑鐢靛帇鍊�</param>
+ /// <param name="current">瑙f瀽鍚庣殑鐢垫祦鍊�</param>
+ private static void ParseMeasurementResponse(string rawResponse, out double? voltage, out double? current)
+ {
+ voltage = null;
+ current = null;
+
+ if (string.IsNullOrWhiteSpace(rawResponse))
+ return;
+
+ try
+ {
+ var parts = rawResponse.Split(',');
+
+ if (parts.Length >= 1 && double.TryParse(parts[0].Trim(), out var v))
+ {
+ voltage = v;
+ }
+
+ if (parts.Length >= 2 && double.TryParse(parts[1].Trim(), out var c))
+ {
+ current = c;
+ }
+ }
+ catch (Exception)
+ {
+ // 瑙f瀽澶辫触鏃朵繚鎸� null 鍊�
+ }
+ }
+ }
+}
--
Gitblit v1.9.1