diff --git a/DeviceCommand/Devices/Chroma61800.cs b/DeviceCommand/Devices/Chroma61800.cs
new file mode 100644
index 0000000..95d697e
--- /dev/null
+++ b/DeviceCommand/Devices/Chroma61800.cs
@@ -0,0 +1,166 @@
+using Common.Attributes;
+using DeviceCommand.Base;
+using Model.Models;
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Devices
+{
+ [ACPCommand]
+ public class Chroma61800 : Tcp
+ {
+ // Chroma SCPI 默认使用 \n 作为结束符
+ private const string ScpiDelimiter = "\n";
+
+ public Chroma61800(TcpConfig config) : base(config)
+ {
+ }
+
+ #region 1. 基础系统控制
+
+ public virtual async Task 清除错误队列(CancellationToken ct = default)
+ {
+ await SendAsync($"*CLS{ScpiDelimiter}", ct);
+ }
+
+ #endregion
+
+ #region 2. LIST 模式初始化
+
+ ///
+ /// 初始化 LIST 模式的三相独立编辑环境
+ ///
+ /// 循环次数,0代表无限循环
+ public virtual async Task 初始化三相List模式(int loopCount = 0, CancellationToken ct = default)
+ {
+ await SendAsync($"INST:PHAS THRE{ScpiDelimiter}", ct); // 选择三相模式
+ await SendAsync($"INST:EDIT EACH{ScpiDelimiter}", ct); // 选择编辑电压方式为分别编辑
+ await SendAsync($"LIST:COUN {loopCount}{ScpiDelimiter}", ct); // 循环次数设定
+ await SendAsync($"LIST:TRIG AUTO{ScpiDelimiter}", ct); // 设定触发方式
+ await SendAsync($"LIST:BASE TIME{ScpiDelimiter}", ct); // 选择执行时间类别
+ }
+
+ #endregion
+
+ #region 3. LIST 步阶参数配置
+
+ ///
+ /// 配置单相的 LIST 序列参数
+ /// 传入的数组长度必须保持一致,代表 LIST 的每个 Step(SEQ)
+ ///
+ /// 相位 (1: L1, 2: L2, 3: L3)
+ /// 各步起始角度 (如 [0, 0, 0])
+ /// 各步交流起始电压 (如 [230, 11.5, 230])
+ /// 各步交流结束电压 (如 [230, 11.5, 230])
+ /// 各步直流起始电压
+ /// 各步直流结束电压
+ /// 各步起始频率
+ /// 各步结束频率
+ /// 各步执行时间(单位: 毫秒)
+ public virtual async Task 配置单相List序列(
+ int phase,
+ double[] degrees,
+ double[] vacStart, double[] vacEnd,
+ double[] vdcStart, double[] vdcEnd,
+ double[] freqStart, double[] freqEnd,
+ double[] dwellTimeMs,
+ CancellationToken ct = default)
+ {
+ if (phase < 1 || phase > 3) throw new ArgumentOutOfRangeException(nameof(phase), "相位必须为 1, 2, 或 3");
+
+ // 选择相位并设置为正弦波
+ await SendAsync($"INST:NSEL {phase}{ScpiDelimiter}", ct);
+ await SendAsync($"FUNC:SHAP:A SINE{ScpiDelimiter}", ct);
+
+ // 转换数组为 SCPI 需要的逗号分隔字符串
+ string strDegrees = JoinParameters(degrees);
+ string strVacStart = JoinParameters(vacStart);
+ string strVacEnd = JoinParameters(vacEnd);
+ string strVdcStart = JoinParameters(vdcStart);
+ string strVdcEnd = JoinParameters(vdcEnd);
+ string strFreqStart = JoinParameters(freqStart);
+ string strFreqEnd = JoinParameters(freqEnd);
+ string strDwell = JoinParameters(dwellTimeMs);
+
+ // 下发序列参数
+ // 注意 Chroma 部分指令是 DEGR,部分固件版本是 DEGRee,这里统一使用简写 DEGR,兼容性最好
+ await SendAsync($"LIST:DEGR {strDegrees}{ScpiDelimiter}", ct);
+ await SendAsync($"LIST:VOLT:AC:STAR {strVacStart}{ScpiDelimiter}", ct);
+ await SendAsync($"LIST:VOLT:AC:END {strVacEnd}{ScpiDelimiter}", ct);
+ await SendAsync($"LIST:VOLT:DC:STAR {strVdcStart}{ScpiDelimiter}", ct);
+ await SendAsync($"LIST:VOLT:DC:END {strVdcEnd}{ScpiDelimiter}", ct);
+ await SendAsync($"LIST:FREQ:STAR {strFreqStart}{ScpiDelimiter}", ct);
+ await SendAsync($"LIST:FREQ:END {strFreqEnd}{ScpiDelimiter}", ct);
+ await SendAsync($"LIST:DWEL {strDwell}{ScpiDelimiter}", ct);
+ }
+
+ ///
+ /// 辅助方法:将 double 数组转换为逗号分隔的字符串,确保小数点格式正确
+ ///
+ private string JoinParameters(double[] values)
+ {
+ return string.Join(",", values.Select(v => v.ToString("0.###", CultureInfo.InvariantCulture)));
+ }
+
+ #endregion
+
+ #region 4. LIST 触发与状态监控
+
+ ///
+ /// 切换到 LIST 模式并触发输出
+ ///
+ public virtual async Task 启动List输出(CancellationToken ct = default)
+ {
+ await SendAsync($"OUTP:MODE LIST{ScpiDelimiter}", ct);
+ await SendAsync($"TRIG ON{ScpiDelimiter}", ct);
+ }
+
+ ///
+ /// 查询 LIST 序列是否正在运行
+ ///
+ public virtual async Task 查询List是否运行中(CancellationToken ct = default)
+ {
+ string state = await WriteReadAsync($"TRIG:STATE?{ScpiDelimiter}", ScpiDelimiter, ct);
+ state = state?.Trim().ToUpper();
+ return state == "ON" || state == "1";
+ }
+
+ ///
+ /// 阻塞异步等待直到 LIST 序列执行完毕 (带安全超时保护)
+ ///
+ /// 最大等待超时时间(建议比实际LIST总时长多5-10秒)
+ public virtual async Task 等待List执行结束(int timeoutMs = 60000, CancellationToken ct = default)
+ {
+ // 给仪器留出响应触发的时间
+ await Task.Delay(500, ct);
+
+ Stopwatch sw = Stopwatch.StartNew();
+ bool isRunning = true;
+
+ while (isRunning)
+ {
+ ct.ThrowIfCancellationRequested();
+
+ if (sw.ElapsedMilliseconds > timeoutMs)
+ {
+ throw new TimeoutException($"等待 LIST 执行结束超时 ({timeoutMs} ms)。");
+ }
+
+ // 读取当前状态
+ isRunning = await 查询List是否运行中(ct);
+
+ if (isRunning)
+ {
+ // 还在运行,适当休眠后继续轮询,避免总线阻塞
+ await Task.Delay(500, ct);
+ }
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file