命令树优化,测试编辑区域优化

This commit is contained in:
“hsc”
2026-08-27 10:50:10 +08:00
parent 99ac3f2b8d
commit e144dc78a7
24 changed files with 1520 additions and 338 deletions
+12 -3
View File
@@ -11,20 +11,29 @@ using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
/// <summary>
/// 负载 一对三
/// ANEVH80 电子负载一对三控制),基于 TCP 通信,使用 SCPI 指令集。
/// 用于被测产品的放电/带载测试,可模拟真实负载工况。
/// </summary>
[ACPCommand]
public class ANEVH80 : Tcp
{
// Chroma SCPI 默认使用 \n 作为结束符
// SCPI 指令默认使用 \n 作为结束符
private const string ScpiDelimiter = "\n";
/// <summary>
/// 构造函数,初始化 TCP 连接配置。
/// </summary>
/// <param name="config">TCP 连接配置(IP、端口等)</param>
public ANEVH80(TcpConfig config) : base(config)
{
}
/// <summary>
/// 占位符,可能的操作先占位
/// 占位符方法,预留后续负载控制操作(如设置负载模式、设置电流等)。
/// 当前实现为查询频率测量值。
/// </summary>
/// <param name="ct">异步取消令牌</param>
/// <returns>查询到的频率值,解析失败返回 0.0</returns>
public virtual async Task<double> (CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:FREQ?{ScpiDelimiter}", ScpiDelimiter, ct);
+52 -26
View File
@@ -3,6 +3,7 @@ using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -21,10 +22,27 @@ namespace DeviceCommand.Devices
{
}
/// <summary>
/// 从设备返回的 SCPI 响应字符串中提取数值部分并转换为 double。
/// 支持科学计数法(如 2.48E-03),结果保留两位小数。
/// </summary>
/// <param name="raw">设备返回的原始字符串</param>
/// <returns>提取到的数值(保留两位小数),解析失败时返回 0</returns>
private static double ExtractDouble(string raw)
{
if (string.IsNullOrWhiteSpace(raw)) return 0;
// 从响应中提取第一个数值(含正负号、小数点、科学计数法),可自动忽略单位后缀与命令头
var match = Regex.Match(raw, @"[+-]?(?:\d+\.?\d*|\.\d+)(?:[Ee][+-]?\d+)?");
return match.Success && double.TryParse(match.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double val)
? Math.Round(val, 2)
: 0;
}
#region 1.
/// <summary>
/// 清除错误队列 (*CLS)[cite: 1]
/// 清除错误队列 (*CLS)
/// </summary>
public virtual async Task Async(CancellationToken ct = default)
{
@@ -32,7 +50,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 重设仪器为初始状态 (*RST)[cite: 1]
/// 重设仪器为初始状态 (*RST)
/// </summary>
public virtual async Task Async(CancellationToken ct = default)
{
@@ -40,7 +58,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 查询仪器识别码 (*IDN?)[cite: 1]
/// 查询仪器识别码 (*IDN?)
/// </summary>
public virtual async Task<string> Async(CancellationToken ct = default)
{
@@ -49,10 +67,10 @@ namespace DeviceCommand.Devices
#endregion
#region 2. (OUTPut )[cite: 1]
#region 2. (OUTPut )
/// <summary>
/// 设置输出开关状态 (OUTP ON / OFF)[cite: 1]
/// 设置输出开关状态 (OUTP ON / OFF)
/// </summary>
/// <param name="isOn">true: 开启输出, false: 关闭输出</param>
public virtual async Task Async(bool isOn, CancellationToken ct = default)
@@ -62,7 +80,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置输出耦合模式 (OUTP:COUP AC | DC | ACDC)[cite: 1]
/// 设置输出耦合模式 (OUTP:COUP AC | DC | ACDC)
/// </summary>
public virtual async Task Async(string couplingMode, CancellationToken ct = default)
{
@@ -71,7 +89,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置输出继电器状态 (OUTP:REL ON | OFF)[cite: 1]
/// 设置输出继电器状态 (OUTP:REL ON | OFF)
/// </summary>
public virtual async Task Async(bool isOn, CancellationToken ct = default)
{
@@ -81,10 +99,10 @@ namespace DeviceCommand.Devices
#endregion
#region 3. (SOURCE )[cite: 1]
#region 3. (SOURCE )
/// <summary>
/// 设置交流电压 (VOLT:AC)[cite: 1]
/// 设置交流电压 (VOLT:AC)
/// </summary>
/// <param name="voltage">电压值 (0 ~ 300V 或高压选配范围)</param>
public virtual async Task Async(double voltage, CancellationToken ct = default)
@@ -94,7 +112,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置直流电压 (VOLT:DC)[cite: 1]
/// 设置直流电压 (VOLT:DC)
/// </summary>
public virtual async Task Async(double voltage, CancellationToken ct = default)
{
@@ -103,7 +121,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置输出频率 (FREQ)[cite: 1]
/// 设置输出频率 (FREQ)
/// </summary>
/// <param name="frequency">频率值 (Hz)</param>
public virtual async Task Async(double frequency, CancellationToken ct = default)
@@ -113,7 +131,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置波形选择 (FUNC:SHAP:A SINE / SQUA / CSIN 等)[cite: 1]
/// 设置波形选择 (FUNC:SHAP:A SINE / SQUA / CSIN 等)
/// </summary>
public virtual async Task Async(string shape, CancellationToken ct = default)
{
@@ -122,10 +140,10 @@ namespace DeviceCommand.Devices
#endregion
#region 4. (INST & PHASE )[cite: 1]
#region 4. (INST & PHASE )
/// <summary>
/// 设置单/三相工作模式 (INST:PHAS THREE / SINGLE)[cite: 1]
/// 设置单/三相工作模式 (INST:PHAS THREE / SINGLE)
/// </summary>
/// <param name="isThreePhase">true: 三相模式, false: 单相模式</param>
public virtual async Task Async(bool isThreePhase, CancellationToken ct = default)
@@ -135,7 +153,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置三相模式下的相互关系 (PHASE:THREE INDEPEND / SAMEFREQ / BALANCE)[cite: 1]
/// 设置三相模式下的相互关系 (PHASE:THREE INDEPEND / SAMEFREQ / BALANCE)
/// </summary>
public virtual async Task Async(string relation, CancellationToken ct = default)
{
@@ -144,7 +162,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置输出开启相位角 (PHASE:ON)[cite: 1]
/// 设置输出开启相位角 (PHASE:ON)
/// </summary>
public virtual async Task Async(double degree, CancellationToken ct = default)
{
@@ -153,7 +171,7 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置输出关闭相位角 (PHASE:OFF)[cite: 1]
/// 设置输出关闭相位角 (PHASE:OFF)
/// </summary>
public virtual async Task Async(double degree, CancellationToken ct = default)
{
@@ -163,42 +181,50 @@ namespace DeviceCommand.Devices
#endregion
#region 5. (MEASure )[cite: 1]
#region 5. (MEASure )
/// <summary>
/// 查询交流电压均方根值 (MEAS:VOLT:AC?)[cite: 1]
/// 查询交流电压均方根值 (MEAS:VOLT:AC?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>交流电压均方根值 (单位: V,保留两位小数)</returns>
public virtual async Task<double> Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:VOLT:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
return double.TryParse(resp, NumberStyles.Any, CultureInfo.InvariantCulture, out double val) ? val : 0.0;
return ExtractDouble(resp);
}
/// <summary>
/// 查询交流电流均方根值 (MEAS:CURR:AC?)[cite: 1]
/// 查询交流电流均方根值 (MEAS:CURR:AC?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>交流电流均方根值 (单位: A,保留两位小数)</returns>
public virtual async Task<double> Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:CURR:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
return double.TryParse(resp, NumberStyles.Any, CultureInfo.InvariantCulture, out double val) ? val : 0.0;
return ExtractDouble(resp);
}
/// <summary>
/// 查询输出频率 (MEAS:FREQ?)[cite: 1]
/// 查询输出频率 (MEAS:FREQ?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>输出频率值 (单位: Hz,保留两位小数)</returns>
public virtual async Task<double> Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:FREQ?{ScpiDelimiter}", ScpiDelimiter, ct);
return double.TryParse(resp, NumberStyles.Any, CultureInfo.InvariantCulture, out double val) ? val : 0.0;
return ExtractDouble(resp);
}
/// <summary>
/// 查询真实输出功率 (MEAS:POW:AC?)[cite: 1]
/// 查询真实输出功率 (MEAS:POW:AC?)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>真实输出功率值 (单位: W,保留两位小数)</returns>
public virtual async Task<double> Async(CancellationToken ct = default)
{
string resp = await WriteReadAsync($"MEAS:POW:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
return double.TryParse(resp, NumberStyles.Any, CultureInfo.InvariantCulture, out double val) ? val : 0.0;
return ExtractDouble(resp);
}
#endregion
+137 -19
View File
@@ -3,6 +3,7 @@ using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -45,33 +46,74 @@ namespace DeviceCommand.Devices
#endregion
/// <summary>
/// 信号发生器 (DG1000Z 系列) 一拖三,支持波形输出与频率计测量
/// </summary>
[ACPCommand]
public class DG1000Z : Tcp
{
// 使用换行符 \n (ASCII 0x0A) 作为 SCPI 结束符
private const string ScpiDelimiter = "\n";
/// <summary>
/// 构造函数:传入 <see cref="TcpConfig"/> 一次性初始化信号发生器通信参数
/// </summary>
public DG1000Z(TcpConfig config) : base(config)
{
}
/// <summary>
/// 从设备返回的 SCPI 响应字符串中提取数值部分并转换为 double。
/// 支持科学计数法(如 2.48E-03),结果保留两位小数。
/// </summary>
/// <param name="raw">设备返回的原始字符串</param>
/// <returns>提取到的数值(保留两位小数),解析失败时返回 0</returns>
private static double ExtractDouble(string raw)
{
if (string.IsNullOrWhiteSpace(raw)) return 0;
// 从响应中提取第一个数值(含正负号、小数点、科学计数法),可自动忽略单位后缀与命令头
var match = Regex.Match(raw, @"[+-]?(?:\d+\.?\d*|\.\d+)(?:[Ee][+-]?\d+)?");
return match.Success && double.TryParse(match.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double val)
? Math.Round(val, 2)
: 0;
}
#region 1. IEEE 488.2
/// <summary>
/// 清除标准事件状态寄存器和错误队列 (*CLS)
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*CLS{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询设备识别信息 (*IDN? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>设备标识字符串 (制造商, 型号, 序列号, 固件版本)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 重设仪器为初始状态 (*RST)
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*RST{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询仪器支持的 SCPI 版本 (SYSTem:VERSion? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>SCPI 版本号字符串</returns>
public virtual async Task<string> SCPI版本(CancellationToken ct = default)
{
return await WriteReadAsync($":SYSTem:VERSion?{ScpiDelimiter}", ScpiDelimiter, ct);
@@ -82,16 +124,23 @@ namespace DeviceCommand.Devices
#region 2. (CH1 / CH2)
/// <summary>
/// 打开或关闭指定通道的输出
/// 打开或关闭指定通道的输出 (OUTPut 指令)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="开启">true为开启,false为关闭</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int = 1, bool = true, CancellationToken ct = default)
{
string = ? "ON" : "OFF";
await SendAsync($":OUTPut{通道号}:STATe {参数}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询指定通道的输出开关状态 (OUTPut:STATe? 指令)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="ct">取消令牌</param>
/// <returns>通道输出状态字符串 (ON / OFF)</returns>
public virtual async Task<string> (int = 1, CancellationToken ct = default)
{
return await WriteReadAsync($":OUTPut{通道号}:STATe?{ScpiDelimiter}", ScpiDelimiter, ct);
@@ -104,51 +153,84 @@ namespace DeviceCommand.Devices
/// <summary>
/// 设置指定通道的波形类型 (如正弦波、方波等)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="波形">波形类型枚举,默认正弦波</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int = 1, SignalWaveform = SignalWaveform.SINusoid, CancellationToken ct = default)
{
await SendAsync($":SOURce{通道号}:FUNCtion:SHAPe {波形}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置指定通道的输出频率 (单位: Hz)
/// 设置指定通道的输出频率 (SOURce:FREQuency 指令)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="频率Hz">输出频率值 (单位: Hz),默认 1000</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int = 1, double Hz = 1000, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:FREQuency {1:F2}{2}", , Hz, ScpiDelimiter);
await SendAsync(cmd, ct);
}
public virtual async Task<string> (int = 1, CancellationToken ct = default)
/// <summary>
/// 查询指定通道的当前输出频率 (SOURce:FREQuency? 指令)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="ct">取消令牌</param>
/// <returns>输出频率值 (单位: Hz,保留两位小数)</returns>
public virtual async Task<double> (int = 1, CancellationToken ct = default)
{
return await WriteReadAsync($":SOURce{通道号}:FREQuency?{ScpiDelimiter}", ScpiDelimiter, ct);
string resp = await WriteReadAsync($":SOURce{通道号}:FREQuency?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 设置指定通道的输出幅度 (单位: Vpp,峰峰值)
/// 设置指定通道的输出幅度 (SOURce:VOLTage:AMPLitude 指令)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="幅度Vpp">输出幅度 (单位: Vpp 峰峰值),默认 5</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int = 1, double Vpp = 5, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:VOLTage:AMPLitude {1:F2}{2}", , Vpp, ScpiDelimiter);
await SendAsync(cmd, ct);
}
public virtual async Task<string> (int = 1, CancellationToken ct = default)
/// <summary>
/// 查询指定通道的当前输出幅度 (SOURce:VOLTage:AMPLitude? 指令)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="ct">取消令牌</param>
/// <returns>输出幅度 (单位: Vpp,保留两位小数)</returns>
public virtual async Task<double> (int = 1, CancellationToken ct = default)
{
return await WriteReadAsync($":SOURce{通道号}:VOLTage:AMPLitude?{ScpiDelimiter}", ScpiDelimiter, ct);
string resp = await WriteReadAsync($":SOURce{通道号}:VOLTage:AMPLitude?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
/// <summary>
/// 设置指定通道的直流偏移电压 (单位: Vdc)
/// 设置指定通道的直流偏移电压 (SOURce:VOLTage:OFFSet 指令)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="偏移Vdc">直流偏移电压 (单位: Vdc),默认 0</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int = 1, double Vdc = 0, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:VOLTage:OFFSet {1:F2}{2}", , Vdc, ScpiDelimiter);
await SendAsync(cmd, ct);
}
public virtual async Task<string> (int = 1, CancellationToken ct = default)
/// <summary>
/// 查询指定通道的当前直流偏移电压 (SOURce:VOLTage:OFFSet? 指令)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="ct">取消令牌</param>
/// <returns>直流偏移电压 (单位: Vdc,保留两位小数)</returns>
public virtual async Task<double> (int = 1, CancellationToken ct = default)
{
return await WriteReadAsync($":SOURce{通道号}:VOLTage:OFFSet?{ScpiDelimiter}", ScpiDelimiter, ct);
string resp = await WriteReadAsync($":SOURce{通道号}:VOLTage:OFFSet?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
#endregion
@@ -156,8 +238,11 @@ namespace DeviceCommand.Devices
#region 4. / (CP信号模拟)
/// <summary>
/// 设置方波信号的占空比 (0.01% ~ 99.99%)[cite: 1]
/// 设置方波信号的占空比 (0.01% ~ 99.99%)
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="占空比">方波占空比百分比,默认 50.0</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int = 1, double = 50.0, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:FUNCtion:SQUare:DCYCle {1:F2}{2}", , , ScpiDelimiter);
@@ -165,9 +250,12 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置脉冲波信号的占空比 (0.01% ~ 99.99%)[cite: 1]
/// 设置脉冲波信号的占空比 (0.01% ~ 99.99%)
/// 注意:使用此命令前必须先设置为 PULSe 波形类型
/// </summary>
/// <param name="通道号">通道 1 或 2,默认 1</param>
/// <param name="占空比">脉冲波占空比百分比,默认 50.0</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int = 1, double = 50.0, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:FUNCtion:PULSe:DCYCle {1:F2}{2}", , , ScpiDelimiter);
@@ -179,47 +267,68 @@ namespace DeviceCommand.Devices
#region 5. ()
/// <summary>
/// 打开或关闭内置频率计功能
/// 打开或关闭内置频率计功能 (COUNter:STATe 指令)
/// </summary>
/// <param name="开启">true: 开启频率计, false: 关闭频率计</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (bool = true, CancellationToken ct = default)
{
string = ? "ON" : "OFF";
await SendAsync($":COUNter:STATe {参数}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询内置频率计的开关状态 (COUNter:STATe? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>频率计开关状态字符串 (ON / OFF)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":COUNter:STATe?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 设置频率计输入信号的耦合方式
/// 设置频率计输入信号的耦合方式 (COUNter:COUPling 指令)
/// </summary>
/// <param name="耦合">耦合方式枚举 (AC 交流 / DC 直流),默认 AC</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (CounterCoupling = CounterCoupling.AC, CancellationToken ct = default)
{
await SendAsync($":COUNter:COUPling {耦合}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置频率计的触发电平 (单位: V)
/// 设置频率计的触发电平 (COUNter:LEVel 指令)
/// </summary>
/// <param name="电平V">触发电平值 (单位: V),默认 0.1</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (double V = 0.1, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":COUNter:LEVel {0:F2}{1}", V, ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 查询频率计测量值 (COUNter:MEASure? 指令)。
/// 响应格式为 "频率, 周期, 占空比, 正脉宽, 负脉宽",此方法提取第一项频率值
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>频率计测得的频率值 (单位: Hz,保留两位小数)</returns>
[Monitorable("信号发生器频率计测量值")]
public virtual async Task<string> (CancellationToken ct = default)
public virtual async Task<double> (CancellationToken ct = default)
{
// 返回格式: 频率, 周期, 占空比, 正脉宽, 负脉宽
return await WriteReadAsync($":COUNter:MEASure?{ScpiDelimiter}", ScpiDelimiter, ct);
string resp = await WriteReadAsync($":COUNter:MEASure?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
#endregion
#region 6.
/// <summary>
/// 切换远程控制模式。信号发生器通过 LAN/USB 通信即自动进入远程模式
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task (CancellationToken ct = default)
{
// 信号发生器通常通过 LAN/USB 和 VISA 通信即自动进入远程控制,
@@ -227,12 +336,21 @@ namespace DeviceCommand.Devices
await Task.CompletedTask;
}
/// <summary>
/// 切换本地控制模式。通常通过前面板按键退出远程
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task (CancellationToken ct = default)
{
// 通常通过前面板按键退出远程。不过可提供 SCPI 关闭屏幕保护等。
await Task.CompletedTask;
}
/// <summary>
/// 查询系统错误信息 (SYSTem:ERRor? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>错误代码和描述信息</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":SYSTem:ERRor?{ScpiDelimiter}", ScpiDelimiter, ct);
@@ -240,4 +358,4 @@ namespace DeviceCommand.Devices
#endregion
}
}
}
+34 -3
View File
@@ -12,22 +12,39 @@ using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
/// <summary>
/// IO板卡 一对一由于板卡映射不完全一样采用IOGroup
/// IO 继电器板卡一对一控制),基于 Modbus TCP 协议通过线圈(Coil)读写控制继电器输出。
/// 由于多块板卡的点位映射不完全一致,实际业务中使用 <see cref="IOBoardGroup"/> 统一调度三块板卡。
/// </summary>
//[ACPCommand]
public class IOBoard : ModbusTcp
{
/// <summary>
/// 构造函数,初始化 Modbus TCP 连接配置。
/// </summary>
/// <param name="config">TCP 连接配置(IP、端口等)</param>
public IOBoard(TcpConfig config) : base(config)
{
}
/// <summary>
/// 写入单个输出开关(线圈)状态。
/// </summary>
/// <param name="站号">Modbus 从站站号</param>
/// <param name="开始地址">线圈地址(0 起始)</param>
/// <param name="data">开关状态(true: 吸合/开启, false: 断开/关闭)</param>
public async Task (byte , ushort , bool data)
{
await Modbus.WriteSingleCoilAsync(, , data);
}
/// <summary>
/// 批量写入输出开关状态。先读出全部 16 个线圈当前状态,
/// 在内存中修改指定偏移段的值后再整体写回,避免影响其他点位。
/// </summary>
/// <param name="站号">Modbus 从站站号</param>
/// <param name="开始地址">起始线圈地址(0 起始)</param>
/// <param name="datas">要写入的开关状态数组,按顺序从开始地址写入</param>
public async Task (byte , ushort , bool[] datas)
{
var = await Modbus.ReadCoilsAsync(1, 0, 16);
@@ -40,10 +57,24 @@ namespace DeviceCommand.Devices
}
await Modbus.WriteMultipleCoilsAsync(, 0, );
}
/// <summary>
/// 读取单个输出开关(线圈)状态。
/// </summary>
/// <param name="站号">Modbus 从站站号</param>
/// <param name="开始地址">线圈地址(0 起始)</param>
public async Task (byte , ushort )
{
await Modbus.ReadCoilsAsync(, , 1);
}
/// <summary>
/// 批量读取输出开关(线圈)状态。
/// </summary>
/// <param name="站号">Modbus 从站站号</param>
/// <param name="开始地址">起始线圈地址(0 起始)</param>
/// <param name="数量">要读取的线圈数量</param>
/// <returns>线圈状态数组,true 表示吸合/开启</returns>
public async Task<bool[]> (byte , ushort ,ushort )
{
return await Modbus.ReadCoilsAsync(, , );
+25 -37
View File
@@ -48,6 +48,11 @@ namespace DeviceCommand.Devices
}
}
/// <summary>
/// IO 板卡组(三工位统一调度),封装 3 块 IO 继电器板卡的访问。
/// 根据 ACP 硬件接线图的点位映射字典,按台架序号路由到对应板卡的线圈地址,
/// 并内置充电/放电互锁保护,防止同时吸合造成短路。
/// </summary>
[ACPCommand]
public class IOBoardGroup
{
@@ -121,6 +126,13 @@ namespace DeviceCommand.Devices
}}
};
/// <summary>
/// 构造函数,注入三个工位的 IO 板卡实例。
/// </summary>
/// <param name="board1">1# 工位 IO 板卡实例</param>
/// <param name="board2">2# 工位 IO 板卡实例</param>
/// <param name="board3">3# 工位 IO 板卡实例</param>
/// <exception cref="ArgumentNullException">任一块板卡实例为空时抛出</exception>
// 修改构造函数以支持 3 个板块
public IOBoardGroup(IOBoard board1, IOBoard board2, IOBoard board3)
{
@@ -168,49 +180,25 @@ namespace DeviceCommand.Devices
await .(_slaveAddress, io信息.Address, );
}
// =================================================================================
// 以下为新增的原生命令透传接口,使用台架序号自动路由至对应 IOBoard
// =================================================================================
/// <summary>
/// 针对指定台架直接写入单个输出开关
/// 向指定板卡批量写入输出开关状态,直接透传到对应板卡的批量写线圈操作。
/// </summary>
public async Task (int , byte , ushort , bool data)
/// <param name="板卡序号">板卡序号 (1 - 3)</param>
/// <param name="站号">Modbus 从站站号</param>
/// <param name="开始地址">线圈起始地址 (0-15)</param>
/// <param name="数据">开关状态数组 (true: 开启吸合, false: 关闭断开),例如 [true, true, false]</param>
/// <param name="取消令牌">异步取消令牌</param>
public async Task (int , byte , ushort , bool[] , CancellationToken = default)
{
IOBoard targetBoard = GetBoardInstance();
await targetBoard.(, , data);
await GetBoardInstance().(, , );
}
/// <summary>
/// 针对指定台架直接批量写入输出开关
/// </summary>
public async Task (int , byte , ushort , bool[] datas)
{
IOBoard targetBoard = GetBoardInstance();
await targetBoard.(, , datas);
}
/// <summary>
/// 针对指定台架直接读取单个输出开关状态
/// </summary>
public async Task (int , byte , ushort )
{
IOBoard targetBoard = GetBoardInstance();
await targetBoard.(, );
}
/// <summary>
/// 针对指定台架直接批量读取输出开关状态
/// </summary>
public async Task<bool[]> (int , byte , ushort , ushort )
{
IOBoard targetBoard = GetBoardInstance();
return await targetBoard.(, , );
}
/// <summary>
/// 内部路由辅助方法:根据板卡/台架索引安全获取当前连接的实例对象
/// 内部路由辅助方法:根据板卡序号安全获取对应的 IO 板卡实例。
/// </summary>
/// <param name="moduleIndex">板卡序号 (1 - 3)</param>
/// <returns>对应的 IO 板卡实例</returns>
/// <exception cref="ArgumentOutOfRangeException">板卡序号不在 1-3 范围内时抛出</exception>
/// <exception cref="InvalidOperationException">板卡实例未初始化时抛出</exception>
private IOBoard GetBoardInstance(int moduleIndex)
{
IOBoard board = moduleIndex switch
+23 -4
View File
@@ -133,6 +133,10 @@ namespace DeviceCommand.Devices
throw new Exception("IT6720 切换控制模式时通讯校验失败。");
}
/// <summary>
/// 切换为本地(面板)控制模式,与远程控制互斥
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task (CancellationToken ct = default)
{
await (false, ct);
@@ -150,6 +154,11 @@ namespace DeviceCommand.Devices
throw new Exception("IT6720 设置输出时通讯校验失败。");
}
/// <summary>
/// 查询电源输出开关状态(由实时测量值的状态字节判断)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>输出开关状态字符串 (ON / OFF)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
var (_, _, status) = await (ct);
@@ -230,18 +239,28 @@ namespace DeviceCommand.Devices
return (actualCurrent, actualVoltage, statusByte);
}
/// <summary>
/// 查询电源的实时实际输出电压 (MEASure 相关寄存器)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>实时电压值 (单位: V,保留两位小数)</returns>
[Monitorable("IT6720 实际电压")]
public virtual async Task<string> (CancellationToken ct = default)
public virtual async Task<double> (CancellationToken ct = default)
{
var (_, voltage, _) = await (ct);
return voltage.ToString("F2", CultureInfo.InvariantCulture);
return Math.Round(voltage, 2);
}
/// <summary>
/// 查询电源的实时实际输出电流 (MEASure 相关寄存器)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>实时电流值 (单位: A,保留两位小数)</returns>
[Monitorable("IT6720 实际电流")]
public virtual async Task<string> (CancellationToken ct = default)
public virtual async Task<double> (CancellationToken ct = default)
{
var (current, _, _) = await (ct);
return current.ToString("F3", CultureInfo.InvariantCulture);
return Math.Round(current, 2);
}
/// <summary>
+6 -1
View File
@@ -9,10 +9,15 @@ using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
/// <summary>
/// 水冷机 一拖三
/// MCc30W 水冷机一拖三控制),基于 Modbus TCP 协议通信。
/// 用于被测产品的冷却温控,预留后续读写温度设定、启停控制等寄存器操作。
/// </summary>
public class MCc30W:ModbusTcp
{
/// <summary>
/// 构造函数,初始化 Modbus TCP 连接配置。
/// </summary>
/// <param name="config">TCP 连接配置(IP、端口等)</param>
public MCc30W(TcpConfig config) : base(config)
{
}
+261 -33
View File
@@ -2,13 +2,16 @@
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Device
{
/// <summary>
/// 功率分析仪(型号:HIOKI PW8001) 一拖三
/// 功率分析仪(型号:HIOKI PW8001) 一拖三,支持多通道电压/电流/功率及谐波测量
/// </summary>
[ACPCommand]
public class PW8001 : Tcp
@@ -25,23 +28,58 @@ namespace DeviceCommand.Device
/// </summary>
public string? SessionKey { get; set; }
/// <summary>
/// 从设备返回的 SCPI 响应字符串中提取数值部分并转换为 double。
/// 支持科学计数法(如 2.48E-03),结果保留两位小数。
/// </summary>
/// <param name="raw">设备返回的原始字符串</param>
/// <returns>提取到的数值(保留两位小数),解析失败时返回 0</returns>
private static double ExtractDouble(string raw)
{
if (string.IsNullOrWhiteSpace(raw)) return 0;
// 从响应中提取第一个数值(含正负号、小数点、科学计数法),可自动忽略单位后缀与命令头
var match = Regex.Match(raw, @"[+-]?(?:\d+\.?\d*|\.\d+)(?:[Ee][+-]?\d+)?");
return match.Success && double.TryParse(match.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double val)
? Math.Round(val, 2)
: 0;
}
#region 1. IEEE 488.2
/// <summary>
/// 查询仪器识别信息 (*IDN? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>设备标识字符串 (制造商, 型号, 序列号, 固件版本)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync("*IDN?\r\n", "\n", ct);
}
/// <summary>
/// 查询仪器已安装的硬件选件 (*OPT? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>硬件选件列表字符串</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync("*OPT?\r\n", "\n", ct);
}
/// <summary>
/// 复位仪器到默认状态 (*RST 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync("*RST\r\n", ct);
}
/// <summary>
/// 清除状态寄存器和错误队列 (*CLS 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync("*CLS\r\n", ct);
@@ -51,66 +89,129 @@ namespace DeviceCommand.Device
#region 2. (System & Mode)
/// <summary>
/// 设置测试模式为 WIDE 宽带测量模式 (:MODE WIDE 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task _WIDE(CancellationToken ct = default)
{
await SendAsync(":MODE WIDE\r\n", ct);
}
/// <summary>
/// 设置测试模式为 IEC 标准测量模式 (:MODE IEC 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task _IEC(CancellationToken ct = default)
{
await SendAsync(":MODE IEC\r\n", ct);
}
/// <summary>
/// 查询当前测试模式 (:MODE? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>测试模式字符串 (WIDE / IEC)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync(":MODE?\r\n", "\n", ct);
}
/// <summary>
/// 设置同步源 (:SYNC:SOURce 指令)
/// </summary>
/// <param name="源">同步源标识</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (string , CancellationToken ct = default)
{
await SendAsync($":SYNC:SOURce {源}\r\n", ct);
}
/// <summary>
/// 查询当前同步源 (:SYNC:SOURce? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>同步源标识字符串</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync(":SYNC:SOURce?\r\n", "\n", ct);
}
/// <summary>
/// 设置零点调整状态 (:ZERO 指令)
/// </summary>
/// <param name="状态">零点调整状态 (ON / OFF)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (string , CancellationToken ct = default)
{
await SendAsync($":ZERO {状态}\r\n", ct);
}
/// <summary>
/// 查询零点调整状态 (:ZERO? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>零点调整状态字符串 (ON / OFF)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync(":ZERO?\r\n", "\n", ct);
}
/// <summary>
/// 设置零点抑制状态 (:ZSP 指令)
/// </summary>
/// <param name="状态">零点抑制状态 (ON / OFF)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (string , CancellationToken ct = default)
{
await SendAsync($":ZSP {状态}\r\n", ct);
}
/// <summary>
/// 查询零点抑制状态 (:ZSP? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>零点抑制状态字符串 (ON / OFF)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync(":ZSP?\r\n", "\n", ct);
}
/// <summary>
/// 设置响应消息头开关 (:HEADer 指令)
/// </summary>
/// <param name="状态">消息头开关状态 (ON / OFF)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (string , CancellationToken ct = default)
{
await SendAsync($":HEADer {状态}\r\n", ct);
}
/// <summary>
/// 查询响应消息头开关状态 (:HEADer? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>消息头开关状态字符串 (ON / OFF)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync(":HEADer?\r\n", "\n", ct);
}
/// <summary>
/// 设置按键锁定状态 (:KLOCk 指令)
/// </summary>
/// <param name="状态">按键锁定状态 (ON / OFF)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (string , CancellationToken ct = default)
{
await SendAsync($":KLOCk {状态}\r\n", ct);
}
/// <summary>
/// 查询按键锁定状态 (:KLOCk? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>按键锁定状态字符串 (ON / OFF)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync(":KLOCk?\r\n", "\n", ct);
@@ -120,21 +221,43 @@ namespace DeviceCommand.Device
#region 3. (Integration)
/// <summary>
/// 设置积分控制模式 (:INTEG:CONTROL 指令)
/// </summary>
/// <param name="模式">积分控制模式</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (string , CancellationToken ct = default)
{
await SendAsync($":INTEG:CONTROL {模式}\r\n", ct);
}
/// <summary>
/// 查询积分控制模式 (:INTEG:CONTROL? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>积分控制模式字符串</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync(":INTEG:CONTROL?\r\n", "\n", ct);
}
/// <summary>
/// 设置指定通道的积分模式 (:INTEG:MODE 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="模式">积分模式</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (string , string , CancellationToken ct = default)
{
await SendAsync($":INTEG:MODE{通道号} {模式}\r\n", ct);
}
/// <summary>
/// 查询指定通道的积分模式 (:INTEG:MODE? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>积分模式字符串</returns>
public virtual async Task<string> (string , CancellationToken ct = default)
{
return await WriteReadAsync($":INTEG:MODE{通道号}?\r\n", "\n", ct);
@@ -146,85 +269,188 @@ namespace DeviceCommand.Device
// ---------------- 基础测量(不含变比) ----------------
public virtual async Task<string> _不含变比(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电压测量值(不含变比) (:MEAS:U? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电压测量值 (单位: V,保留两位小数)</returns>
public virtual async Task<double> _不含变比(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:U{通道号}?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:U{通道号}?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> _不含变比(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电流测量值(不含变比) (:MEAS:I? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电流测量值 (单位: A,保留两位小数)</returns>
public virtual async Task<double> _不含变比(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:I{通道号}?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:I{通道号}?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> _不含变比(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的功率测量值(不含变比) (:MEAS:P? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>功率测量值 (单位: W,保留两位小数)</returns>
public virtual async Task<double> _不含变比(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:P{通道号}?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:P{通道号}?\r\n", "\n", ct);
return ExtractDouble(resp);
}
// ---------------- 基础测量(含变比 CT ----------------
public virtual async Task<string> _含变比(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电压测量值(含变比) (:MEAS:U:CT? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电压测量值 (单位: V,保留两位小数)</returns>
public virtual async Task<double> _含变比(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:U{通道号}:CT?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:U{通道号}:CT?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> _含变比(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电流测量值(含变比) (:MEAS:I:CT? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电流测量值 (单位: A,保留两位小数)</returns>
public virtual async Task<double> _含变比(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:I{通道号}:CT?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:I{通道号}:CT?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> _含变比(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的功率测量值(含变比) (:MEAS:P:CT? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>功率测量值 (单位: W,保留两位小数)</returns>
public virtual async Task<double> _含变比(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:P{通道号}:CT?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:P{通道号}:CT?\r\n", "\n", ct);
return ExtractDouble(resp);
}
// ---------------- 其他高阶参数测量 ----------------
public virtual async Task<string> (int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的有功功率积分值 (:MEAS:WP? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>有功功率积分值 (单位: Wh,保留两位小数)</returns>
public virtual async Task<double> (int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:WP{通道号}?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:WP{通道号}?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> THD(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电压总谐波失真 (THD) (:MEAS:UTHD? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电压 THD 值 (单位: %,保留两位小数)</returns>
public virtual async Task<double> THD(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:UTHD{通道号}?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:UTHD{通道号}?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> THD(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电流总谐波失真 (THD) (:MEAS:ITHD? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电流 THD 值 (单位: %,保留两位小数)</returns>
public virtual async Task<double> THD(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:ITHD{通道号}?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:ITHD{通道号}?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> 线U12(CancellationToken ct = default)
/// <summary>
/// 查询线电压 U12 (:MEAS:U12? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>线电压 U12 值 (单位: V,保留两位小数)</returns>
public virtual async Task<double> 线U12(CancellationToken ct = default)
{
return await WriteReadAsync(":MEAS:U12?\r\n", "\n", ct);
string resp = await WriteReadAsync(":MEAS:U12?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> P123(CancellationToken ct = default)
/// <summary>
/// 查询三相总功率 P123 (:MEAS:P123? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>三相总功率值 (单位: W,保留两位小数)</returns>
public virtual async Task<double> P123(CancellationToken ct = default)
{
return await WriteReadAsync(":MEAS:P123?\r\n", "\n", ct);
string resp = await WriteReadAsync(":MEAS:P123?\r\n", "\n", ct);
return ExtractDouble(resp);
}
// ---------------- 整流平均值 ----------------
public virtual async Task<string> (int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电压整流平均值(不含变比) (:MEAS:UMN? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电压整流平均值 (单位: V,保留两位小数)</returns>
public virtual async Task<double> (int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:UMN{通道号}?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:UMN{通道号}?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> (int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电流整流平均值(不含变比) (:MEAS:IMN? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电流整流平均值 (单位: A,保留两位小数)</returns>
public virtual async Task<double> (int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:IMN{通道号}?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:IMN{通道号}?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> _含变比(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电压整流平均值(含变比) (:MEAS:UMN:CT? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电压整流平均值 (单位: V,保留两位小数)</returns>
public virtual async Task<double> _含变比(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:UMN{通道号}:CT?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:UMN{通道号}:CT?\r\n", "\n", ct);
return ExtractDouble(resp);
}
public virtual async Task<string> _含变比(int , CancellationToken ct = default)
/// <summary>
/// 查询指定通道的电流整流平均值(含变比) (:MEAS:IMN:CT? 指令)
/// </summary>
/// <param name="通道号">通道编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>电流整流平均值 (单位: A,保留两位小数)</returns>
public virtual async Task<double> _含变比(int , CancellationToken ct = default)
{
return await WriteReadAsync($":MEAS:IMN{通道号}:CT?\r\n", "\n", ct);
string resp = await WriteReadAsync($":MEAS:IMN{通道号}:CT?\r\n", "\n", ct);
return ExtractDouble(resp);
}
#endregion
@@ -232,8 +458,10 @@ namespace DeviceCommand.Device
#region 5.
/// <summary>
/// 发送自定义命令
/// 发送自定义命令(透传任意 SCPI 指令)
/// </summary>
/// <param name="命令">自定义命令字符串</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (string , CancellationToken ct = default)
{
await SendAsync($"{命令}\r\n", ct);
@@ -241,4 +469,4 @@ namespace DeviceCommand.Device
#endregion
}
}
}
+142 -14
View File
@@ -8,30 +8,45 @@ using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
/// <summary>
/// 环境箱(型号:RLT1000) 一拖三
/// 环境箱(型号:RLT1000) 一拖三,支持温度/湿度/水温/水流量的监测与定值控制 (Modbus TCP 协议)
/// </summary>
[ACPCommand]
public class RLT1000 : ModbusTcp
{
/// <summary>
/// 构造函数:传入 <see cref="TcpConfig"/> 初始化环境箱 Modbus TCP 通信参数
/// </summary>
public RLT1000(TcpConfig config) : base(config)
{
}
// Modbus 从站号
private const byte SlaveId = 1;
#region
/// <summary>
/// 读取环境箱运行状态监控字 (保持寄存器 5)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>状态监控字 (ushort 原始值)</returns>
public async Task<ushort> (CancellationToken ct = default)
{
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 5, 1, ct);
return re[0];
}
public async Task<float> (CancellationToken ct = default)
/// <summary>
/// 读取环境箱当前温度值 (保持寄存器 10-11)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>当前温度值 (单位: ℃,保留两位小数)</returns>
public async Task<double> (CancellationToken ct = default)
{
try
{
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 10, 2, ct);
return ConvertToFloat(re);
return Math.Round(ConvertToFloat(re), 2);
}
catch (Exception)
{
@@ -39,18 +54,28 @@ namespace DeviceCommand.Devices
}
}
public async Task<float> 湿(CancellationToken ct = default)
/// <summary>
/// 读取环境箱当前湿度值 (保持寄存器 16-17)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>当前湿度值 (单位: %RH,保留两位小数)</returns>
public async Task<double> 湿(CancellationToken ct = default)
{
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 16, 2, ct);
return ConvertToFloat(re);
return Math.Round(ConvertToFloat(re), 2);
}
public async Task<float> (CancellationToken ct = default)
/// <summary>
/// 读取环境箱当前水温值 (保持寄存器 22-23)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>当前水温值 (单位: ℃,保留两位小数)</returns>
public async Task<double> (CancellationToken ct = default)
{
try
{
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 22, 2, ct);
return ConvertToFloat(re);
return Math.Round(ConvertToFloat(re), 2);
}
catch (Exception)
{
@@ -58,119 +83,212 @@ namespace DeviceCommand.Devices
}
}
public async Task<float> 1(CancellationToken ct = default)
/// <summary>
/// 读取当前 1 号水流量值 (保持寄存器 28-29)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>1 号水流量值 (保留两位小数)</returns>
public async Task<double> 1(CancellationToken ct = default)
{
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 28, 2, ct);
return ConvertToFloat(re);
return Math.Round(ConvertToFloat(re), 2);
}
public async Task<float> 2(CancellationToken ct = default)
/// <summary>
/// 读取当前 2 号水流量值 (保持寄存器 34-35)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>2 号水流量值 (保留两位小数)</returns>
public async Task<double> 2(CancellationToken ct = default)
{
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 34, 2, ct);
return ConvertToFloat(re);
return Math.Round(ConvertToFloat(re), 2);
}
public async Task<float> 3(CancellationToken ct = default)
/// <summary>
/// 读取当前 3 号水流量值 (保持寄存器 40-41)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>3 号水流量值 (保留两位小数)</returns>
public async Task<double> 3(CancellationToken ct = default)
{
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 40, 2, ct);
return ConvertToFloat(re);
return Math.Round(ConvertToFloat(re), 2);
}
#endregion
#region
/// <summary>
/// 切换环境箱为本地控制模式 (寄存器 147 写 0)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 147, 0, ct);
}
/// <summary>
/// 切换环境箱为远程控制模式 (寄存器 147 写 1)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 147, 1, ct);
}
/// <summary>
/// 远程模式下关闭环境箱 (寄存器 148 写 0)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 148, 0, ct);
}
/// <summary>
/// 远程模式下开启环境箱 (寄存器 148 写 1)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 148, 1, ct);
}
/// <summary>
/// 远程模式复位结束 (寄存器 149 写 0)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 149, 0, ct);
}
/// <summary>
/// 远程模式复位 (寄存器 149 写 1)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 149, 1, ct);
}
/// <summary>
/// 切换为程序运行模式 (寄存器 153 写 0)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 153, 0, ct);
}
/// <summary>
/// 切换为定值运行模式 (寄存器 153 写 1)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 153, 1, ct);
}
/// <summary>
/// 定值模式下设置目标温度 (寄存器 154-155)
/// </summary>
/// <param name="温度">目标温度值 (单位: ℃)</param>
/// <param name="ct">取消令牌</param>
public async Task (float , CancellationToken ct = default)
{
var tmp = ConvertFromFloat();
await WriteMultipleRegistersAsync(SlaveId, 154, tmp, ct);
}
/// <summary>
/// 定值模式下设置目标湿度 (寄存器 158-159)
/// </summary>
/// <param name="湿度">目标湿度值 (单位: %RH)</param>
/// <param name="ct">取消令牌</param>
public async Task 湿(float 湿, CancellationToken ct = default)
{
var tmp = ConvertFromFloat(湿);
await WriteMultipleRegistersAsync(SlaveId, 158, tmp, ct);
}
/// <summary>
/// 定值模式下设置目标水温 (寄存器 162-163)
/// </summary>
/// <param name="水温">目标水温值 (单位: ℃)</param>
/// <param name="ct">取消令牌</param>
public async Task (float , CancellationToken ct = default)
{
var tmp = ConvertFromFloat();
await WriteMultipleRegistersAsync(SlaveId, 162, tmp, ct);
}
/// <summary>
/// 定值模式下设置 1 号水流量目标值 (寄存器 164-165)
/// </summary>
/// <param name="水流量">1 号水流量目标值</param>
/// <param name="ct">取消令牌</param>
public async Task 1(float , CancellationToken ct = default)
{
var tmp = ConvertFromFloat();
await WriteMultipleRegistersAsync(SlaveId, 164, tmp, ct);
}
/// <summary>
/// 定值模式下设置 2 号水流量目标值 (寄存器 166-167)
/// </summary>
/// <param name="水流量">2 号水流量目标值</param>
/// <param name="ct">取消令牌</param>
public async Task 2(float , CancellationToken ct = default)
{
var tmp = ConvertFromFloat();
await WriteMultipleRegistersAsync(SlaveId, 166, tmp, ct);
}
/// <summary>
/// 定值模式下设置 3 号水流量目标值 (寄存器 168-169)
/// </summary>
/// <param name="水流量">3 号水流量目标值</param>
/// <param name="ct">取消令牌</param>
public async Task 3(float , CancellationToken ct = default)
{
var tmp = ConvertFromFloat();
await WriteMultipleRegistersAsync(SlaveId, 168, tmp, ct);
}
/// <summary>
/// 设置水温模式不使用 (寄存器 1181 写 0)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task 使(CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 1181, 0, ct);
}
/// <summary>
/// 设置水温模式使用 (寄存器 1181 写 1)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task 使(CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 1181, 1, ct);
}
/// <summary>
/// 设置环境箱温度模式不使用 (寄存器 1182 写 0)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task 使(CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 1182, 0, ct);
}
/// <summary>
/// 设置环境箱温度模式使用 (寄存器 1182 写 1)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task 使(CancellationToken ct = default)
{
await WriteSingleRegisterAsync(SlaveId, 1182, 1, ct);
@@ -180,6 +298,11 @@ namespace DeviceCommand.Devices
#region
/// <summary>
/// 将两个 16 位寄存器(大端序)转换为 IEEE754 单精度浮点数
/// </summary>
/// <param name="values">两个 ushort 寄存器值</param>
/// <returns>转换后的浮点数值</returns>
private float ConvertToFloat(ushort[] values)
{
if (values == null || values.Length < 2) return 0f;
@@ -192,6 +315,11 @@ namespace DeviceCommand.Devices
return BitConverter.ToSingle(bytes, 0);
}
/// <summary>
/// 将单精度浮点数转换为两个 16 位寄存器(大端序)
/// </summary>
/// <param name="value">待转换的浮点数值</param>
/// <returns>两个 ushort 寄存器值</returns>
private ushort[] ConvertFromFloat(float value)
{
byte[] bytes = BitConverter.GetBytes(value);
@@ -203,4 +331,4 @@ namespace DeviceCommand.Devices
#endregion
}
}
}
+235 -37
View File
@@ -1,65 +1,119 @@
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
// 根据您的项目实际路径保留枚举的引用
// using 通讯驱动Base.枚举;
namespace DeviceCommand.Devices
{
/// <summary>
/// S7200 负载工作模式枚举 (恒流/恒压/恒功率/恒阻等)
/// </summary>
public enum S7200负载模式_枚举
{
/// <summary>恒流模式</summary>
CC,
/// <summary>恒压模式</summary>
CV,
/// <summary>恒功率模式</summary>
CP,
/// <summary>恒阻模式</summary>
CR,
/// <summary>恒压+恒流组合模式</summary>
CVCC,
/// <summary>恒阻+恒流组合模式</summary>
CRCC,
/// <summary>恒压+恒阻组合模式</summary>
CVCR,
/// <summary>自动模式</summary>
AUTO
}
/// <summary>
/// S7200 直流源工作模式枚举 (电压源/电流源/电池模拟/光伏模拟等)
/// </summary>
public enum S7200直流源模式_枚举
{
/// <summary>电压源模式</summary>
VOLTage,
/// <summary>电流源模式</summary>
CURRent,
/// <summary>电池测试模式</summary>
BATTest,
/// <summary>电池模拟模式</summary>
BATSim,
/// <summary>光伏模拟模式</summary>
SOLar,
/// <summary>EN50530 标准光伏曲线模式</summary>
EN50530,
/// <summary>列表输出模式</summary>
LIST,
/// <summary>用户自定义波形模式</summary>
UDW,
/// <summary>方波输出模式</summary>
SQUare,
/// <summary>三角波输出模式</summary>
TRIangle,
/// <summary>正弦波输出模式</summary>
SINusoid,
/// <summary>DIN40839 12V 启动曲线</summary>
DIN40839_12V,
/// <summary>DIN40839 24V 启动曲线</summary>
DIN40839_24V,
/// <summary>ISO16750 短时跌落 12V</summary>
IS016750_SHORTDROP_12V,
/// <summary>ISO16750 短时跌落 24V</summary>
IS016750_SHORTDROP_24V,
/// <summary>ISO16750 复位测试</summary>
IS016750_RESETTEST,
/// <summary>ISO16750 启动曲线 12V 第 1 组</summary>
IS016750_STARTINGPROFILE_12V_1,
/// <summary>ISO16750 启动曲线 12V 第 2 组</summary>
IS016750_STARTINGPROFILE_12V_2,
/// <summary>ISO16750 启动曲线 12V 第 3 组</summary>
IS016750_STARTINGPROFILE_12V_3,
/// <summary>ISO16750 启动曲线 12V 第 4 组</summary>
IS016750_STARTINGPROFILE_12V_4,
/// <summary>ISO16750 启动曲线 24V 第 1 组</summary>
IS016750_STARTINGPROFILE_24V_1,
/// <summary>ISO16750 启动曲线 24V 第 2 组</summary>
IS016750_STARTINGPROFILE_24V_2,
/// <summary>ISO16750 启动曲线 24V 第 3 组</summary>
IS016750_STARTINGPROFILE_24V_3,
/// <summary>ISO16750 抛负载测试 A 12V</summary>
IS016750_LOADDUMP_TESTA_12V,
/// <summary>ISO16750 抛负载测试 A 24V</summary>
IS016750_LOADDUMP_TESTA_24V,
/// <summary>ISO16750 抛负载测试 B 12V</summary>
IS016750_LOADDUMP_TESTB_12V,
/// <summary>ISO16750 抛负载测试 B 24V</summary>
IS016750_LOADDUMP_TESTB_24V,
/// <summary>LV123 高压曲线 1</summary>
LV123_HV_1,
/// <summary>LV123 高压曲线 2A</summary>
LV123_HV_2A,
/// <summary>LV123 高压曲线 2B</summary>
LV123_HV_2B,
/// <summary>LV123 高压曲线 3</summary>
LV123_HV_3
}
/// <summary>
/// S7200 工作模式枚举 (电源模式 / 负载模式)
/// </summary>
public enum S7200工作模式_枚举
{
/// <summary>作为电源输出</summary>
,
/// <summary>作为负载吸收</summary>
,
}
/// <summary>
/// 高压直流源载一体机 (适配 IT6000C SCPI指令集)
/// 高压直流源载一体机 (适配 IT6000C SCPI 指令集),支持电源输出与负载吸收双向工作
/// </summary>
[ACPCommand]
public class S7200 : Tcp
@@ -67,115 +121,239 @@ namespace DeviceCommand.Devices
// SCPI 指令结束符
private const string ScpiDelimiter = "\n";
#region
public async Task (CancellationToken ct = default)
/// <summary>
/// 构造函数:传入 <see cref="TcpConfig"/> 一次性初始化一体机通信参数
/// </summary>
public S7200(TcpConfig config) : base(config)
{
await SendAsync($"SYSTem:REMote{ScpiDelimiter}", ct); //[cite: 1]
}
/// <summary>
/// 从设备返回的 SCPI 响应字符串中提取数值部分并转换为 double。
/// 支持科学计数法(如 2.48E-03),结果保留两位小数。
/// </summary>
/// <param name="raw">设备返回的原始字符串</param>
/// <returns>提取到的数值(保留两位小数),解析失败时返回 0</returns>
private static double ExtractDouble(string raw)
{
if (string.IsNullOrWhiteSpace(raw)) return 0;
// 从响应中提取第一个数值(含正负号、小数点、科学计数法),可自动忽略单位后缀与命令头
var match = Regex.Match(raw, @"[+-]?(?:\d+\.?\d*|\.\d+)(?:[Ee][+-]?\d+)?");
return match.Success && double.TryParse(match.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double val)
? Math.Round(val, 2)
: 0;
}
#region
/// <summary>
/// 设置仪器为远程控制模式 (SYSTem:REMote)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await SendAsync($"SYSTem:REMote{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置电源工作模式 (电源/负载)。IT6000C 支持双向无缝切换,无需显式下发源载切换指令
/// </summary>
/// <param name="开关">工作模式枚举 (电源模式 / 负载模式)</param>
/// <param name="ct">取消令牌</param>
public async Task (S7200工作模式_枚举 , CancellationToken ct = default)
{
// IT6000C 为双向无缝切换,底层硬件无需显式发送源载切换指令
// 保留此方法仅为兼容原有上位机的工步调用流程,直接返回即可
// 保留此方法仅为兼容原有上位机的工步调用流程
await Task.CompletedTask;
}
/// <summary>
/// 设置直流源工作模式 (FUNCtion 指令,如 VOLTage / CURRent / SOLar 等)
/// </summary>
/// <param name="模式">直流源工作模式枚举</param>
/// <param name="ct">取消令牌</param>
public async Task (S7200直流源模式_枚举 , CancellationToken ct = default)
{
// 原指令: MODE {模式} -> 现 IT6000C 指令: FUNCtion {模式} (如 VOLTage / CURRent)[cite: 1]
// 若枚举 ToString() 后不匹配,建议在此处加 Switch 转换
await SendAsync($"FUNCtion {模式}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置负载工作模式。IT6000C 负载控制通过负向边界实现
/// </summary>
/// <param name="模式">负载工作模式枚举</param>
/// <param name="ct">取消令牌</param>
public async Task (S7200负载模式_枚举 , CancellationToken ct = default)
{
// IT6000C 负载控制通过负向边界实现。若是想开启纯电阻模式,可调用 SINK:RESistance:STATe ON[cite: 1]
// 想开启纯电阻模式,可调用 SINK:RESistance:STATe ON
await Task.CompletedTask;
}
/// <summary>
/// 开启或关闭通道输出 (OUTPut 指令)
/// </summary>
/// <param name="开关">true: 开启输出, false: 关闭输出</param>
/// <param name="ct">取消令牌</param>
public async Task (bool , CancellationToken ct = default)
{
await SendAsync($"OUTPut {(开关 ? 1 : 0)}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"OUTPut {(开关 ? 1 : 0)}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置恒流 (CC) 模式的电流值 (CURRent 指令)
/// </summary>
/// <param name="电流">电流设定值 (单位: A)</param>
/// <param name="ct">取消令牌</param>
public async Task CC模式电流(double , CancellationToken ct = default)
{
await SendAsync($"CURRent {电流}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"CURRent {电流}{ScpiDelimiter}", ct);
}
public async Task CC电压H(double , CancellationToken ct = default) // 沿用原参数名“电流”,实际是设定电压上限
/// <summary>
/// 设置恒流 (CC) 模式的电压上限 (VOLTage:LIMit:POSitive 指令)
/// </summary>
/// <param name="电流">电压上限设定值 (单位: V),沿用原参数名</param>
/// <param name="ct">取消令牌</param>
public async Task CC电压H(double , CancellationToken ct = default)
{
await SendAsync($"VOLTage:LIMit:POSitive {电流}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"VOLTage:LIMit:POSitive {电流}{ScpiDelimiter}", ct);
}
public async Task CC电压L(double , CancellationToken ct = default) // 沿用原参数名“电流”,实际是设定电压下限
/// <summary>
/// 设置恒流 (CC) 模式的电压下限 (VOLTage:LIMit:NEGative 指令)
/// </summary>
/// <param name="电流">电压下限设定值 (单位: V),沿用原参数名</param>
/// <param name="ct">取消令牌</param>
public async Task CC电压L(double , CancellationToken ct = default)
{
await SendAsync($"VOLTage:LIMit:NEGative {电流}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"VOLTage:LIMit:NEGative {电流}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置恒压 (CV) 模式的正向电流限制 (CURRent:LIMit:POSitive 指令)
/// </summary>
/// <param name="电流">正向电流限制值 (单位: A)</param>
/// <param name="ct">取消令牌</param>
public async Task CV正向电流(double , CancellationToken ct = default)
{
await SendAsync($"CURRent:LIMit:POSitive {电流}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"CURRent:LIMit:POSitive {电流}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置恒压 (CV) 模式的反向电流限制 (CURRent:LIMit:NEGative 指令)
/// </summary>
/// <param name="电流">反向电流限制值 (单位: A),负载模式需传负值</param>
/// <param name="ct">取消令牌</param>
public async Task CV反向电流(double , CancellationToken ct = default)
{
// 提醒: 此处传入的参数如果是正数建议在外部或此处转换为负值,因为载模式限制需要负数[cite: 1]
// 载模式限制需要负数,若传入正数建议在外部转换为负值
await SendAsync($"CURRent:LIMit:NEGative {电流}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置正向功率阈值 (POWer:LIMit:POSitive 指令)
/// </summary>
/// <param name="功率">正向功率阈值 (单位: W)</param>
/// <param name="ct">取消令牌</param>
public async Task (double , CancellationToken ct = default)
{
await SendAsync($"POWer:LIMit:POSitive {功率}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"POWer:LIMit:POSitive {功率}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置反向功率阈值 (POWer:LIMit:NEGative 指令)
/// </summary>
/// <param name="功率">反向功率阈值 (单位: W),必须为负数</param>
/// <param name="ct">取消令牌</param>
public async Task (double , CancellationToken ct = default)
{
// 提醒: 此处传入的参数必须为负数[cite: 1]
await SendAsync($"POWer:LIMit:NEGative {功率}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置输出电压值 (VOLTage 指令)
/// </summary>
/// <param name="电压">电压设定值 (单位: V)</param>
/// <param name="ct">取消令牌</param>
public async Task (double , CancellationToken ct = default)
{
await SendAsync($"VOLTage {电压}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"VOLTage {电压}{ScpiDelimiter}", ct);
}
/// <summary>
/// 清除保护状态 (OUTPut:PROTection:CLEar 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
public async Task (CancellationToken ct = default)
{
await SendAsync($"OUTPut:PROTection:CLEar{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"OUTPut:PROTection:CLEar{ScpiDelimiter}", ct);
}
/// <summary>
/// 开启或关闭过流保护 (OCP) 功能 (CURRent:PROTection:STATe 指令)
/// </summary>
/// <param name="v">true: 开启过流保护, false: 关闭过流保护</param>
/// <param name="ct">取消令牌</param>
public async Task OCP开关(bool v, CancellationToken ct = default)
{
await SendAsync($"CURRent:PROTection:STATe {(v ? 1 : 0)}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"CURRent:PROTection:STATe {(v ? 1 : 0)}{ScpiDelimiter}", ct);
}
/// <summary>
/// 开启或关闭过压保护 (OVP) 功能 (VOLTage:PROTection:STATe 指令)
/// </summary>
/// <param name="v">true: 开启过压保护, false: 关闭过压保护</param>
/// <param name="ct">取消令牌</param>
public async Task OVP开关(bool v, CancellationToken ct = default)
{
await SendAsync($"VOLTage:PROTection:STATe {(v ? 1 : 0)}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"VOLTage:PROTection:STATe {(v ? 1 : 0)}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置过压保护 (OVP) 的触发电压值 (VOLTage:PROTection 指令)
/// </summary>
/// <param name="oVP电压">过压保护触发电压值 (单位: V)</param>
/// <param name="ct">取消令牌</param>
public async Task OVP电压(double oVP电压, CancellationToken ct = default)
{
await SendAsync($"VOLTage:PROTection {oVP电压}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"VOLTage:PROTection {oVP电压}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置过流保护 (OCP) 的触发电流值 (CURRent:PROTection 指令)
/// </summary>
/// <param name="oCP电流">过流保护触发电流值 (单位: A)</param>
/// <param name="ct">取消令牌</param>
public async Task OCP电流(double oCP电流, CancellationToken ct = default)
{
await SendAsync($"CURRent:PROTection {oCP电流}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"CURRent:PROTection {oCP电流}{ScpiDelimiter}", ct);
}
/// <summary>
/// 开启或关闭过功率保护 (OPP) 功能 (POWer:PROTection:STATe 指令)
/// </summary>
/// <param name="v">true: 开启过功率保护, false: 关闭过功率保护</param>
/// <param name="ct">取消令牌</param>
public async Task (bool v, CancellationToken ct = default)
{
await SendAsync($"POWer:PROTection:STATe {(v ? 1 : 0)}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"POWer:PROTection:STATe {(v ? 1 : 0)}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置过功率保护 (OPP) 的触发功率值 (POWer:PROTection 指令)
/// </summary>
/// <param name="oPP功率">过功率保护触发功率值 (单位: W)</param>
/// <param name="ct">取消令牌</param>
public async Task (double oPP功率, CancellationToken ct = default)
{
await SendAsync($"POWer:PROTection {oPP功率}{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"POWer:PROTection {oPP功率}{ScpiDelimiter}", ct);
}
/// <summary>
/// 发送自定义 SCPI 指令
/// </summary>
/// <param name="指令">自定义指令字符串</param>
/// <param name="ct">取消令牌</param>
public async Task (string , CancellationToken ct = default)
{
await SendAsync($"{指令}{ScpiDelimiter}", ct);
@@ -185,29 +363,49 @@ namespace DeviceCommand.Devices
#region
/// <summary>
/// 查询设备识别信息 (*IDN? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>设备标识字符串 (制造商, 型号, 序列号, 固件版本)</returns>
public async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 查询实时输出电压 (MEASure:VOLTage? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>实时电压值 (单位: V,保留两位小数)</returns>
public async Task<double> (CancellationToken ct = default)
{
var str = await WriteReadAsync($"MEASure:VOLTage?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
return double.TryParse(str, out double result) ? result : 0;
var str = await WriteReadAsync($"MEASure:VOLTage?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(str);
}
/// <summary>
/// 查询实时输出电流 (MEASure:CURRent? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>实时电流值 (单位: A,保留两位小数)</returns>
public async Task<double> (CancellationToken ct = default)
{
var str = await WriteReadAsync($"MEASure:CURRent?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
return double.TryParse(str, out double result) ? result : 0;
var str = await WriteReadAsync($"MEASure:CURRent?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(str);
}
/// <summary>
/// 查询实时功率 (MEASure:POWer? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>实时功率值 (单位: W,保留两位小数)</returns>
public async Task<double> (CancellationToken ct = default)
{
var str = await WriteReadAsync($"MEASure:POWer?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
return double.TryParse(str, out double result) ? result : 0;
var str = await WriteReadAsync($"MEASure:POWer?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(str);
}
#endregion
}
}
}
+143 -42
View File
@@ -5,6 +5,7 @@ using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -37,22 +38,48 @@ namespace DeviceCommand.Devices
/// </summary>
public enum TekMeasurementType
{
/// <summary>幅度</summary>
AMPLitude,
/// <summary>频率</summary>
FREQuency,
/// <summary>平均值</summary>
MEAN,
/// <summary>峰峰值</summary>
PK2PK,
/// <summary>最大值</summary>
MAXimum,
/// <summary>最小值</summary>
MINimum
}
#endregion
/// <summary>
/// Tektronix 示波器 (MSO 4/5/6 系列),支持采集控制、通道设置、自动测量与截图导出
/// </summary>
[ACPCommand]
public class TektronixMSO : Tcp
{
// SCPI 指令结束符 (消息终止符需使用 LF)
private const string ScpiDelimiter = "\n";
/// <summary>
/// 从设备返回的 SCPI 响应字符串中提取数值部分并转换为 double。
/// 支持科学计数法(如 2.48E-03),结果保留两位小数。
/// </summary>
/// <param name="raw">设备返回的原始字符串</param>
/// <returns>提取到的数值(保留两位小数),解析失败时返回 0</returns>
private static double ExtractDouble(string raw)
{
if (string.IsNullOrWhiteSpace(raw)) return 0;
// 从响应中提取第一个数值(含正负号、小数点、科学计数法),可自动忽略单位后缀与命令头
var match = Regex.Match(raw, @"[+-]?(?:\d+\.?\d*|\.\d+)(?:[Ee][+-]?\d+)?");
return match.Success && double.TryParse(match.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double val)
? Math.Round(val, 2)
: 0;
}
#region MSO44B ACP
public enum AcquireMode { Sample = 0, PeakDetect = 1, HiRes = 2, Average = 3, Envelope = 4 }
@@ -81,21 +108,32 @@ namespace DeviceCommand.Devices
#region 1.
/// <summary>
/// 查询仪器识别码 (*IDN? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>设备标识字符串 (制造商, 型号, 序列号, 固件版本)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
// 返回仪器的标识代码[cite: 2]
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 查询仪器是否处于忙碌状态,常用于同步操作 (BUSY? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>忙碌状态字符串 (0: 空闲, 1: 忙碌)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
// 查询仪器是否处于忙碌状态,常用于同步操作[cite: 2]
return await WriteReadAsync($"BUSY?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 指示仪器执行信号路径校准 (SPC) (*CAL? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task (CancellationToken ct = default)
{
// 指示仪器执行信号路径校准 (SPC)[cite: 2]
await SendAsync($"*CAL?{ScpiDelimiter}", ct);
}
@@ -104,24 +142,33 @@ namespace DeviceCommand.Devices
#region 2. (Acquisition)
/// <summary>
/// 启动或停止采集
/// 启动或停止采集 (ACQuire:STATE 指令)
/// </summary>
/// <param name="运行">true: 启动采集 (RUN), false: 停止采集 (STOP)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (bool , CancellationToken ct = default)
{
// 启动、停止或返回采集状态[cite: 2]
string = ? "RUN" : "STOP";
await SendAsync($"ACQuire:STATE {参数}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询当前采集状态 (ACQuire:STATE? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>采集状态字符串 (RUN / STOP)</returns>
public virtual async Task<string> (CancellationToken ct = default)
{
// 启动、停止或返回采集状态[cite: 2]
return await WriteReadAsync($"ACQuire:STATE?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 设置采集模式 (ACQuire:MODe 指令)
/// </summary>
/// <param name="模式">采集模式枚举 (采样/峰值检测/高分辨率/平均/包络)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (TekAcquisitionMode , CancellationToken ct = default)
{
// 设置或查询采集模式[cite: 2]
await SendAsync($"ACQuire:MODe {模式}{ScpiDelimiter}", ct);
}
@@ -129,23 +176,36 @@ namespace DeviceCommand.Devices
#region 3. (Horizontal)
/// <summary>
/// 设置水平刻度 (Scale),即每格代表的时间 (HORizontal:SCAle 指令)
/// </summary>
/// <param name="秒每格">水平刻度值 (单位: s/Div)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (double , CancellationToken ct = default)
{
// 设置或查询水平刻度 (Scale)[cite: 2]
string cmd = string.Format(CultureInfo.InvariantCulture, "HORizontal:SCAle {0:E}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 设置水平记录长度 (HORizontal:RECOrdlength 指令)
/// </summary>
/// <param name="长度">记录长度(采样点数)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (long , CancellationToken ct = default)
{
// 设置或查询水平记录长度[cite: 2]
await SendAsync($"HORizontal:RECOrdlength {长度}{ScpiDelimiter}", ct);
}
public virtual async Task<string> (CancellationToken ct = default)
/// <summary>
/// 查询水平采样率 (HORizontal:SAMPLERate? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>水平采样率 (单位: Sa/s,保留两位小数)</returns>
public virtual async Task<double> (CancellationToken ct = default)
{
// 查询水平采样率[cite: 2]
return await WriteReadAsync($"HORizontal:SAMPLERate?{ScpiDelimiter}", ScpiDelimiter, ct);
string resp = await WriteReadAsync($"HORizontal:SAMPLERate?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
#endregion
@@ -153,18 +213,23 @@ namespace DeviceCommand.Devices
#region 4. (Vertical)
/// <summary>
/// 全局启用或关闭某通道的显示
/// 全局启用或关闭某通道的显示 (DISplay:GLObal:CH:STATE 指令)
/// </summary>
/// <param name="通道号">通道编号 (1 - 4)</param>
/// <param name="开启">true: 开启通道显示, false: 关闭通道显示</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int , bool , CancellationToken ct = default)
{
// 4/5/6 Series MSO 标准通道显示指令[cite: 2]
string = ? "ON" : "OFF";
await SendAsync($"DISplay:GLObal:CH{通道号}:STATE {参数}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置指定通道的垂直缩放比例 (Volts/Div)
/// 设置指定通道的垂直缩放比例 (CH:SCAle 指令)
/// </summary>
/// <param name="通道号">通道编号 (1 - 4)</param>
/// <param name="伏特每格">垂直刻度值 (单位: V/Div)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int , double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "CH{0}:SCAle {1:E}{2}", , , ScpiDelimiter);
@@ -172,8 +237,11 @@ namespace DeviceCommand.Devices
}
/// <summary>
/// 设置指定通道的垂直位置 (Divisions)
/// 设置指定通道的垂直位置 (CH:POSition 指令)
/// </summary>
/// <param name="通道号">通道编号 (1 - 4)</param>
/// <param name="格数">垂直位置偏移 (单位: Div)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int , double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "CH{0}:POSition {1:F2}{2}", , , ScpiDelimiter);
@@ -185,43 +253,73 @@ namespace DeviceCommand.Devices
#region 5. (Measurement)
/// <summary>
/// 动态添加并开启一个测量项
/// 动态添加并开启一个测量项 (MEASUrement:ADDNew 指令)。
/// 4/5/6 Series MSO 必须先动态创建测量项
/// </summary>
/// <param name="测量项编号">测量项编号</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int , CancellationToken ct = default)
{
// 4/5/6 Series MSO 必须先动态创建测量项[cite: 2]
await SendAsync($"MEASUrement:ADDNew \"MEAS{}\"{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置测量项的测量类型 (MEASUrement:TYPe 指令)
/// </summary>
/// <param name="测量项编号">测量项编号</param>
/// <param name="类型">测量类型枚举 (幅度/频率/平均值/峰峰值等)</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int , TekMeasurementType , CancellationToken ct = default)
{
// 设置或查询测量类型[cite: 2]
await SendAsync($"MEASUrement:MEAS{测量项编号}:TYPe {类型}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置测量项的测量源 (MEASUrement:SOUrce1 指令)
/// </summary>
/// <param name="测量项编号">测量项编号</param>
/// <param name="源名称">测量源名称 (如 "CH1", "CH2")</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int , string , CancellationToken ct = default)
{
// 4/5/6 Series 中设置测量源[cite: 2]
await SendAsync($"MEASUrement:MEAS{测量项编号}:SOUrce1 {源名称}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询测量项的当前采集平均值 (MEASUrement:RESUlts:CURRentacq:MEAN? 指令)
/// </summary>
/// <param name="测量项编号">测量项编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>测量项当前采集的平均值 (保留两位小数)</returns>
[Monitorable("测量项的当前采集平均值")]
public virtual async Task<string> (int , CancellationToken ct = default)
public virtual async Task<double> (int , CancellationToken ct = default)
{
// 4/5/6 Series 获取当前采集值的标准方式,查询平均值[cite: 2]
return await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:CURRentacq:MEAN?{ScpiDelimiter}", ScpiDelimiter, ct);
string resp = await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:CURRentacq:MEAN?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
public virtual async Task<string> (int , CancellationToken ct = default)
/// <summary>
/// 查询测量项的全局历史累积平均值 (MEASUrement:RESUlts:ALLAcqs:MEAN? 指令)
/// </summary>
/// <param name="测量项编号">测量项编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>测量项全局平均值 (保留两位小数)</returns>
public virtual async Task<double> (int , CancellationToken ct = default)
{
// 获取所有采集(AllAcqs)历史累积的平均值[cite: 2]
return await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:ALLAcqs:MEAN?{ScpiDelimiter}", ScpiDelimiter, ct);
string resp = await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:ALLAcqs:MEAN?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
public virtual async Task<string> (int , CancellationToken ct = default)
/// <summary>
/// 查询测量项的全局历史累积最大值 (MEASUrement:RESUlts:ALLAcqs:MAXimum? 指令)
/// </summary>
/// <param name="测量项编号">测量项编号</param>
/// <param name="ct">取消令牌</param>
/// <returns>测量项全局最大值 (保留两位小数)</returns>
public virtual async Task<double> (int , CancellationToken ct = default)
{
// 获取所有采集(AllAcqs)历史累积的最大值[cite: 2]
return await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:ALLAcqs:MAXimum?{ScpiDelimiter}", ScpiDelimiter, ct);
string resp = await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:ALLAcqs:MAXimum?{ScpiDelimiter}", ScpiDelimiter, ct);
return ExtractDouble(resp);
}
#endregion
@@ -237,13 +335,13 @@ namespace DeviceCommand.Devices
{
string = "E:/temp1.png";
// 1. 直接保存截图到示波器U盘 (自动识别 .png 扩展名)[cite: 2]
// 1. 直接保存截图到示波器U盘 (自动识别 .png 扩展名)
await SendAsync($"SAVe:IMAGe \"{}\"{ScpiDelimiter}", ct);
// 2. 发送 *OPC? 并等待返回 1,确保图像文件已经完全写入磁盘[cite: 2]
// 2. 发送 *OPC? 并等待返回 1,确保图像文件已经完全写入磁盘
await WriteReadAsync($"*OPC?{ScpiDelimiter}", ScpiDelimiter, ct);
// 3. 将文件内容读取到当前通信接口[cite: 2]
// 3. 将文件内容读取到当前通信接口
await SendAsync($"FILESystem:READFile \"{}\"{ScpiDelimiter}", ct);
// 4. 提取底层的二进制块 (Block Data)
@@ -252,7 +350,7 @@ namespace DeviceCommand.Devices
// 5. 将提取的二进制字节流写入上位机本地磁盘
await File.WriteAllBytesAsync(, imageBytes, ct);
// 6. 删除示波器上的临时文件,保持设备存储干净[cite: 2]
// 6. 删除示波器上的临时文件,保持设备存储干净
await SendAsync($"FILESystem:DELEte \"{}\"{ScpiDelimiter}", ct);
}
@@ -331,41 +429,44 @@ namespace DeviceCommand.Devices
#region 7. (Status and Error)
/// <summary>
/// 清除所有的状态寄存器和错误/事件队列
/// 清除所有的状态寄存器和错误/事件队列 (*CLS 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
public virtual async Task Async(CancellationToken ct = default)
{
// 发送 *CLS 指令清空状态[cite: 2]
await SendAsync($"*CLS{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询错误队列中当前的事件/错误数量
/// 查询错误队列中当前的事件/错误数量 (EVQty? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>事件队列中的事件数量字符串</returns>
public virtual async Task<string> Async(CancellationToken ct = default)
{
// 返回事件队列中的事件数量
return await WriteReadAsync($"EVQty?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 从错误队列中读取最早的一个事件/错误(包含代码和详细消息),并将其从队列中弹出
/// 从错误队列中读取最早的一个事件/错误(包含代码和详细消息),并将其从队列中弹出 (EVMsg? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>事件代码和消息字符串</returns>
public virtual async Task<string> Async(CancellationToken ct = default)
{
// 返回事件队列中的事件代码和消息
return await WriteReadAsync($"EVMsg?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 读取并清空队列中的所有错误和事件消息
/// 读取并清空队列中的所有错误和事件消息 (ALLEv? 指令)
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>所有事件及其消息字符串</returns>
public virtual async Task<string> Async(CancellationToken ct = default)
{
// 返回所有事件及其消息
return await WriteReadAsync($"ALLEv?{ScpiDelimiter}", ScpiDelimiter, ct);
}
#endregion
}
}
}