using Common.Attributes; using DeviceCommand.Base; using Logger; using System.Globalization; using System.Threading; using System.Threading.Tasks; namespace DeviceCommand.Device { [BOBCommand] public class SQ0030G1D : Tcp { public SQ0030G1D(string ip, int port, int sendTimeout, int receiveTimeout) { ConfigureDevice(ip, port, sendTimeout, receiveTimeout); } #region 心跳 private CancellationTokenSource _cancellationTokenSource; private Task? _heartbeatTask; private const int HeartbeatInterval = 3000; public bool IsActive = false; public int ReConnectionAttempts = 0; public const int MaxReconnectAttempts = 10; public override async Task ConnectAsync(CancellationToken ct = default) { await _commLock.WaitAsync(ct); try { if (TcpClient != null && !TcpClient.Connected) TcpClient = new(); if (TcpClient.Connected) { return true; } await TcpClient.ConnectAsync(IPAddress, Port, ct); IsActive = true; StartHeartbeat(); return true; } catch (Exception ex) { return false; } finally { _commLock.Release(); } } public override void Close() { if (!TcpClient.Connected) { throw new InvalidOperationException("TCP 没有连接成功"); } if (TcpClient.Connected) { TcpClient.Close(); StopHeartbeat(); } } // 启动设备的心跳 public void StartHeartbeat() { if (_heartbeatTask != null) return; if (_cancellationTokenSource == null || _cancellationTokenSource.IsCancellationRequested) _cancellationTokenSource = new(); _heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token)); } // 停止设备的心跳 public void StopHeartbeat() { IsActive = false; _cancellationTokenSource.Cancel(); _heartbeatTask = null; } private async Task HeartbeatLoop(CancellationToken ct) { while (!ct.IsCancellationRequested) { await Task.Delay(HeartbeatInterval, ct); try { await 设置远程控制(); } catch (Exception ex) { IsActive = false; ReConnectionAttempts++; if (MaxReconnectAttempts < ReConnectionAttempts) { StopHeartbeat(); return; } await ReconnectDevice(ct); } } } private async Task ReconnectDevice(CancellationToken ct) { try { bool resultConnect = await ConnectAsync(ct); if (resultConnect) { ReConnectionAttempts = 0; } } catch (Exception ex) { } } #endregion // ===================== 基础封装 ===================== protected virtual Task 写命令(string cmd, CancellationToken ct = default) => SendAsync(cmd + "\n", ct); protected virtual async Task 查询命令(string cmd, CancellationToken ct = default) { await SendAsync(cmd + "\n", ct); return await ReadAsync(ct: ct); } // ===================== 1. 基础控制 ===================== public async Task 启动电源() { await 写命令($"OUTPut 1\n"); } public async Task 关闭电源() { await 写命令($"OUTPut 0\n"); } public virtual Task 获取设备ID(CancellationToken ct = default) => 查询命令("*IDN?", ct); public virtual Task 重置设备(CancellationToken ct = default) => 写命令("*RST", ct); public virtual Task 设置远程控制(CancellationToken ct = default) => 写命令("SYST:REM", ct); public virtual Task 设置本地控制(CancellationToken ct = default) => 写命令("SYST:LOC", ct); public virtual Task 设置输出状态(bool on, CancellationToken ct = default) => 写命令($"OUTP:STAT {(on ? "ON" : "OFF")}", ct); public virtual async Task 获取输出状态(CancellationToken ct = default) => (await 查询命令("OUTP:STAT?", ct)).Trim().ToUpper() == "ON"; // ===================== 2. 电压/频率控制 ===================== public virtual Task 设置输出电压(double value, CancellationToken ct = default) => 写命令($"VOLT {value}", ct); public virtual async Task 获取输出电压(CancellationToken ct = default) => double.Parse((await 查询命令("VOLT?", ct)).Replace("V", ""), CultureInfo.InvariantCulture); public virtual async Task 获取输出频率(CancellationToken ct = default) => double.Parse((await 查询命令("FREQ?", ct)).Replace("Hz", ""), CultureInfo.InvariantCulture); // ===================== 3. 保护 ===================== public virtual Task 设置过压保护(double v, CancellationToken ct = default) => 写命令($"VOLT:PROT {v}", ct); public virtual async Task 获取过压保护(CancellationToken ct = default) => double.Parse((await 查询命令("VOLT:PROT?", ct)).Replace("V", ""), CultureInfo.InvariantCulture); public virtual Task 设置过流保护(double a, CancellationToken ct = default) => 写命令($"CURR:PROT {a}", ct); public virtual async Task 获取过流保护(CancellationToken ct = default) => double.Parse((await 查询命令("CURR:PROT?", ct)).Replace("A", ""), CultureInfo.InvariantCulture); public virtual Task 清除保护(CancellationToken ct = default) => 写命令("SYST:PROT:CLE", ct); // ===================== 4. 测量 ===================== public virtual async Task 测量输出电压(CancellationToken ct = default) => double.Parse((await 查询命令("MEAS:VOLT?", ct)).Replace("V", ""), CultureInfo.InvariantCulture); public virtual async Task 测量输出电流(CancellationToken ct = default) => double.Parse((await 查询命令("MEAS:CURR?", ct)).Replace("A", ""), CultureInfo.InvariantCulture); public virtual async Task 测量输出功率(CancellationToken ct = default) => double.Parse((await 查询命令("MEAS:POW?", ct)).Replace("W", ""), CultureInfo.InvariantCulture); public virtual async Task<(double volt, double curr, double pow)> 测量所有参数(CancellationToken ct = default) { var parts = (await 查询命令("MEAS:ARR?", ct)).Split(','); return ( double.Parse(parts[0].Replace("V", ""), CultureInfo.InvariantCulture), double.Parse(parts[1].Replace("A", ""), CultureInfo.InvariantCulture), double.Parse(parts[2].Replace("W", ""), CultureInfo.InvariantCulture) ); } // 切换到远程控制模式 public virtual Task 设置远程控制模式(CancellationToken ct = default) => 写命令("SYST:REM", ct); // 切换到本地控制模式 public virtual Task 设置本地控制模式(CancellationToken ct = default) => 写命令("SYST:LOC", ct); // 设定三相电压高低档 public virtual Task 设置三相电压高低档(int range, CancellationToken ct = default) => 写命令($"OUTP:RANG {range}", ct); // 设定高低档:166(低档)/333(高档) // 设定通用输出电压 public virtual Task 设置通用输出电压(double value, CancellationToken ct = default) => 写命令($"VOLT {value}", ct); // 设定三相输出电压 public virtual Task 设置三相输出电压(double U, double V, double W, CancellationToken ct = default) => 写命令($"VOLT:PHAS A, {U}, B, {V}, C, {W}", ct); // 设定输出频率 public virtual Task 设置输出频率(double freq, CancellationToken ct = default) => 写命令($"FREQ {freq}", ct); // 设定步阶输出电压 public virtual Task 设置步阶输出电压(double targetVoltage, double stepTime, CancellationToken ct = default) => 写命令($"TRIG:TRAN:VOLT:STEP {targetVoltage}, {stepTime}", ct); // 设定步阶输出频率 public virtual Task 设置步阶输出频率(double targetFrequency, double stepTime, CancellationToken ct = default) => 写命令($"TRIG:TRAN:FREQ:STEP {targetFrequency}, {stepTime}", ct); // 设定渐变输出电压 public virtual Task 设置渐变输出电压(double startVoltage, double endVoltage, double sweepTime, CancellationToken ct = default) => 写命令($"TRIG:TRAN:VOLT:SWEEP {startVoltage}, {endVoltage}, {sweepTime}", ct); // 设定渐变输出频率 public virtual Task 设置渐变输出频率(double startFreq, double endFreq, double sweepTime, CancellationToken ct = default) => 写命令($"TRIG:TRAN:FREQ:SWEEP {startFreq}, {endFreq}, {sweepTime}", ct); // 设定软件启动功能起始电压与额定电压 public virtual Task 设置软件启动功能起始电压与额定电压(double startVoltage, double ratedVoltage, CancellationToken ct = default) => 写命令($"PON:VOLT {startVoltage}, {ratedVoltage}", ct); // 设定软件启动功能起始电压与起始频率 public virtual Task 设置软件启动功能起始电压与起始频率(double startVoltage, double startFrequency, CancellationToken ct = default) => 写命令($"PON:FREQ {startVoltage}, {startFrequency}", ct); } }