示波器修改
This commit is contained in:
@@ -3,7 +3,7 @@ using DeviceCommand.Base;
|
||||
using Model.Models;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -17,21 +17,22 @@ namespace DeviceCommand.Devices
|
||||
private const string ScpiDelimiter = "\n";
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数:传入 <see cref="TcpConfig"/> 一次性初始化示波器通信参数。
|
||||
/// 构造函数:一次性初始化示波器通信参数。
|
||||
/// </summary>
|
||||
/// <param name="config">TCP 通信配置对象,包含 IP 地址和端口号等信息</param>
|
||||
public SDS2000X_HD(TcpConfig config) : base(config)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从示波器返回的 SCPI 响应字符串中提取数值部分并转换为 double。
|
||||
/// 响应格式示例: "C1:PAVA PKPK,2.48E-03V" → 按逗号分割后提取 2.48E-03
|
||||
/// 响应格式示例: "PKPK,2.48E-03V" → 按逗号分割后提取 2.48E-03
|
||||
/// </summary>
|
||||
/// <param name="raw">示波器返回的原始字符串</param>
|
||||
/// <returns>提取到的数值,解析失败时返回 0</returns>
|
||||
/// <returns>提取到的数值,解析失败或字符串为空时返回 0</returns>
|
||||
private static double ExtractDouble(string raw)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(raw)) return 0;
|
||||
if (string.IsNullOrWhiteSpace(raw)) return 0;
|
||||
|
||||
string dataPart = raw;
|
||||
// 按逗号分割,取最后一段(数值通常在逗号后面)
|
||||
@@ -49,46 +50,50 @@ namespace DeviceCommand.Devices
|
||||
#region 1. IEEE 488.2 公共命令
|
||||
|
||||
/// <summary>
|
||||
/// 清除标准事件状态寄存器和错误队列
|
||||
/// 清除标准事件状态寄存器和错误队列 (*CLS)。
|
||||
/// </summary>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 清除状态(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"*CLS{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询错误信息
|
||||
/// 查询错误信息。
|
||||
/// </summary>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <returns>错误代码和描述信息</returns>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>示波器返回的错误代码和描述信息的字符串</returns>
|
||||
public virtual async Task<string> 查询错误信息(CancellationToken ct = default)
|
||||
{
|
||||
return await WriteReadAsync($":SYSTem:ERRor?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
|
||||
return await WriteReadAsync($":SYSTem:ERRor?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取示波器识别字符串(制造商、型号、序列号、固件版本)
|
||||
/// 读取示波器识别字符串(制造商、型号、序列号、固件版本)。
|
||||
/// </summary>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <returns>设备标识字符串(制造商, 型号, 序列号, 固件版本)</returns>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>设备标识字符串(如 "Siglent Technologies,SDS2004X HD,...")</returns>
|
||||
public virtual async Task<string> 查询设备标识(CancellationToken ct = default)
|
||||
{
|
||||
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复位命令。使示波器恢复到默认的出厂设置
|
||||
/// 复位命令 (*RST)。使示波器恢复到默认的出厂设置。
|
||||
/// </summary>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 重置设备(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"*RST{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询先前操作是否完成。
|
||||
/// 查询先前操作是否完成 (*OPC?)。
|
||||
/// </summary>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <returns>true: 操作已完成, false: 操作仍在执行中</returns>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>布尔值:true 表示所有挂起的操作已完成,false 表示操作仍在执行中</returns>
|
||||
public virtual async Task<bool> 检查操作完成_OPC(CancellationToken ct = default)
|
||||
{
|
||||
string res = await WriteReadAsync($"*OPC?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||
@@ -97,147 +102,129 @@ namespace DeviceCommand.Devices
|
||||
|
||||
#endregion
|
||||
|
||||
#region 2. 运行与捕获控制 (Run / Stop / Single)
|
||||
#region 2. 运行与捕获控制 (Run / Stop / Trigger Mode)
|
||||
|
||||
/// <summary>
|
||||
/// 控制示波器开始捕获波形
|
||||
/// 控制示波器开始连续捕获波形。
|
||||
/// </summary>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 启动捕获_RUN(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($":TRIGger:RUN{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止捕获波形
|
||||
/// 停止捕获波形,画面将定格在当前捕捉的帧。
|
||||
/// </summary>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 停止捕获_STOP(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"TRIGger:STOP{ScpiDelimiter}", ct);
|
||||
await SendAsync($":TRIGger:STOP{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制示波器进入单次触发捕获模式
|
||||
/// </summary>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
public virtual async Task 单次触发_SINGLE(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($":TRIGger:MODE SINGle{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发一次波形采样
|
||||
/// </summary>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
public virtual async Task 强制触发(CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"::TRIGger:MODE FTRIG{ScpiDelimiter}", ct);
|
||||
}
|
||||
/// <summary>
|
||||
/// 示波器触发控制模式(符合 SDS2000X-HD 规范)。
|
||||
/// </summary>
|
||||
public enum TriggerMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动触发模式 (即使无触发信号也周期性刷屏)
|
||||
/// </summary>
|
||||
/// <summary>自动触发模式 (即使无触发信号也周期性刷屏)</summary>
|
||||
AUTO,
|
||||
|
||||
/// <summary>
|
||||
/// 普通触发模式 (仅当满足触发条件时才刷新)
|
||||
/// </summary>
|
||||
NORM,
|
||||
|
||||
/// <summary>
|
||||
/// 单次触发模式 (捕捉到一次满足条件的信号后立刻 STOP)
|
||||
/// </summary>
|
||||
SINGLE
|
||||
/// <summary>普通触发模式 (仅当满足触发条件时才刷新)</summary>
|
||||
NORMal,
|
||||
/// <summary>单次触发模式 (捕捉到一次满足条件的信号后立刻 STOP)</summary>
|
||||
SINGle
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置触发模式 (AUTO 自动, NORM 普通, SINGLE 单次)
|
||||
/// 设置触发模式。
|
||||
/// </summary>
|
||||
/// <param name="mode">触发模式枚举</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <param name="mode">触发模式枚举 (AUTO 自动, NORMal 普通, SINGle 单次)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置触发模式(TriggerMode mode, CancellationToken ct = default)
|
||||
{
|
||||
// 例如发送:TRMD AUTO\n、TRMD NORM\n 或 TRMD SINGLE\n
|
||||
string cmd = $"TRMD {mode}{ScpiDelimiter}";
|
||||
string cmd = $":TRIGger:MODE {mode}{ScpiDelimiter}";
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 3. Channel 垂直控制子系统 (C1 ~ C4)
|
||||
#region 3. Channel 垂直控制子系统 (电压/电流纹波测试依赖此项)
|
||||
|
||||
/// <summary>
|
||||
/// 开启或关闭指定的模拟通道 (符合手册 57 页规范)
|
||||
/// 开启或关闭指定的模拟通道。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="enable">true: 开启通道, false: 关闭通道</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <param name="enable">布尔值:true 表示开启通道, false 表示关闭通道</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置通道开关(int channel, bool enable, CancellationToken ct = default)
|
||||
{
|
||||
string state = enable ? "ON" : "OFF";
|
||||
await SendAsync($"C{channel}:TRAce {state}{ScpiDelimiter}", ct);
|
||||
await SendAsync($":CHANnel{channel}:SWITch {state}{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定通道的垂直电压档位 (Volts/Div)
|
||||
/// 设置指定通道的物理单位,用于区分测电压还是测电流,影响测量结果读数。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="volts">电压档位 (Volts/Div)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
public virtual async Task 设置通道电压档位(int channel, double volts, CancellationToken ct = default)
|
||||
/// <param name="unit">字符串:"V" 代表电压,"A" 代表电流</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置通道单位(int channel, string unit, CancellationToken ct = default)
|
||||
{
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, "C{0}:VDIV {1:F4}{2}", channel, volts, ScpiDelimiter);
|
||||
await SendAsync($":CHANnel{channel}:UNIT {unit.ToUpper()}{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定通道的垂直档位 (Volts/Div 或 Amps/Div)。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="value">档位数值 (例如 0.05 表示 50mV/div 或 50mA/div)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置通道档位(int channel, double value, CancellationToken ct = default)
|
||||
{
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, ":CHANnel{0}:SCALe {1:E4}{2}", channel, value, ScpiDelimiter);
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
public enum ChannelCoupling { DC, AC, GND }
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定通道当前的电压档位
|
||||
/// 设置通道耦合方式 (测纹波时必须设置为 AC 交流耦合)。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <returns>当前电压档位值 (Volts/Div)</returns>
|
||||
public virtual async Task<double> 查询通道电压档位(int channel, CancellationToken ct = default)
|
||||
/// <param name="coupling">耦合方式枚举 (DC, AC, GND)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置通道耦合(int channel, ChannelCoupling coupling, CancellationToken ct = default)
|
||||
{
|
||||
string res = await WriteReadAsync($"C{channel}:VDIV?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||
return ExtractDouble(res);
|
||||
await SendAsync($":CHANnel{channel}:COUPling {coupling}{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定通道的垂直偏移量 (Offset)
|
||||
/// 设置通道带宽限制 (测纹波时通常设置为 20M 带宽限制以滤除高频噪声)。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="offset">垂直偏移量 (单位: V)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <param name="limit">带宽限制参数的字符串 (可选: "20M", "200M", "FULL")</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置通道带宽限制(int channel, string limit, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($":CHANnel{channel}:BWLimit {limit.ToUpper()}{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置通道的垂直偏移量,用于调整波形在屏幕上的垂直位置。
|
||||
/// 泄放测试中需要设置合适的偏移使衰减波形完整显示在屏幕内。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="offset">垂直偏移值 (单位:V 或 A,正值向上移动,负值向下移动)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置通道垂直偏移(int channel, double offset, CancellationToken ct = default)
|
||||
{
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, "C{0}:OFST {1:F4}{2}", channel, offset, ScpiDelimiter);
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
/// <summary>
|
||||
/// 示波器通道输入阻抗类型。
|
||||
/// </summary>
|
||||
public enum ImpedanceType
|
||||
{
|
||||
/// <summary>50Ω 阻抗</summary>
|
||||
FIFty,
|
||||
|
||||
/// <summary>1MΩ 阻抗</summary>
|
||||
ONEM
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定通道的输入阻抗类型
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="impedance">阻抗类型枚举 (FIFty: 50Ω, ONEM: 1MΩ)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
public virtual async Task 设置通道阻抗(int channel, ImpedanceType impedance, CancellationToken ct = default)
|
||||
{
|
||||
// 例如发送:C1:IMPedance FIFty\n 或 C1:IMPedance ONEM\n
|
||||
string cmd = $"CHANnel{channel}:IMPedance {impedance}{ScpiDelimiter}";
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, ":CHANnel{0}:OFFSet {1:F3}{2}", channel, offset, ScpiDelimiter);
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
@@ -246,168 +233,199 @@ namespace DeviceCommand.Devices
|
||||
#region 4. Timebase 水平时基子系统
|
||||
|
||||
/// <summary>
|
||||
/// 设置示波器的水平时基档位 (Time/Div)
|
||||
/// 设置示波器的水平时基档位 (Time/Div)。
|
||||
/// </summary>
|
||||
/// <param name="scale">水平时基档位 (Time/Div)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <param name="scale">水平时基数值 (单位:秒/格,如 1.00E-03 表示 1ms/div)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置水平时基(double scale, CancellationToken ct = default)
|
||||
{
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, "TDIV {0:E6}{1}", scale, ScpiDelimiter);
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置示波器的触发水平延迟位置 (Horizontal Delay)
|
||||
/// </summary>
|
||||
/// <param name="delay">水平延迟位置 (单位: s)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
public virtual async Task 设置水平延迟(double delay, CancellationToken ct = default)
|
||||
{
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, "TRDL {0:E6}{1}", delay, ScpiDelimiter);
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, ":TIMebase:SCALe {0:E6}{1}", scale, ScpiDelimiter);
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 5. Trigger 触发子系统
|
||||
#region 5. Trigger 触发设置子系统
|
||||
|
||||
/// <summary>
|
||||
/// 设置边沿触发的电平值 (Trigger Level)
|
||||
/// 设置边沿触发的触发源。
|
||||
/// </summary>
|
||||
/// <param name="level">触发电平值 (单位: V)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
public virtual async Task 设置触发电平(double level, CancellationToken ct = default)
|
||||
/// <param name="source">触发源标识符的字符串 (例如: "C1", "C2", "EX", "LINE")</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置边沿触发源(string source, CancellationToken ct = default)
|
||||
{
|
||||
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, "TRIGger:EDGE:LEVel {0:F3}{1}", level, ScpiDelimiter);
|
||||
await SendAsync(cmd, ct);
|
||||
await SendAsync($":TRIGger:EDGE:SOURce {source.ToUpper()}{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置边沿触发的触发源 (例如: C1, C2, C3, C4, EX, LINE)
|
||||
/// 设置边沿触发的电平值。
|
||||
/// </summary>
|
||||
/// <param name="source">触发源通道标识 (例如: "C1", "C2", "EX", "LINE")</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
public virtual async Task 设置触发源(string source, CancellationToken ct = default)
|
||||
/// <param name="level">触发电平数值 (根据通道单位,通常为 V 或 A)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置边沿触发电平(double level, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($"TRSE EDGE,SR,{source.ToUpper()}{ScpiDelimiter}", ct);
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, ":TRIGger:EDGE:LEVel {0:F3}{1}", level, ScpiDelimiter);
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
public enum TriggerSlope { RISing, FALLing, ALTernate }
|
||||
|
||||
/// <summary>
|
||||
/// 设置边沿触发的斜率类型 (测试 AC 泄放时间需使用 FALLing 下降沿)。
|
||||
/// </summary>
|
||||
/// <param name="slope">斜率枚举类型 (RISing 上升沿, FALLing 下降沿, ALTernate 任意沿)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置边沿触发斜率(TriggerSlope slope, CancellationToken ct = default)
|
||||
{
|
||||
await SendAsync($":TRIGger:EDGE:SLOPe {slope}{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 6. Measure 自动测量参数回读
|
||||
#region 6. Cursor 光标子系统 (用于计算启动时间、泄放时间的 ΔT)
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定通道自动测量项的当前实时测量数值
|
||||
/// 开启手动光标并设置为 X 轴(时间轴)测量模式。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="paramName">测量参数名称 (如 "PKPK", "FREQ", "RMS" 等)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <returns>测量参数的实时数值 (double)</returns>
|
||||
public virtual async Task<double> 查询通道测量项参数(int channel, string paramName, CancellationToken ct = default)
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 开启手动X光标(CancellationToken ct = default)
|
||||
{
|
||||
string query = string.Format(CultureInfo.InvariantCulture, "C{0}:PAVA? {1}{2}", channel, paramName.ToUpper(), ScpiDelimiter);
|
||||
string res = await WriteReadAsync(query, ScpiDelimiter, ct);
|
||||
await SendAsync($":CURSor:MODE MANual,X{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置 X1 光标的绝对位置。
|
||||
/// </summary>
|
||||
/// <param name="position">光标在时间轴上的位置 (单位:秒)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置光标X1位置(double position, CancellationToken ct = default)
|
||||
{
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, ":CURSor:X1 {0:E6}{1}", position, ScpiDelimiter);
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置 X2 光标的绝对位置。
|
||||
/// </summary>
|
||||
/// <param name="position">光标在时间轴上的位置 (单位:秒)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置光标X2位置(double position, CancellationToken ct = default)
|
||||
{
|
||||
string cmd = string.Format(CultureInfo.InvariantCulture, ":CURSor:X2 {0:E6}{1}", position, ScpiDelimiter);
|
||||
await SendAsync(cmd, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询光标 X2 和 X1 当前位置的时间差 (ΔT = X2 - X1)。
|
||||
/// </summary>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>返回 X 轴两光标之间的时间差数值 (double 类型,单位:秒)</returns>
|
||||
public virtual async Task<double> 查询光标X时间差(CancellationToken ct = default)
|
||||
{
|
||||
string res = await WriteReadAsync($":CURSor:XDELta?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||
return ExtractDouble(res);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 7. Measure 基本测量子系统 (测试纹波PKPK、冲击电流MAX)
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定通道的电压峰峰值 (Vpp)
|
||||
/// 设置基本测量系统的全局参考信源。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <returns>电压峰峰值 (Vpp)</returns>
|
||||
public virtual async Task<double> 查询实际电压峰峰值(int channel, CancellationToken ct = default)
|
||||
/// <param name="channel">作为测量对象的通道号 (1 - 4)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置基本测量源(int channel, CancellationToken ct = default)
|
||||
{
|
||||
return await 查询通道测量项参数(channel, "PKPK", ct);
|
||||
await SendAsync($":MEASure:SIMPle:SOURce C{channel}{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定通道的频率值 (Frequency)
|
||||
/// 开启或关闭某项基本测量参数 (在屏幕下方显示或隐藏该测量项)。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <returns>频率值 (单位: Hz)</returns>
|
||||
public virtual async Task<double> 查询实际频率(int channel, CancellationToken ct = default)
|
||||
/// <param name="parameter">要设置的测量参数名称 (如: "PKPK", "MAX", "MIN")</param>
|
||||
/// <param name="enable">布尔值:true 表示开启显示, false 表示关闭</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>表示异步操作的 Task</returns>
|
||||
public virtual async Task 设置基本测量项(string parameter, bool enable, CancellationToken ct = default)
|
||||
{
|
||||
return await 查询通道测量项参数(channel, "FREQ", ct);
|
||||
string state = enable ? "ON" : "OFF";
|
||||
await SendAsync($":MEASure:SIMPle:ITEM {parameter.ToUpper()},{state}{ScpiDelimiter}", ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定通道的真均方根电压值 (Vrms)
|
||||
/// 查询基本测量中指定测量项的当前实时数值。
|
||||
/// </summary>
|
||||
/// <param name="channel">通道号 (1 - 4)</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <returns>真均方根电压值 (Vrms)</returns>
|
||||
public virtual async Task<double> 查询实际电压均方根(int channel, CancellationToken ct = default)
|
||||
/// <param name="type">要查询的测量参数名称 (如: "PKPK" 获取峰峰值, "MAX" 获取最大值)</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>返回该测量参数提取到的实时数值 (double 类型)</returns>
|
||||
public virtual async Task<double> 查询基本测量值(string type, CancellationToken ct = default)
|
||||
{
|
||||
return await 查询通道测量项参数(channel, "RMS", ct);
|
||||
string res = await WriteReadAsync($":MEASure:SIMPle:VALue? {type.ToUpper()}{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||
return ExtractDouble(res);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 7. 屏幕截图导出子系统
|
||||
#region 8. 屏幕截图导出子系统
|
||||
|
||||
/// <summary>
|
||||
/// 【一键获取并保存截图】
|
||||
/// 自动下发 :PRINt? PNG 指令,接收示波器返回的纯 PNG 二进制流并直接保存到指定路径。
|
||||
/// 自动下发 :PRINt? PNG 指令,接收示波器返回的纯 PNG 二进制流并直接保存到上位机本地作测试记录。
|
||||
/// </summary>
|
||||
/// <param name="saveFilePath">本地绝对保存路径 (例如: @"D:\Oscilloscope\Screen_01.png")</param>
|
||||
/// <param name="ct">取消令牌</param>
|
||||
/// <returns>返回是否获取并保存成功</returns>
|
||||
/// <param name="saveFilePath">目标保存文件的绝对路径 (例如: @"D:\Oscilloscope\RippleTest.png")</param>
|
||||
/// <param name="ct">异步取消令牌</param>
|
||||
/// <returns>布尔值:true 表示成功获取并保存截图,false 表示获取或保存失败</returns>
|
||||
public virtual async Task<bool> 获取屏幕图像并保存(string saveFilePath, CancellationToken ct = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
string FileDirectory = Path.GetDirectoryName(saveFilePath) ?? ""; // 获取目录
|
||||
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(saveFilePath); // 获取纯文件名
|
||||
string extension = Path.GetExtension(saveFilePath); // 获取后缀名 (如 .png)
|
||||
// 生成时间戳,格式为 年月日_时分秒 (例如 20260817_123045)
|
||||
string FileDirectory = Path.GetDirectoryName(saveFilePath) ?? "";
|
||||
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(saveFilePath);
|
||||
string extension = Path.GetExtension(saveFilePath);
|
||||
// 自动追加当前时间戳避免同名文件覆盖
|
||||
string timeStamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
|
||||
// 组合成新的路径
|
||||
saveFilePath = Path.Combine(FileDirectory, $"{fileNameWithoutExt}_{timeStamp}{extension}");
|
||||
// 1. 调用我们在基类 Tcp 中全新实现的 ReadRawAsync
|
||||
// 它会在内部下发 ":PRINt? PNG\n",自动接收完整的网络字节流
|
||||
|
||||
// 下发截图指令,接收纯字节流
|
||||
byte[] pureImageBytes = await ReadAllBytesAsync($":PRINt? PNG{ScpiDelimiter}", ct);
|
||||
|
||||
// 2. 校验返回数据
|
||||
if (pureImageBytes == null || pureImageBytes.Length < 8)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("错误:接收到的图片数据为空或长度不足。");
|
||||
return false;
|
||||
}
|
||||
if (pureImageBytes == null || pureImageBytes.Length < 8) return false;
|
||||
|
||||
// 3. 核心校验:验证是否为标准的 PNG 文件格式 (PNG 头通常为 89 50 4E 47)
|
||||
// 验证 PNG 格式头,以确认确实是一张合法图像
|
||||
if (pureImageBytes[0] != 0x89 || pureImageBytes[1] != 'P' || pureImageBytes[2] != 'N' || pureImageBytes[3] != 'G')
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("错误:接收到的二进制数据不符合标准 PNG 格式头!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 如果传入的目标文件夹路径不存在,自动帮其创建
|
||||
string directory = Path.GetDirectoryName(saveFilePath);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
// 5. 使用文件流直接将 PNG 字节数据落地写入本地硬盘
|
||||
// 将接收到的二进制数组写入文件
|
||||
using (FileStream fs = new FileStream(saveFilePath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
await fs.WriteAsync(pureImageBytes, 0, pureImageBytes.Length, ct);
|
||||
await fs.FlushAsync(ct); // 强制刷新,确保数据完整落地
|
||||
await fs.FlushAsync(ct);
|
||||
}
|
||||
|
||||
System.Diagnostics.Debug.WriteLine($"成功:截图已保存至路径: {saveFilePath}");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"崩溃:保存截图时发生未知异常: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user