using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Aging.Infrastructure.Contracts; using log4net; using PLCHelper; namespace Aging.Infrastructure.Drivers { /// /// SCPI 协议驱动适配器。 /// 封装 PLCHelper.RestTcpClient,实现统一的 IDeviceDriver 接口。 /// 用于控制支持 SCPI 命令的仪器(如电源、电子负载等)。 /// public sealed class ScpiDriverAdapter : IDeviceDriver { private static readonly ILog Log = LogManager.GetLogger(typeof(ScpiDriverAdapter)); private readonly string _ip; private readonly int _port; private RestTcpClient? _client; private bool _disposed; private readonly Stopwatch _latencyStopwatch = new Stopwatch(); private double _lastLatencyMs; private string _lastError = string.Empty; private DateTime? _lastErrorTime; private int _reconnectCount; /// public string DeviceId { get; } /// public bool IsConnected => _client != null; /// public event EventHandler? ConnectionChanged; /// /// 初始化 SCPI 协议驱动适配器 /// /// 设备唯一标识符 /// 目标 IP 地址 /// 目标端口号 public ScpiDriverAdapter(string deviceId, string ip, int port) { DeviceId = deviceId ?? throw new ArgumentNullException(nameof(deviceId)); _ip = ip ?? throw new ArgumentNullException(nameof(ip)); _port = port; } /// public Task ConnectAsync(CancellationToken ct) { ThrowIfDisposed(); Log.Info($"[SCPI] 设备 {DeviceId} 正在连接 {_ip}:{_port}..."); try { _client = new RestTcpClient(_ip, _port); _client.ReceiveTimeout = 5000; _client.ConnectServer(); // 发送复位命令验证连接 if (_client.Request("*RST", out string response, out string errMsg)) { Log.Info($"[SCPI] 设备 {DeviceId} 复位响应: {response}"); } else { Log.Warn($"[SCPI] 设备 {DeviceId} 复位失败: {errMsg}"); } _lastError = string.Empty; Log.Info($"[SCPI] 设备 {DeviceId} 已成功连接到 {_ip}:{_port}"); OnConnectionChanged(true, "连接成功"); } catch (Exception ex) { _lastError = ex.Message; _lastErrorTime = DateTime.Now; Log.Error($"[SCPI] 设备 {DeviceId} 连接异常: {ex.Message}", ex); _client?.Dispose(); _client = null; throw; } return Task.CompletedTask; } /// public Task DisconnectAsync() { ThrowIfDisposed(); Log.Info($"[SCPI] 设备 {DeviceId} 正在断开连接..."); try { _client?.Dispose(); _client = null; Log.Info($"[SCPI] 设备 {DeviceId} 已断开连接"); OnConnectionChanged(false, "主动断开"); } catch (Exception ex) { _lastError = ex.Message; _lastErrorTime = DateTime.Now; Log.Error($"[SCPI] 设备 {DeviceId} 断开连接异常: {ex.Message}", ex); _client = null; } return Task.CompletedTask; } /// public Task SendCommandAsync(string command, CancellationToken ct) { ThrowIfDisposed(); if (!IsConnected) throw new InvalidOperationException("[SCPI] 设备未连接"); _latencyStopwatch.Restart(); try { Log.Debug($"[SCPI] 设备 {DeviceId} 发送命令: {command}"); // SCPI 命令以 \r 结尾(RestTcpClient 协议自动处理) bool success = _client.Request(command, out string response, out string errMsg); _latencyStopwatch.Stop(); _lastLatencyMs = _latencyStopwatch.Elapsed.TotalMilliseconds; if (!success) { _lastError = errMsg; _lastErrorTime = DateTime.Now; throw new InvalidOperationException($"[SCPI] 命令执行失败: {errMsg}"); } Log.Debug($"[SCPI] 设备 {DeviceId} 命令响应: {response} (延迟 {_lastLatencyMs:F2}ms)"); return Task.FromResult(response); } catch (Exception ex) { _latencyStopwatch.Stop(); _lastLatencyMs = _latencyStopwatch.Elapsed.TotalMilliseconds; _lastError = ex.Message; _lastErrorTime = DateTime.Now; Log.Error($"[SCPI] 设备 {DeviceId} 发送命令失败: {ex.Message}", ex); throw; } } /// public Task QueryAsync(string query, CancellationToken ct) { ThrowIfDisposed(); if (!IsConnected) throw new InvalidOperationException("[SCPI] 设备未连接"); _latencyStopwatch.Restart(); try { Log.Debug($"[SCPI] 设备 {DeviceId} 发送查询: {query}"); // 发送查询命令并等待回读(如 "MEAS:CURR?") bool success = _client.Request(query, out string response, out string errMsg); _latencyStopwatch.Stop(); _lastLatencyMs = _latencyStopwatch.Elapsed.TotalMilliseconds; if (!success) { _lastError = errMsg; _lastErrorTime = DateTime.Now; throw new TimeoutException($"[SCPI] 查询超时或失败: {errMsg}"); } Log.Debug($"[SCPI] 设备 {DeviceId} 查询响应: {response} (延迟 {_lastLatencyMs:F2}ms)"); return Task.FromResult(response); } catch (Exception ex) { _latencyStopwatch.Stop(); _lastLatencyMs = _latencyStopwatch.Elapsed.TotalMilliseconds; _lastError = ex.Message; _lastErrorTime = DateTime.Now; Log.Error($"[SCPI] 设备 {DeviceId} 查询失败: {ex.Message}", ex); throw; } } /// public DeviceDriverStatus GetStatus() { return new DeviceDriverStatus { IsConnected = IsConnected, IsHealthy = IsConnected && string.IsNullOrEmpty(_lastError), LastError = _lastError, LastErrorTime = _lastErrorTime, LatencyMs = _lastLatencyMs, ReconnectCount = _reconnectCount }; } /// public void Dispose() { if (_disposed) return; _disposed = true; try { _client?.Dispose(); } catch (Exception ex) { Log.Error($"[SCPI] 设备 {DeviceId} 释放资源异常: {ex.Message}", ex); } } /// /// 触发连接状态变化事件 /// private void OnConnectionChanged(bool isConnected, string reason) { ConnectionChanged?.Invoke(this, new DeviceConnectionEventArgs { DeviceId = DeviceId, IsConnected = isConnected, Reason = reason }); if (!isConnected) { _reconnectCount++; } } /// /// 检查是否已释放 /// private void ThrowIfDisposed() { if (_disposed) throw new ObjectDisposedException(nameof(ScpiDriverAdapter)); } } }