命令树优化,测试编辑区域优化
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -11,20 +11,29 @@ using System.Threading.Tasks;
|
|||||||
namespace DeviceCommand.Devices
|
namespace DeviceCommand.Devices
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 负载 一对三
|
/// ANEVH80 电子负载(一对三控制),基于 TCP 通信,使用 SCPI 指令集。
|
||||||
|
/// 用于被测产品的放电/带载测试,可模拟真实负载工况。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public class ANEVH80 : Tcp
|
public class ANEVH80 : Tcp
|
||||||
{
|
{
|
||||||
// Chroma SCPI 默认使用 \n 作为结束符
|
// SCPI 指令默认使用 \n 作为结束符
|
||||||
private const string ScpiDelimiter = "\n";
|
private const string ScpiDelimiter = "\n";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数,初始化 TCP 连接配置。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">TCP 连接配置(IP、端口等)</param>
|
||||||
public ANEVH80(TcpConfig config) : base(config)
|
public ANEVH80(TcpConfig config) : base(config)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 占位符,可能的操作先占位
|
/// 占位符方法,预留后续负载控制操作(如设置负载模式、设置电流等)。
|
||||||
|
/// 当前实现为查询频率测量值。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
/// <returns>查询到的频率值,解析失败返回 0.0</returns>
|
||||||
public virtual async Task<double> 占位符(CancellationToken ct = default)
|
public virtual async Task<double> 占位符(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string resp = await WriteReadAsync($"MEAS:FREQ?{ScpiDelimiter}", ScpiDelimiter, ct);
|
string resp = await WriteReadAsync($"MEAS:FREQ?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using DeviceCommand.Base;
|
|||||||
using Model.Models;
|
using Model.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
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. 基础系统与公共指令
|
#region 1. 基础系统与公共指令
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清除错误队列 (*CLS)[cite: 1]
|
/// 清除错误队列 (*CLS)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task 清除错误队列Async(CancellationToken ct = default)
|
public virtual async Task 清除错误队列Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -32,7 +50,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重设仪器为初始状态 (*RST)[cite: 1]
|
/// 重设仪器为初始状态 (*RST)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task 复位Async(CancellationToken ct = default)
|
public virtual async Task 复位Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -40,7 +58,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询仪器识别码 (*IDN?)[cite: 1]
|
/// 查询仪器识别码 (*IDN?)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task<string> 查询设备信息Async(CancellationToken ct = default)
|
public virtual async Task<string> 查询设备信息Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -49,10 +67,10 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 2. 基础输出与耦合控制 (OUTPut 子系统)[cite: 1]
|
#region 2. 基础输出与耦合控制 (OUTPut 子系统)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置输出开关状态 (OUTP ON / OFF)[cite: 1]
|
/// 设置输出开关状态 (OUTP ON / OFF)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="isOn">true: 开启输出, false: 关闭输出</param>
|
/// <param name="isOn">true: 开启输出, false: 关闭输出</param>
|
||||||
public virtual async Task 设置输出开关Async(bool isOn, CancellationToken ct = default)
|
public virtual async Task 设置输出开关Async(bool isOn, CancellationToken ct = default)
|
||||||
@@ -62,7 +80,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置输出耦合模式 (OUTP:COUP AC | DC | ACDC)[cite: 1]
|
/// 设置输出耦合模式 (OUTP:COUP AC | DC | ACDC)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task 设置耦合模式Async(string couplingMode, CancellationToken ct = default)
|
public virtual async Task 设置耦合模式Async(string couplingMode, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -71,7 +89,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置输出继电器状态 (OUTP:REL ON | OFF)[cite: 1]
|
/// 设置输出继电器状态 (OUTP:REL ON | OFF)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task 设置输出继电器Async(bool isOn, CancellationToken ct = default)
|
public virtual async Task 设置输出继电器Async(bool isOn, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -81,10 +99,10 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 3. 电源核心参数设置 (SOURCE 子系统)[cite: 1]
|
#region 3. 电源核心参数设置 (SOURCE 子系统)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置交流电压 (VOLT:AC)[cite: 1]
|
/// 设置交流电压 (VOLT:AC)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="voltage">电压值 (0 ~ 300V 或高压选配范围)</param>
|
/// <param name="voltage">电压值 (0 ~ 300V 或高压选配范围)</param>
|
||||||
public virtual async Task 设置交流电压Async(double voltage, CancellationToken ct = default)
|
public virtual async Task 设置交流电压Async(double voltage, CancellationToken ct = default)
|
||||||
@@ -94,7 +112,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置直流电压 (VOLT:DC)[cite: 1]
|
/// 设置直流电压 (VOLT:DC)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task 设置直流电压Async(double voltage, CancellationToken ct = default)
|
public virtual async Task 设置直流电压Async(double voltage, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -103,7 +121,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置输出频率 (FREQ)[cite: 1]
|
/// 设置输出频率 (FREQ)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="frequency">频率值 (Hz)</param>
|
/// <param name="frequency">频率值 (Hz)</param>
|
||||||
public virtual async Task 设置频率Async(double frequency, CancellationToken ct = default)
|
public virtual async Task 设置频率Async(double frequency, CancellationToken ct = default)
|
||||||
@@ -113,7 +131,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置波形选择 (FUNC:SHAP:A SINE / SQUA / CSIN 等)[cite: 1]
|
/// 设置波形选择 (FUNC:SHAP:A SINE / SQUA / CSIN 等)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task 设置波形Async(string shape, CancellationToken ct = default)
|
public virtual async Task 设置波形Async(string shape, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -122,10 +140,10 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 4. 相位与多相模式控制 (INST & PHASE 子系统)[cite: 1]
|
#region 4. 相位与多相模式控制 (INST & PHASE 子系统)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置单/三相工作模式 (INST:PHAS THREE / SINGLE)[cite: 1]
|
/// 设置单/三相工作模式 (INST:PHAS THREE / SINGLE)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="isThreePhase">true: 三相模式, false: 单相模式</param>
|
/// <param name="isThreePhase">true: 三相模式, false: 单相模式</param>
|
||||||
public virtual async Task 设置单三相模式Async(bool isThreePhase, CancellationToken ct = default)
|
public virtual async Task 设置单三相模式Async(bool isThreePhase, CancellationToken ct = default)
|
||||||
@@ -135,7 +153,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置三相模式下的相互关系 (PHASE:THREE INDEPEND / SAMEFREQ / BALANCE)[cite: 1]
|
/// 设置三相模式下的相互关系 (PHASE:THREE INDEPEND / SAMEFREQ / BALANCE)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task 设置三相关系Async(string relation, CancellationToken ct = default)
|
public virtual async Task 设置三相关系Async(string relation, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -144,7 +162,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置输出开启相位角 (PHASE:ON)[cite: 1]
|
/// 设置输出开启相位角 (PHASE:ON)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task 设置开机角度Async(double degree, CancellationToken ct = default)
|
public virtual async Task 设置开机角度Async(double degree, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -153,7 +171,7 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置输出关闭相位角 (PHASE:OFF)[cite: 1]
|
/// 设置输出关闭相位角 (PHASE:OFF)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual async Task 设置关机角度Async(double degree, CancellationToken ct = default)
|
public virtual async Task 设置关机角度Async(double degree, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
@@ -163,42 +181,50 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 5. 参数测量查询 (MEASure 子系统)[cite: 1]
|
#region 5. 参数测量查询 (MEASure 子系统)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询交流电压均方根值 (MEAS:VOLT:AC?)[cite: 1]
|
/// 查询交流电压均方根值 (MEAS:VOLT:AC?)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>交流电压均方根值 (单位: V,保留两位小数)</returns>
|
||||||
public virtual async Task<double> 读取交流电压Async(CancellationToken ct = default)
|
public virtual async Task<double> 读取交流电压Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string resp = await WriteReadAsync($"MEAS:VOLT:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
|
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>
|
/// <summary>
|
||||||
/// 查询交流电流均方根值 (MEAS:CURR:AC?)[cite: 1]
|
/// 查询交流电流均方根值 (MEAS:CURR:AC?)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>交流电流均方根值 (单位: A,保留两位小数)</returns>
|
||||||
public virtual async Task<double> 读取交流电流Async(CancellationToken ct = default)
|
public virtual async Task<double> 读取交流电流Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string resp = await WriteReadAsync($"MEAS:CURR:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
|
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>
|
/// <summary>
|
||||||
/// 查询输出频率 (MEAS:FREQ?)[cite: 1]
|
/// 查询输出频率 (MEAS:FREQ?)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>输出频率值 (单位: Hz,保留两位小数)</returns>
|
||||||
public virtual async Task<double> 读取频率Async(CancellationToken ct = default)
|
public virtual async Task<double> 读取频率Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string resp = await WriteReadAsync($"MEAS:FREQ?{ScpiDelimiter}", ScpiDelimiter, ct);
|
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>
|
/// <summary>
|
||||||
/// 查询真实输出功率 (MEAS:POW:AC?)[cite: 1]
|
/// 查询真实输出功率 (MEAS:POW:AC?)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>真实输出功率值 (单位: W,保留两位小数)</returns>
|
||||||
public virtual async Task<double> 读取真实功率Async(CancellationToken ct = default)
|
public virtual async Task<double> 读取真实功率Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string resp = await WriteReadAsync($"MEAS:POW:AC?{ScpiDelimiter}", ScpiDelimiter, ct);
|
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
|
#endregion
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using DeviceCommand.Base;
|
|||||||
using Model.Models;
|
using Model.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@@ -45,33 +46,74 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 信号发生器 (DG1000Z 系列) 一拖三,支持波形输出与频率计测量
|
||||||
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public class DG1000Z : Tcp
|
public class DG1000Z : Tcp
|
||||||
{
|
{
|
||||||
// 使用换行符 \n (ASCII 0x0A) 作为 SCPI 结束符
|
// 使用换行符 \n (ASCII 0x0A) 作为 SCPI 结束符
|
||||||
private const string ScpiDelimiter = "\n";
|
private const string ScpiDelimiter = "\n";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数:传入 <see cref="TcpConfig"/> 一次性初始化信号发生器通信参数
|
||||||
|
/// </summary>
|
||||||
public DG1000Z(TcpConfig config) : base(config)
|
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 公共命令
|
#region 1. IEEE 488.2 公共命令
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清除标准事件状态寄存器和错误队列 (*CLS)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 清除状态寄存器(CancellationToken ct = default)
|
public virtual async Task 清除状态寄存器(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($"*CLS{ScpiDelimiter}", ct);
|
await SendAsync($"*CLS{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询设备识别信息 (*IDN? 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>设备标识字符串 (制造商, 型号, 序列号, 固件版本)</returns>
|
||||||
public virtual async Task<string> 查询设备标识(CancellationToken ct = default)
|
public virtual async Task<string> 查询设备标识(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重设仪器为初始状态 (*RST)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 重置设备(CancellationToken ct = default)
|
public virtual async Task 重置设备(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($"*RST{ScpiDelimiter}", ct);
|
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)
|
public virtual async Task<string> 查询系统SCPI版本(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync($":SYSTem:VERSion?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return await WriteReadAsync($":SYSTem:VERSion?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
@@ -82,16 +124,23 @@ namespace DeviceCommand.Devices
|
|||||||
#region 2. 通道输出控制 (CH1 / CH2)
|
#region 2. 通道输出控制 (CH1 / CH2)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 打开或关闭指定通道的输出
|
/// 打开或关闭指定通道的输出 (OUTPut 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="通道号">通道 1 或 2,默认 1</param>
|
/// <param name="通道号">通道 1 或 2,默认 1</param>
|
||||||
/// <param name="开启">true为开启,false为关闭</param>
|
/// <param name="开启">true为开启,false为关闭</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置通道输出状态(int 通道号 = 1, bool 开启 = true, CancellationToken ct = default)
|
public virtual async Task 设置通道输出状态(int 通道号 = 1, bool 开启 = true, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string 参数 = 开启 ? "ON" : "OFF";
|
string 参数 = 开启 ? "ON" : "OFF";
|
||||||
await SendAsync($":OUTPut{通道号}:STATe {参数}{ScpiDelimiter}", ct);
|
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)
|
public virtual async Task<string> 查询通道输出状态(int 通道号 = 1, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync($":OUTPut{通道号}:STATe?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return await WriteReadAsync($":OUTPut{通道号}:STATe?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
@@ -104,51 +153,84 @@ namespace DeviceCommand.Devices
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置指定通道的波形类型 (如正弦波、方波等)
|
/// 设置指定通道的波形类型 (如正弦波、方波等)
|
||||||
/// </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)
|
public virtual async Task 设置波形类型(int 通道号 = 1, SignalWaveform 波形 = SignalWaveform.SINusoid, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($":SOURce{通道号}:FUNCtion:SHAPe {波形}{ScpiDelimiter}", ct);
|
await SendAsync($":SOURce{通道号}:FUNCtion:SHAPe {波形}{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置指定通道的输出频率 (单位: Hz)
|
/// 设置指定通道的输出频率 (SOURce:FREQuency 指令)
|
||||||
/// </summary>
|
/// </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)
|
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);
|
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:FREQuency {1:F2}{2}", 通道号, 频率Hz, ScpiDelimiter);
|
||||||
await SendAsync(cmd, ct);
|
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>
|
/// <summary>
|
||||||
/// 设置指定通道的输出幅度 (单位: Vpp,峰峰值)
|
/// 设置指定通道的输出幅度 (SOURce:VOLTage:AMPLitude 指令)
|
||||||
/// </summary>
|
/// </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)
|
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);
|
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:VOLTage:AMPLitude {1:F2}{2}", 通道号, 幅度Vpp, ScpiDelimiter);
|
||||||
await SendAsync(cmd, ct);
|
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>
|
/// <summary>
|
||||||
/// 设置指定通道的直流偏移电压 (单位: Vdc)
|
/// 设置指定通道的直流偏移电压 (SOURce:VOLTage:OFFSet 指令)
|
||||||
/// </summary>
|
/// </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)
|
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);
|
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:VOLTage:OFFSet {1:F2}{2}", 通道号, 偏移Vdc, ScpiDelimiter);
|
||||||
await SendAsync(cmd, ct);
|
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
|
#endregion
|
||||||
@@ -156,8 +238,11 @@ namespace DeviceCommand.Devices
|
|||||||
#region 4. 方波 / 脉冲波占空比设置 (重点用于CP信号模拟)
|
#region 4. 方波 / 脉冲波占空比设置 (重点用于CP信号模拟)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置方波信号的占空比 (0.01% ~ 99.99%)[cite: 1]
|
/// 设置方波信号的占空比 (0.01% ~ 99.99%)
|
||||||
/// </summary>
|
/// </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)
|
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);
|
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:FUNCtion:SQUare:DCYCle {1:F2}{2}", 通道号, 占空比, ScpiDelimiter);
|
||||||
@@ -165,9 +250,12 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置脉冲波信号的占空比 (0.01% ~ 99.99%)[cite: 1]
|
/// 设置脉冲波信号的占空比 (0.01% ~ 99.99%)。
|
||||||
/// 注意:使用此命令前必须先设置为 PULSe 波形类型
|
/// 注意:使用此命令前必须先设置为 PULSe 波形类型
|
||||||
/// </summary>
|
/// </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)
|
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);
|
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce{0}:FUNCtion:PULSe:DCYCle {1:F2}{2}", 通道号, 占空比, ScpiDelimiter);
|
||||||
@@ -179,47 +267,68 @@ namespace DeviceCommand.Devices
|
|||||||
#region 5. 频率计测量功能 (高频数据轮询核心)
|
#region 5. 频率计测量功能 (高频数据轮询核心)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 打开或关闭内置频率计功能
|
/// 打开或关闭内置频率计功能 (COUNter:STATe 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="开启">true: 开启频率计, false: 关闭频率计</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置频率计开关(bool 开启 = true, CancellationToken ct = default)
|
public virtual async Task 设置频率计开关(bool 开启 = true, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string 参数 = 开启 ? "ON" : "OFF";
|
string 参数 = 开启 ? "ON" : "OFF";
|
||||||
await SendAsync($":COUNter:STATe {参数}{ScpiDelimiter}", ct);
|
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)
|
public virtual async Task<string> 查询频率计开关状态(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync($":COUNter:STATe?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return await WriteReadAsync($":COUNter:STATe?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置频率计输入信号的耦合方式
|
/// 设置频率计输入信号的耦合方式 (COUNter:COUPling 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="耦合">耦合方式枚举 (AC 交流 / DC 直流),默认 AC</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置频率计耦合方式(CounterCoupling 耦合 = CounterCoupling.AC, CancellationToken ct = default)
|
public virtual async Task 设置频率计耦合方式(CounterCoupling 耦合 = CounterCoupling.AC, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($":COUNter:COUPling {耦合}{ScpiDelimiter}", ct);
|
await SendAsync($":COUNter:COUPling {耦合}{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置频率计的触发电平 (单位: V)
|
/// 设置频率计的触发电平 (COUNter:LEVel 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="电平V">触发电平值 (单位: V),默认 0.1</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置频率计触发电平(double 电平V = 0.1, CancellationToken ct = default)
|
public virtual async Task 设置频率计触发电平(double 电平V = 0.1, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string cmd = string.Format(CultureInfo.InvariantCulture, ":COUNter:LEVel {0:F2}{1}", 电平V, ScpiDelimiter);
|
string cmd = string.Format(CultureInfo.InvariantCulture, ":COUNter:LEVel {0:F2}{1}", 电平V, ScpiDelimiter);
|
||||||
await SendAsync(cmd, ct);
|
await SendAsync(cmd, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询频率计测量值 (COUNter:MEASure? 指令)。
|
||||||
|
/// 响应格式为 "频率, 周期, 占空比, 正脉宽, 负脉宽",此方法提取第一项频率值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>频率计测得的频率值 (单位: Hz,保留两位小数)</returns>
|
||||||
[Monitorable("信号发生器频率计测量值")]
|
[Monitorable("信号发生器频率计测量值")]
|
||||||
public virtual async Task<string> 查询频率计测量值(CancellationToken ct = default)
|
public virtual async Task<double> 查询频率计测量值(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 返回格式: 频率, 周期, 占空比, 正脉宽, 负脉宽
|
string resp = await WriteReadAsync($":COUNter:MEASure?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
return await WriteReadAsync($":COUNter:MEASure?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return ExtractDouble(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 6. 系统维护与远程控制扩展命令
|
#region 6. 系统维护与远程控制扩展命令
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 切换远程控制模式。信号发生器通过 LAN/USB 通信即自动进入远程模式
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 切换远程控制模式(CancellationToken ct = default)
|
public virtual async Task 切换远程控制模式(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 信号发生器通常通过 LAN/USB 和 VISA 通信即自动进入远程控制,
|
// 信号发生器通常通过 LAN/USB 和 VISA 通信即自动进入远程控制,
|
||||||
@@ -227,12 +336,21 @@ namespace DeviceCommand.Devices
|
|||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 切换本地控制模式。通常通过前面板按键退出远程
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 切换本地控制模式(CancellationToken ct = default)
|
public virtual async Task 切换本地控制模式(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 通常通过前面板按键退出远程。不过可提供 SCPI 关闭屏幕保护等。
|
// 通常通过前面板按键退出远程。不过可提供 SCPI 关闭屏幕保护等。
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询系统错误信息 (SYSTem:ERRor? 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>错误代码和描述信息</returns>
|
||||||
public virtual async Task<string> 查询错误信息(CancellationToken ct = default)
|
public virtual async Task<string> 查询错误信息(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync($":SYSTem:ERRor?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return await WriteReadAsync($":SYSTem:ERRor?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
@@ -240,4 +358,4 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,22 +12,39 @@ using System.Threading.Tasks;
|
|||||||
namespace DeviceCommand.Devices
|
namespace DeviceCommand.Devices
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// IO板卡 一对一由于板卡映射不完全一样采用IOGroup
|
/// IO 继电器板卡(一对一控制),基于 Modbus TCP 协议通过线圈(Coil)读写控制继电器输出。
|
||||||
|
/// 由于多块板卡的点位映射不完全一致,实际业务中使用 <see cref="IOBoardGroup"/> 统一调度三块板卡。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
//[ACPCommand]
|
//[ACPCommand]
|
||||||
public class IOBoard : ModbusTcp
|
public class IOBoard : ModbusTcp
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数,初始化 Modbus TCP 连接配置。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">TCP 连接配置(IP、端口等)</param>
|
||||||
public IOBoard(TcpConfig config) : base(config)
|
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)
|
public async Task 写输出开关(byte 站号, ushort 开始地址, bool data)
|
||||||
{
|
{
|
||||||
await Modbus.WriteSingleCoilAsync(站号, 开始地址, 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)
|
public async Task 批量写输出开关(byte 站号, ushort 开始地址, bool[] datas)
|
||||||
{
|
{
|
||||||
var 批量写入 = await Modbus.ReadCoilsAsync(1, 0, 16);
|
var 批量写入 = await Modbus.ReadCoilsAsync(1, 0, 16);
|
||||||
@@ -40,10 +57,24 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
await Modbus.WriteMultipleCoilsAsync(站号, 0, 批量写入);
|
await Modbus.WriteMultipleCoilsAsync(站号, 0, 批量写入);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 读取单个输出开关(线圈)状态。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="站号">Modbus 从站站号</param>
|
||||||
|
/// <param name="开始地址">线圈地址(0 起始)</param>
|
||||||
public async Task 读输出开关(byte 站号, ushort 开始地址)
|
public async Task 读输出开关(byte 站号, ushort 开始地址)
|
||||||
{
|
{
|
||||||
await Modbus.ReadCoilsAsync(站号, 开始地址, 1);
|
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 数量)
|
public async Task<bool[]> 批量读输出开关(byte 站号, ushort 开始地址,ushort 数量)
|
||||||
{
|
{
|
||||||
return await Modbus.ReadCoilsAsync(站号, 开始地址, 数量);
|
return await Modbus.ReadCoilsAsync(站号, 开始地址, 数量);
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IO 板卡组(三工位统一调度),封装 3 块 IO 继电器板卡的访问。
|
||||||
|
/// 根据 ACP 硬件接线图的点位映射字典,按台架序号路由到对应板卡的线圈地址,
|
||||||
|
/// 并内置充电/放电互锁保护,防止同时吸合造成短路。
|
||||||
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public class IOBoardGroup
|
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 个板块
|
// 修改构造函数以支持 3 个板块
|
||||||
public IOBoardGroup(IOBoard board1, IOBoard board2, IOBoard board3)
|
public IOBoardGroup(IOBoard board1, IOBoard board2, IOBoard board3)
|
||||||
{
|
{
|
||||||
@@ -168,49 +180,25 @@ namespace DeviceCommand.Devices
|
|||||||
await 目标板卡.写输出开关(_slaveAddress, io信息.Address, 开关状态);
|
await 目标板卡.写输出开关(_slaveAddress, io信息.Address, 开关状态);
|
||||||
}
|
}
|
||||||
|
|
||||||
// =================================================================================
|
|
||||||
// 以下为新增的原生命令透传接口,使用台架序号自动路由至对应 IOBoard
|
|
||||||
// =================================================================================
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 针对指定台架直接写入单个输出开关
|
/// 向指定板卡批量写入输出开关状态,直接透传到对应板卡的批量写线圈操作。
|
||||||
/// </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 GetBoardInstance(板卡序号).批量写输出开关(站号, 开始地址, 数据);
|
||||||
await targetBoard.写输出开关(站号, 开始地址, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 针对指定台架直接批量写入输出开关
|
/// 内部路由辅助方法:根据板卡序号安全获取对应的 IO 板卡实例。
|
||||||
/// </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>
|
|
||||||
/// 内部路由辅助方法:根据板卡/台架索引安全获取当前连接的实例对象
|
|
||||||
/// </summary>
|
/// </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)
|
private IOBoard GetBoardInstance(int moduleIndex)
|
||||||
{
|
{
|
||||||
IOBoard board = moduleIndex switch
|
IOBoard board = moduleIndex switch
|
||||||
|
|||||||
@@ -133,6 +133,10 @@ namespace DeviceCommand.Devices
|
|||||||
throw new Exception("IT6720 切换控制模式时通讯校验失败。");
|
throw new Exception("IT6720 切换控制模式时通讯校验失败。");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 切换为本地(面板)控制模式,与远程控制互斥
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 切换本地控制模式(CancellationToken ct = default)
|
public virtual async Task 切换本地控制模式(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await 切换远程控制模式(false, ct);
|
await 切换远程控制模式(false, ct);
|
||||||
@@ -150,6 +154,11 @@ namespace DeviceCommand.Devices
|
|||||||
throw new Exception("IT6720 设置输出时通讯校验失败。");
|
throw new Exception("IT6720 设置输出时通讯校验失败。");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询电源输出开关状态(由实时测量值的状态字节判断)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>输出开关状态字符串 (ON / OFF)</returns>
|
||||||
public virtual async Task<string> 查询输出开关状态(CancellationToken ct = default)
|
public virtual async Task<string> 查询输出开关状态(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var (_, _, status) = await 查询实时测量值(ct);
|
var (_, _, status) = await 查询实时测量值(ct);
|
||||||
@@ -230,18 +239,28 @@ namespace DeviceCommand.Devices
|
|||||||
return (actualCurrent, actualVoltage, statusByte);
|
return (actualCurrent, actualVoltage, statusByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询电源的实时实际输出电压 (MEASure 相关寄存器)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>实时电压值 (单位: V,保留两位小数)</returns>
|
||||||
[Monitorable("IT6720 实际电压")]
|
[Monitorable("IT6720 实际电压")]
|
||||||
public virtual async Task<string> 查询实际电压(CancellationToken ct = default)
|
public virtual async Task<double> 查询实际电压(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var (_, voltage, _) = await 查询实时测量值(ct);
|
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 实际电流")]
|
[Monitorable("IT6720 实际电流")]
|
||||||
public virtual async Task<string> 查询实际电流(CancellationToken ct = default)
|
public virtual async Task<double> 查询实际电流(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var (current, _, _) = await 查询实时测量值(ct);
|
var (current, _, _) = await 查询实时测量值(ct);
|
||||||
return current.ToString("F3", CultureInfo.InvariantCulture);
|
return Math.Round(current, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -9,10 +9,15 @@ using System.Threading.Tasks;
|
|||||||
namespace DeviceCommand.Devices
|
namespace DeviceCommand.Devices
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 水冷机 一拖三
|
/// MCc30W 水冷机(一拖三控制),基于 Modbus TCP 协议通信。
|
||||||
|
/// 用于被测产品的冷却温控,预留后续读写温度设定、启停控制等寄存器操作。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MCc30W:ModbusTcp
|
public class MCc30W:ModbusTcp
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数,初始化 Modbus TCP 连接配置。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">TCP 连接配置(IP、端口等)</param>
|
||||||
public MCc30W(TcpConfig config) : base(config)
|
public MCc30W(TcpConfig config) : base(config)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
+261
-33
@@ -2,13 +2,16 @@
|
|||||||
using Common.Attributes;
|
using Common.Attributes;
|
||||||
using DeviceCommand.Base;
|
using DeviceCommand.Base;
|
||||||
using Model.Models;
|
using Model.Models;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace DeviceCommand.Device
|
namespace DeviceCommand.Device
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 功率分析仪(型号:HIOKI PW8001) 一拖三
|
/// 功率分析仪(型号:HIOKI PW8001) 一拖三,支持多通道电压/电流/功率及谐波测量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public class PW8001 : Tcp
|
public class PW8001 : Tcp
|
||||||
@@ -25,23 +28,58 @@ namespace DeviceCommand.Device
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? SessionKey { get; set; }
|
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 基础标准命令
|
#region 1. IEEE 488.2 基础标准命令
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询仪器识别信息 (*IDN? 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>设备标识字符串 (制造商, 型号, 序列号, 固件版本)</returns>
|
||||||
public virtual async Task<string> 查询机器信息(CancellationToken ct = default)
|
public virtual async Task<string> 查询机器信息(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync("*IDN?\r\n", "\n", ct);
|
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)
|
public virtual async Task<string> 查询硬件选项(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync("*OPT?\r\n", "\n", ct);
|
return await WriteReadAsync("*OPT?\r\n", "\n", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 复位仪器到默认状态 (*RST 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 复位仪器(CancellationToken ct = default)
|
public virtual async Task 复位仪器(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync("*RST\r\n", ct);
|
await SendAsync("*RST\r\n", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清除状态寄存器和错误队列 (*CLS 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 清除状态(CancellationToken ct = default)
|
public virtual async Task 清除状态(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync("*CLS\r\n", ct);
|
await SendAsync("*CLS\r\n", ct);
|
||||||
@@ -51,66 +89,129 @@ namespace DeviceCommand.Device
|
|||||||
|
|
||||||
#region 2. 仪器系统与测试模式设置设置 (System & Mode)
|
#region 2. 仪器系统与测试模式设置设置 (System & Mode)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置测试模式为 WIDE 宽带测量模式 (:MODE WIDE 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置测试模式_WIDE(CancellationToken ct = default)
|
public virtual async Task 设置测试模式_WIDE(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync(":MODE WIDE\r\n", ct);
|
await SendAsync(":MODE WIDE\r\n", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置测试模式为 IEC 标准测量模式 (:MODE IEC 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置测试模式_IEC(CancellationToken ct = default)
|
public virtual async Task 设置测试模式_IEC(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync(":MODE IEC\r\n", ct);
|
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)
|
public virtual async Task<string> 查询测试模式(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync(":MODE?\r\n", "\n", ct);
|
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)
|
public virtual async Task 设置同步源(string 源, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($":SYNC:SOURce {源}\r\n", ct);
|
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)
|
public virtual async Task<string> 查询同步源(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync(":SYNC:SOURce?\r\n", "\n", ct);
|
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)
|
public virtual async Task 设置零点调整(string 状态, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($":ZERO {状态}\r\n", ct);
|
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)
|
public virtual async Task<string> 查询零点调整(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync(":ZERO?\r\n", "\n", ct);
|
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)
|
public virtual async Task 设置零点抑制(string 状态, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($":ZSP {状态}\r\n", ct);
|
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)
|
public virtual async Task<string> 查询零点抑制(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync(":ZSP?\r\n", "\n", ct);
|
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)
|
public virtual async Task 设置响应消息头(string 状态, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($":HEADer {状态}\r\n", ct);
|
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)
|
public virtual async Task<string> 查询响应消息头(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync(":HEADer?\r\n", "\n", ct);
|
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)
|
public virtual async Task 设置按键锁定(string 状态, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($":KLOCk {状态}\r\n", ct);
|
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)
|
public virtual async Task<string> 查询按键锁定(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync(":KLOCk?\r\n", "\n", ct);
|
return await WriteReadAsync(":KLOCk?\r\n", "\n", ct);
|
||||||
@@ -120,21 +221,43 @@ namespace DeviceCommand.Device
|
|||||||
|
|
||||||
#region 3. 积分控制 (Integration)
|
#region 3. 积分控制 (Integration)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置积分控制模式 (:INTEG:CONTROL 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="模式">积分控制模式</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置积分控制(string 模式, CancellationToken ct = default)
|
public virtual async Task 设置积分控制(string 模式, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($":INTEG:CONTROL {模式}\r\n", ct);
|
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)
|
public virtual async Task<string> 查询积分控制(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync(":INTEG:CONTROL?\r\n", "\n", ct);
|
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)
|
public virtual async Task 设置积分模式(string 通道号, string 模式, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($":INTEG:MODE{通道号} {模式}\r\n", ct);
|
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)
|
public virtual async Task<string> 查询积分模式(string 通道号, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return await WriteReadAsync($":INTEG:MODE{通道号}?\r\n", "\n", ct);
|
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) ----------------
|
// ---------------- 基础测量(含变比 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
|
#endregion
|
||||||
@@ -232,8 +458,10 @@ namespace DeviceCommand.Device
|
|||||||
#region 5. 自定义透传指令
|
#region 5. 自定义透传指令
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送自定义命令
|
/// 发送自定义命令(透传任意 SCPI 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="命令">自定义命令字符串</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 发送自定义命令(string 命令, CancellationToken ct = default)
|
public virtual async Task 发送自定义命令(string 命令, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($"{命令}\r\n", ct);
|
await SendAsync($"{命令}\r\n", ct);
|
||||||
@@ -241,4 +469,4 @@ namespace DeviceCommand.Device
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,30 +8,45 @@ using System.Threading.Tasks;
|
|||||||
namespace DeviceCommand.Devices
|
namespace DeviceCommand.Devices
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 环境箱(型号:RLT1000) 一拖三
|
/// 环境箱(型号:RLT1000) 一拖三,支持温度/湿度/水温/水流量的监测与定值控制 (Modbus TCP 协议)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public class RLT1000 : ModbusTcp
|
public class RLT1000 : ModbusTcp
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数:传入 <see cref="TcpConfig"/> 初始化环境箱 Modbus TCP 通信参数
|
||||||
|
/// </summary>
|
||||||
public RLT1000(TcpConfig config) : base(config)
|
public RLT1000(TcpConfig config) : base(config)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modbus 从站号
|
||||||
private const byte SlaveId = 1;
|
private const byte SlaveId = 1;
|
||||||
|
|
||||||
#region 读取
|
#region 读取
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 读取环境箱运行状态监控字 (保持寄存器 5)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>状态监控字 (ushort 原始值)</returns>
|
||||||
public async Task<ushort> 读取状态监控(CancellationToken ct = default)
|
public async Task<ushort> 读取状态监控(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 5, 1, ct);
|
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 5, 1, ct);
|
||||||
return re[0];
|
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
|
try
|
||||||
{
|
{
|
||||||
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 10, 2, ct);
|
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 10, 2, ct);
|
||||||
return ConvertToFloat(re);
|
return Math.Round(ConvertToFloat(re), 2);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
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);
|
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
|
try
|
||||||
{
|
{
|
||||||
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 22, 2, ct);
|
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 22, 2, ct);
|
||||||
return ConvertToFloat(re);
|
return Math.Round(ConvertToFloat(re), 2);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
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);
|
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);
|
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);
|
ushort[] re = await ReadHoldingRegistersAsync(SlaveId, 40, 2, ct);
|
||||||
return ConvertToFloat(re);
|
return Math.Round(ConvertToFloat(re), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 读写(控制命令)
|
#region 读写(控制命令)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 切换环境箱为本地控制模式 (寄存器 147 写 0)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 切换为本地模式(CancellationToken ct = default)
|
public async Task 切换为本地模式(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 147, 0, ct);
|
await WriteSingleRegisterAsync(SlaveId, 147, 0, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 切换环境箱为远程控制模式 (寄存器 147 写 1)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 切换为远程模式(CancellationToken ct = default)
|
public async Task 切换为远程模式(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 147, 1, ct);
|
await WriteSingleRegisterAsync(SlaveId, 147, 1, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 远程模式下关闭环境箱 (寄存器 148 写 0)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 远程模式关机(CancellationToken ct = default)
|
public async Task 远程模式关机(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 148, 0, ct);
|
await WriteSingleRegisterAsync(SlaveId, 148, 0, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 远程模式下开启环境箱 (寄存器 148 写 1)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 远程模式开机(CancellationToken ct = default)
|
public async Task 远程模式开机(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 148, 1, ct);
|
await WriteSingleRegisterAsync(SlaveId, 148, 1, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 远程模式复位结束 (寄存器 149 写 0)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 远程模式复位结束(CancellationToken ct = default)
|
public async Task 远程模式复位结束(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 149, 0, ct);
|
await WriteSingleRegisterAsync(SlaveId, 149, 0, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 远程模式复位 (寄存器 149 写 1)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 远程模式复位(CancellationToken ct = default)
|
public async Task 远程模式复位(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 149, 1, ct);
|
await WriteSingleRegisterAsync(SlaveId, 149, 1, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 切换为程序运行模式 (寄存器 153 写 0)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 切换为程序模式(CancellationToken ct = default)
|
public async Task 切换为程序模式(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 153, 0, ct);
|
await WriteSingleRegisterAsync(SlaveId, 153, 0, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 切换为定值运行模式 (寄存器 153 写 1)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 切换为定值模式(CancellationToken ct = default)
|
public async Task 切换为定值模式(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 153, 1, ct);
|
await WriteSingleRegisterAsync(SlaveId, 153, 1, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 定值模式下设置目标温度 (寄存器 154-155)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="温度">目标温度值 (单位: ℃)</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 定值温度设定(float 温度, CancellationToken ct = default)
|
public async Task 定值温度设定(float 温度, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var tmp = ConvertFromFloat(温度);
|
var tmp = ConvertFromFloat(温度);
|
||||||
await WriteMultipleRegistersAsync(SlaveId, 154, tmp, ct);
|
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)
|
public async Task 定值湿度设定(float 湿度, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var tmp = ConvertFromFloat(湿度);
|
var tmp = ConvertFromFloat(湿度);
|
||||||
await WriteMultipleRegistersAsync(SlaveId, 158, tmp, ct);
|
await WriteMultipleRegistersAsync(SlaveId, 158, tmp, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 定值模式下设置目标水温 (寄存器 162-163)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="水温">目标水温值 (单位: ℃)</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 定值水温设定(float 水温, CancellationToken ct = default)
|
public async Task 定值水温设定(float 水温, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var tmp = ConvertFromFloat(水温);
|
var tmp = ConvertFromFloat(水温);
|
||||||
await WriteMultipleRegistersAsync(SlaveId, 162, tmp, ct);
|
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)
|
public async Task 定值1号水流量设定(float 水流量, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var tmp = ConvertFromFloat(水流量);
|
var tmp = ConvertFromFloat(水流量);
|
||||||
await WriteMultipleRegistersAsync(SlaveId, 164, tmp, ct);
|
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)
|
public async Task 定值2号水流量设定(float 水流量, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var tmp = ConvertFromFloat(水流量);
|
var tmp = ConvertFromFloat(水流量);
|
||||||
await WriteMultipleRegistersAsync(SlaveId, 166, tmp, ct);
|
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)
|
public async Task 定值3号水流量设定(float 水流量, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var tmp = ConvertFromFloat(水流量);
|
var tmp = ConvertFromFloat(水流量);
|
||||||
await WriteMultipleRegistersAsync(SlaveId, 168, tmp, ct);
|
await WriteMultipleRegistersAsync(SlaveId, 168, tmp, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置水温模式不使用 (寄存器 1181 写 0)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 水温模式不使用(CancellationToken ct = default)
|
public async Task 水温模式不使用(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 1181, 0, ct);
|
await WriteSingleRegisterAsync(SlaveId, 1181, 0, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置水温模式使用 (寄存器 1181 写 1)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 水温模式使用(CancellationToken ct = default)
|
public async Task 水温模式使用(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 1181, 1, ct);
|
await WriteSingleRegisterAsync(SlaveId, 1181, 1, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置环境箱温度模式不使用 (寄存器 1182 写 0)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 环境箱温度模式不使用(CancellationToken ct = default)
|
public async Task 环境箱温度模式不使用(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 1182, 0, ct);
|
await WriteSingleRegisterAsync(SlaveId, 1182, 0, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置环境箱温度模式使用 (寄存器 1182 写 1)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 环境箱温度模式使用(CancellationToken ct = default)
|
public async Task 环境箱温度模式使用(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await WriteSingleRegisterAsync(SlaveId, 1182, 1, ct);
|
await WriteSingleRegisterAsync(SlaveId, 1182, 1, ct);
|
||||||
@@ -180,6 +298,11 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#region 数据转换助手方法
|
#region 数据转换助手方法
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将两个 16 位寄存器(大端序)转换为 IEEE754 单精度浮点数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="values">两个 ushort 寄存器值</param>
|
||||||
|
/// <returns>转换后的浮点数值</returns>
|
||||||
private float ConvertToFloat(ushort[] values)
|
private float ConvertToFloat(ushort[] values)
|
||||||
{
|
{
|
||||||
if (values == null || values.Length < 2) return 0f;
|
if (values == null || values.Length < 2) return 0f;
|
||||||
@@ -192,6 +315,11 @@ namespace DeviceCommand.Devices
|
|||||||
return BitConverter.ToSingle(bytes, 0);
|
return BitConverter.ToSingle(bytes, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将单精度浮点数转换为两个 16 位寄存器(大端序)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">待转换的浮点数值</param>
|
||||||
|
/// <returns>两个 ushort 寄存器值</returns>
|
||||||
private ushort[] ConvertFromFloat(float value)
|
private ushort[] ConvertFromFloat(float value)
|
||||||
{
|
{
|
||||||
byte[] bytes = BitConverter.GetBytes(value);
|
byte[] bytes = BitConverter.GetBytes(value);
|
||||||
@@ -203,4 +331,4 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+235
-37
@@ -1,65 +1,119 @@
|
|||||||
using Common.Attributes;
|
using Common.Attributes;
|
||||||
using DeviceCommand.Base;
|
using DeviceCommand.Base;
|
||||||
|
using Model.Models;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
// 根据您的项目实际路径保留枚举的引用
|
|
||||||
// using 通讯驱动Base.枚举;
|
|
||||||
|
|
||||||
namespace DeviceCommand.Devices
|
namespace DeviceCommand.Devices
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// S7200 负载工作模式枚举 (恒流/恒压/恒功率/恒阻等)
|
||||||
|
/// </summary>
|
||||||
public enum S7200负载模式_枚举
|
public enum S7200负载模式_枚举
|
||||||
{
|
{
|
||||||
|
/// <summary>恒流模式</summary>
|
||||||
CC,
|
CC,
|
||||||
|
/// <summary>恒压模式</summary>
|
||||||
CV,
|
CV,
|
||||||
|
/// <summary>恒功率模式</summary>
|
||||||
CP,
|
CP,
|
||||||
|
/// <summary>恒阻模式</summary>
|
||||||
CR,
|
CR,
|
||||||
|
/// <summary>恒压+恒流组合模式</summary>
|
||||||
CVCC,
|
CVCC,
|
||||||
|
/// <summary>恒阻+恒流组合模式</summary>
|
||||||
CRCC,
|
CRCC,
|
||||||
|
/// <summary>恒压+恒阻组合模式</summary>
|
||||||
CVCR,
|
CVCR,
|
||||||
|
/// <summary>自动模式</summary>
|
||||||
AUTO
|
AUTO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// S7200 直流源工作模式枚举 (电压源/电流源/电池模拟/光伏模拟等)
|
||||||
|
/// </summary>
|
||||||
public enum S7200直流源模式_枚举
|
public enum S7200直流源模式_枚举
|
||||||
{
|
{
|
||||||
|
/// <summary>电压源模式</summary>
|
||||||
VOLTage,
|
VOLTage,
|
||||||
|
/// <summary>电流源模式</summary>
|
||||||
CURRent,
|
CURRent,
|
||||||
|
/// <summary>电池测试模式</summary>
|
||||||
BATTest,
|
BATTest,
|
||||||
|
/// <summary>电池模拟模式</summary>
|
||||||
BATSim,
|
BATSim,
|
||||||
|
/// <summary>光伏模拟模式</summary>
|
||||||
SOLar,
|
SOLar,
|
||||||
|
/// <summary>EN50530 标准光伏曲线模式</summary>
|
||||||
EN50530,
|
EN50530,
|
||||||
|
/// <summary>列表输出模式</summary>
|
||||||
LIST,
|
LIST,
|
||||||
|
/// <summary>用户自定义波形模式</summary>
|
||||||
UDW,
|
UDW,
|
||||||
|
/// <summary>方波输出模式</summary>
|
||||||
SQUare,
|
SQUare,
|
||||||
|
/// <summary>三角波输出模式</summary>
|
||||||
TRIangle,
|
TRIangle,
|
||||||
|
/// <summary>正弦波输出模式</summary>
|
||||||
SINusoid,
|
SINusoid,
|
||||||
|
/// <summary>DIN40839 12V 启动曲线</summary>
|
||||||
DIN40839_12V,
|
DIN40839_12V,
|
||||||
|
/// <summary>DIN40839 24V 启动曲线</summary>
|
||||||
DIN40839_24V,
|
DIN40839_24V,
|
||||||
|
/// <summary>ISO16750 短时跌落 12V</summary>
|
||||||
IS016750_SHORTDROP_12V,
|
IS016750_SHORTDROP_12V,
|
||||||
|
/// <summary>ISO16750 短时跌落 24V</summary>
|
||||||
IS016750_SHORTDROP_24V,
|
IS016750_SHORTDROP_24V,
|
||||||
|
/// <summary>ISO16750 复位测试</summary>
|
||||||
IS016750_RESETTEST,
|
IS016750_RESETTEST,
|
||||||
|
/// <summary>ISO16750 启动曲线 12V 第 1 组</summary>
|
||||||
IS016750_STARTINGPROFILE_12V_1,
|
IS016750_STARTINGPROFILE_12V_1,
|
||||||
|
/// <summary>ISO16750 启动曲线 12V 第 2 组</summary>
|
||||||
IS016750_STARTINGPROFILE_12V_2,
|
IS016750_STARTINGPROFILE_12V_2,
|
||||||
|
/// <summary>ISO16750 启动曲线 12V 第 3 组</summary>
|
||||||
IS016750_STARTINGPROFILE_12V_3,
|
IS016750_STARTINGPROFILE_12V_3,
|
||||||
|
/// <summary>ISO16750 启动曲线 12V 第 4 组</summary>
|
||||||
IS016750_STARTINGPROFILE_12V_4,
|
IS016750_STARTINGPROFILE_12V_4,
|
||||||
|
/// <summary>ISO16750 启动曲线 24V 第 1 组</summary>
|
||||||
IS016750_STARTINGPROFILE_24V_1,
|
IS016750_STARTINGPROFILE_24V_1,
|
||||||
|
/// <summary>ISO16750 启动曲线 24V 第 2 组</summary>
|
||||||
IS016750_STARTINGPROFILE_24V_2,
|
IS016750_STARTINGPROFILE_24V_2,
|
||||||
|
/// <summary>ISO16750 启动曲线 24V 第 3 组</summary>
|
||||||
IS016750_STARTINGPROFILE_24V_3,
|
IS016750_STARTINGPROFILE_24V_3,
|
||||||
|
/// <summary>ISO16750 抛负载测试 A 12V</summary>
|
||||||
IS016750_LOADDUMP_TESTA_12V,
|
IS016750_LOADDUMP_TESTA_12V,
|
||||||
|
/// <summary>ISO16750 抛负载测试 A 24V</summary>
|
||||||
IS016750_LOADDUMP_TESTA_24V,
|
IS016750_LOADDUMP_TESTA_24V,
|
||||||
|
/// <summary>ISO16750 抛负载测试 B 12V</summary>
|
||||||
IS016750_LOADDUMP_TESTB_12V,
|
IS016750_LOADDUMP_TESTB_12V,
|
||||||
|
/// <summary>ISO16750 抛负载测试 B 24V</summary>
|
||||||
IS016750_LOADDUMP_TESTB_24V,
|
IS016750_LOADDUMP_TESTB_24V,
|
||||||
|
/// <summary>LV123 高压曲线 1</summary>
|
||||||
LV123_HV_1,
|
LV123_HV_1,
|
||||||
|
/// <summary>LV123 高压曲线 2A</summary>
|
||||||
LV123_HV_2A,
|
LV123_HV_2A,
|
||||||
|
/// <summary>LV123 高压曲线 2B</summary>
|
||||||
LV123_HV_2B,
|
LV123_HV_2B,
|
||||||
|
/// <summary>LV123 高压曲线 3</summary>
|
||||||
LV123_HV_3
|
LV123_HV_3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// S7200 工作模式枚举 (电源模式 / 负载模式)
|
||||||
|
/// </summary>
|
||||||
public enum S7200工作模式_枚举
|
public enum S7200工作模式_枚举
|
||||||
{
|
{
|
||||||
|
/// <summary>作为电源输出</summary>
|
||||||
电源模式,
|
电源模式,
|
||||||
|
/// <summary>作为负载吸收</summary>
|
||||||
负载模式,
|
负载模式,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 高压直流源载一体机 (适配 IT6000C SCPI指令集)
|
/// 高压直流源载一体机 (适配 IT6000C SCPI 指令集),支持电源输出与负载吸收双向工作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public class S7200 : Tcp
|
public class S7200 : Tcp
|
||||||
@@ -67,115 +121,239 @@ namespace DeviceCommand.Devices
|
|||||||
// SCPI 指令结束符
|
// SCPI 指令结束符
|
||||||
private const string ScpiDelimiter = "\n";
|
private const string ScpiDelimiter = "\n";
|
||||||
|
|
||||||
#region 设置
|
/// <summary>
|
||||||
|
/// 构造函数:传入 <see cref="TcpConfig"/> 一次性初始化一体机通信参数
|
||||||
public async Task 设置为远程模式(CancellationToken ct = default)
|
/// </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)
|
public async Task 设置电源工作模式(S7200工作模式_枚举 开关, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// IT6000C 为双向无缝切换,底层硬件无需显式发送源载切换指令
|
// IT6000C 为双向无缝切换,底层硬件无需显式发送源载切换指令
|
||||||
// 保留此方法仅为兼容您原有上位机的工步调用流程,直接返回即可
|
// 保留此方法仅为兼容原有上位机的工步调用流程
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置直流源工作模式 (FUNCtion 指令,如 VOLTage / CURRent / SOLar 等)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="模式">直流源工作模式枚举</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 设置直流源工作模式(S7200直流源模式_枚举 模式, CancellationToken ct = default)
|
public async Task 设置直流源工作模式(S7200直流源模式_枚举 模式, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 原指令: MODE {模式} -> 现 IT6000C 指令: FUNCtion {模式} (如 VOLTage / CURRent)[cite: 1]
|
|
||||||
// 若枚举 ToString() 后不匹配,建议在此处加 Switch 转换
|
|
||||||
await SendAsync($"FUNCtion {模式}{ScpiDelimiter}", ct);
|
await SendAsync($"FUNCtion {模式}{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置负载工作模式。IT6000C 负载控制通过负向边界实现
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="模式">负载工作模式枚举</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 设置负载工作模式(S7200负载模式_枚举 模式, CancellationToken ct = default)
|
public async Task 设置负载工作模式(S7200负载模式_枚举 模式, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// IT6000C 负载控制通过负向边界实现。若是想开启纯电阻模式,可调用 SINK:RESistance:STATe ON[cite: 1]
|
// 若想开启纯电阻模式,可调用 SINK:RESistance:STATe ON
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启或关闭通道输出 (OUTPut 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="开关">true: 开启输出, false: 关闭输出</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public async Task 设置通道开关(bool 开关, CancellationToken ct = default)
|
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)
|
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)
|
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)
|
public async Task 设置CV反向电流(double 电流, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 提醒: 此处传入的参数如果是正数,建议在外部或此处转换为负值,因为载模式限制需要负数[cite: 1]
|
// 载模式限制需要负数,若传入正数建议在外部转换为负值
|
||||||
await SendAsync($"CURRent:LIMit:NEGative {电流}{ScpiDelimiter}", ct);
|
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)
|
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)
|
public async Task 设置反向功率阈值(double 功率, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 提醒: 此处传入的参数必须为负数[cite: 1]
|
|
||||||
await SendAsync($"POWer:LIMit:NEGative {功率}{ScpiDelimiter}", ct);
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
public async Task 发送自定义命令(string 指令, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await SendAsync($"{指令}{ScpiDelimiter}", ct);
|
await SendAsync($"{指令}{ScpiDelimiter}", ct);
|
||||||
@@ -185,29 +363,49 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#region 查询
|
#region 查询
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询设备识别信息 (*IDN? 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>设备标识字符串 (制造商, 型号, 序列号, 固件版本)</returns>
|
||||||
public async Task<string> 查询设备信息(CancellationToken ct = default)
|
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)
|
public async Task<double> 查询实时电压(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var str = await WriteReadAsync($"MEASure:VOLTage?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
|
var str = await WriteReadAsync($"MEASure:VOLTage?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
return double.TryParse(str, out double result) ? result : 0;
|
return ExtractDouble(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询实时输出电流 (MEASure:CURRent? 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>实时电流值 (单位: A,保留两位小数)</returns>
|
||||||
public async Task<double> 查询实时电流(CancellationToken ct = default)
|
public async Task<double> 查询实时电流(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var str = await WriteReadAsync($"MEASure:CURRent?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
|
var str = await WriteReadAsync($"MEASure:CURRent?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
return double.TryParse(str, out double result) ? result : 0;
|
return ExtractDouble(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询实时功率 (MEASure:POWer? 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>实时功率值 (单位: W,保留两位小数)</returns>
|
||||||
public async Task<double> 查询功率(CancellationToken ct = default)
|
public async Task<double> 查询功率(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var str = await WriteReadAsync($"MEASure:POWer?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
|
var str = await WriteReadAsync($"MEASure:POWer?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
return double.TryParse(str, out double result) ? result : 0;
|
return ExtractDouble(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@@ -37,22 +38,48 @@ namespace DeviceCommand.Devices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum TekMeasurementType
|
public enum TekMeasurementType
|
||||||
{
|
{
|
||||||
|
/// <summary>幅度</summary>
|
||||||
AMPLitude,
|
AMPLitude,
|
||||||
|
/// <summary>频率</summary>
|
||||||
FREQuency,
|
FREQuency,
|
||||||
|
/// <summary>平均值</summary>
|
||||||
MEAN,
|
MEAN,
|
||||||
|
/// <summary>峰峰值</summary>
|
||||||
PK2PK,
|
PK2PK,
|
||||||
|
/// <summary>最大值</summary>
|
||||||
MAXimum,
|
MAXimum,
|
||||||
|
/// <summary>最小值</summary>
|
||||||
MINimum
|
MINimum
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tektronix 示波器 (MSO 4/5/6 系列),支持采集控制、通道设置、自动测量与截图导出
|
||||||
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public class TektronixMSO : Tcp
|
public class TektronixMSO : Tcp
|
||||||
{
|
{
|
||||||
// SCPI 指令结束符 (消息终止符需使用 LF)
|
// SCPI 指令结束符 (消息终止符需使用 LF)
|
||||||
private const string ScpiDelimiter = "\n";
|
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 测试项反序列化)
|
#region 兼容旧 MSO44B 枚举(供 ACP 测试项反序列化)
|
||||||
|
|
||||||
public enum AcquireMode { Sample = 0, PeakDetect = 1, HiRes = 2, Average = 3, Envelope = 4 }
|
public enum AcquireMode { Sample = 0, PeakDetect = 1, HiRes = 2, Average = 3, Envelope = 4 }
|
||||||
@@ -81,21 +108,32 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#region 1. 公共命令与状态查询
|
#region 1. 公共命令与状态查询
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询仪器识别码 (*IDN? 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>设备标识字符串 (制造商, 型号, 序列号, 固件版本)</returns>
|
||||||
public virtual async Task<string> 查询设备标识(CancellationToken ct = default)
|
public virtual async Task<string> 查询设备标识(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 返回仪器的标识代码[cite: 2]
|
|
||||||
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
|
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)
|
public virtual async Task<string> 查询忙碌状态(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 查询仪器是否处于忙碌状态,常用于同步操作[cite: 2]
|
|
||||||
return await WriteReadAsync($"BUSY?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return await WriteReadAsync($"BUSY?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指示仪器执行信号路径校准 (SPC) (*CAL? 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 执行自校准(CancellationToken ct = default)
|
public virtual async Task 执行自校准(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 指示仪器执行信号路径校准 (SPC)[cite: 2]
|
|
||||||
await SendAsync($"*CAL?{ScpiDelimiter}", ct);
|
await SendAsync($"*CAL?{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,24 +142,33 @@ namespace DeviceCommand.Devices
|
|||||||
#region 2. 采集系统控制 (Acquisition)
|
#region 2. 采集系统控制 (Acquisition)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启动或停止采集
|
/// 启动或停止采集 (ACQuire:STATE 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="运行">true: 启动采集 (RUN), false: 停止采集 (STOP)</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置采集状态(bool 运行, CancellationToken ct = default)
|
public virtual async Task 设置采集状态(bool 运行, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 启动、停止或返回采集状态[cite: 2]
|
|
||||||
string 参数 = 运行 ? "RUN" : "STOP";
|
string 参数 = 运行 ? "RUN" : "STOP";
|
||||||
await SendAsync($"ACQuire:STATE {参数}{ScpiDelimiter}", ct);
|
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)
|
public virtual async Task<string> 查询采集状态(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 启动、停止或返回采集状态[cite: 2]
|
|
||||||
return await WriteReadAsync($"ACQuire:STATE?{ScpiDelimiter}", ScpiDelimiter, ct);
|
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)
|
public virtual async Task 设置采集模式(TekAcquisitionMode 模式, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 设置或查询采集模式[cite: 2]
|
|
||||||
await SendAsync($"ACQuire:MODe {模式}{ScpiDelimiter}", ct);
|
await SendAsync($"ACQuire:MODe {模式}{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,23 +176,36 @@ namespace DeviceCommand.Devices
|
|||||||
|
|
||||||
#region 3. 水平系统控制 (Horizontal)
|
#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)
|
public virtual async Task 设置水平刻度(double 秒每格, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 设置或查询水平刻度 (Scale)[cite: 2]
|
|
||||||
string cmd = string.Format(CultureInfo.InvariantCulture, "HORizontal:SCAle {0:E}{1}", 秒每格, ScpiDelimiter);
|
string cmd = string.Format(CultureInfo.InvariantCulture, "HORizontal:SCAle {0:E}{1}", 秒每格, ScpiDelimiter);
|
||||||
await SendAsync(cmd, ct);
|
await SendAsync(cmd, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置水平记录长度 (HORizontal:RECOrdlength 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="长度">记录长度(采样点数)</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置记录长度(long 长度, CancellationToken ct = default)
|
public virtual async Task 设置记录长度(long 长度, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 设置或查询水平记录长度[cite: 2]
|
|
||||||
await SendAsync($"HORizontal:RECOrdlength {长度}{ScpiDelimiter}", ct);
|
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]
|
string resp = await WriteReadAsync($"HORizontal:SAMPLERate?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
return await WriteReadAsync($"HORizontal:SAMPLERate?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return ExtractDouble(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -153,18 +213,23 @@ namespace DeviceCommand.Devices
|
|||||||
#region 4. 通道与显示控制 (Vertical)
|
#region 4. 通道与显示控制 (Vertical)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 全局启用或关闭某通道的显示
|
/// 全局启用或关闭某通道的显示 (DISplay:GLObal:CH:STATE 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="通道号">通道编号 (1 - 4)</param>
|
||||||
|
/// <param name="开启">true: 开启通道显示, false: 关闭通道显示</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置通道显示开关(int 通道号, bool 开启, CancellationToken ct = default)
|
public virtual async Task 设置通道显示开关(int 通道号, bool 开启, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 4/5/6 Series MSO 标准通道显示指令[cite: 2]
|
|
||||||
string 参数 = 开启 ? "ON" : "OFF";
|
string 参数 = 开启 ? "ON" : "OFF";
|
||||||
await SendAsync($"DISplay:GLObal:CH{通道号}:STATE {参数}{ScpiDelimiter}", ct);
|
await SendAsync($"DISplay:GLObal:CH{通道号}:STATE {参数}{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置指定通道的垂直缩放比例 (Volts/Div)
|
/// 设置指定通道的垂直缩放比例 (CH:SCAle 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="通道号">通道编号 (1 - 4)</param>
|
||||||
|
/// <param name="伏特每格">垂直刻度值 (单位: V/Div)</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置通道垂直刻度(int 通道号, double 伏特每格, CancellationToken ct = default)
|
public virtual async Task 设置通道垂直刻度(int 通道号, double 伏特每格, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string cmd = string.Format(CultureInfo.InvariantCulture, "CH{0}:SCAle {1:E}{2}", 通道号, 伏特每格, ScpiDelimiter);
|
string cmd = string.Format(CultureInfo.InvariantCulture, "CH{0}:SCAle {1:E}{2}", 通道号, 伏特每格, ScpiDelimiter);
|
||||||
@@ -172,8 +237,11 @@ namespace DeviceCommand.Devices
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置指定通道的垂直位置 (Divisions)
|
/// 设置指定通道的垂直位置 (CH:POSition 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="通道号">通道编号 (1 - 4)</param>
|
||||||
|
/// <param name="格数">垂直位置偏移 (单位: Div)</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 设置通道垂直位置(int 通道号, double 格数, CancellationToken ct = default)
|
public virtual async Task 设置通道垂直位置(int 通道号, double 格数, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
string cmd = string.Format(CultureInfo.InvariantCulture, "CH{0}:POSition {1:F2}{2}", 通道号, 格数, ScpiDelimiter);
|
string cmd = string.Format(CultureInfo.InvariantCulture, "CH{0}:POSition {1:F2}{2}", 通道号, 格数, ScpiDelimiter);
|
||||||
@@ -185,43 +253,73 @@ namespace DeviceCommand.Devices
|
|||||||
#region 5. 自动测量 (Measurement)
|
#region 5. 自动测量 (Measurement)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 动态添加并开启一个测量项
|
/// 动态添加并开启一个测量项 (MEASUrement:ADDNew 指令)。
|
||||||
|
/// 4/5/6 Series MSO 必须先动态创建测量项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="测量项编号">测量项编号</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 开启测量项(int 测量项编号, CancellationToken ct = default)
|
public virtual async Task 开启测量项(int 测量项编号, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 4/5/6 Series MSO 必须先动态创建测量项[cite: 2]
|
|
||||||
await SendAsync($"MEASUrement:ADDNew \"MEAS{测量项编号}\"{ScpiDelimiter}", ct);
|
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)
|
public virtual async Task 设置测量类型(int 测量项编号, TekMeasurementType 类型, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 设置或查询测量类型[cite: 2]
|
|
||||||
await SendAsync($"MEASUrement:MEAS{测量项编号}:TYPe {类型}{ScpiDelimiter}", ct);
|
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)
|
public virtual async Task 设置测量源(int 测量项编号, string 源名称, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 4/5/6 Series 中设置测量源[cite: 2]
|
|
||||||
await SendAsync($"MEASUrement:MEAS{测量项编号}:SOUrce1 {源名称}{ScpiDelimiter}", ct);
|
await SendAsync($"MEASUrement:MEAS{测量项编号}:SOUrce1 {源名称}{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询测量项的当前采集平均值 (MEASUrement:RESUlts:CURRentacq:MEAN? 指令)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="测量项编号">测量项编号</param>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>测量项当前采集的平均值 (保留两位小数)</returns>
|
||||||
[Monitorable("测量项的当前采集平均值")]
|
[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]
|
string resp = await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:CURRentacq:MEAN?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
return 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]
|
string resp = await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:ALLAcqs:MEAN?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
return 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]
|
string resp = await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:ALLAcqs:MAXimum?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
return await WriteReadAsync($"MEASUrement:MEAS{测量项编号}:RESUlts:ALLAcqs:MAXimum?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return ExtractDouble(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -237,13 +335,13 @@ namespace DeviceCommand.Devices
|
|||||||
{
|
{
|
||||||
string 临时文件 = "E:/temp1.png";
|
string 临时文件 = "E:/temp1.png";
|
||||||
|
|
||||||
// 1. 直接保存截图到示波器U盘 (自动识别 .png 扩展名)[cite: 2]
|
// 1. 直接保存截图到示波器U盘 (自动识别 .png 扩展名)
|
||||||
await SendAsync($"SAVe:IMAGe \"{临时文件}\"{ScpiDelimiter}", ct);
|
await SendAsync($"SAVe:IMAGe \"{临时文件}\"{ScpiDelimiter}", ct);
|
||||||
|
|
||||||
// 2. 发送 *OPC? 并等待返回 1,确保图像文件已经完全写入磁盘[cite: 2]
|
// 2. 发送 *OPC? 并等待返回 1,确保图像文件已经完全写入磁盘
|
||||||
await WriteReadAsync($"*OPC?{ScpiDelimiter}", ScpiDelimiter, ct);
|
await WriteReadAsync($"*OPC?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
|
|
||||||
// 3. 将文件内容读取到当前通信接口[cite: 2]
|
// 3. 将文件内容读取到当前通信接口
|
||||||
await SendAsync($"FILESystem:READFile \"{临时文件}\"{ScpiDelimiter}", ct);
|
await SendAsync($"FILESystem:READFile \"{临时文件}\"{ScpiDelimiter}", ct);
|
||||||
|
|
||||||
// 4. 提取底层的二进制块 (Block Data)
|
// 4. 提取底层的二进制块 (Block Data)
|
||||||
@@ -252,7 +350,7 @@ namespace DeviceCommand.Devices
|
|||||||
// 5. 将提取的二进制字节流写入上位机本地磁盘
|
// 5. 将提取的二进制字节流写入上位机本地磁盘
|
||||||
await File.WriteAllBytesAsync(上位机文件路径, imageBytes, ct);
|
await File.WriteAllBytesAsync(上位机文件路径, imageBytes, ct);
|
||||||
|
|
||||||
// 6. 删除示波器上的临时文件,保持设备存储干净[cite: 2]
|
// 6. 删除示波器上的临时文件,保持设备存储干净
|
||||||
await SendAsync($"FILESystem:DELEte \"{临时文件}\"{ScpiDelimiter}", ct);
|
await SendAsync($"FILESystem:DELEte \"{临时文件}\"{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,41 +429,44 @@ namespace DeviceCommand.Devices
|
|||||||
#region 7. 状态与错误队列 (Status and Error)
|
#region 7. 状态与错误队列 (Status and Error)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清除所有的状态寄存器和错误/事件队列
|
/// 清除所有的状态寄存器和错误/事件队列 (*CLS 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
public virtual async Task 清除错误队列Async(CancellationToken ct = default)
|
public virtual async Task 清除错误队列Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 发送 *CLS 指令清空状态[cite: 2]
|
|
||||||
await SendAsync($"*CLS{ScpiDelimiter}", ct);
|
await SendAsync($"*CLS{ScpiDelimiter}", ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询错误队列中当前的事件/错误数量
|
/// 查询错误队列中当前的事件/错误数量 (EVQty? 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>事件队列中的事件数量字符串</returns>
|
||||||
public virtual async Task<string> 查询错误数量Async(CancellationToken ct = default)
|
public virtual async Task<string> 查询错误数量Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 返回事件队列中的事件数量
|
|
||||||
return await WriteReadAsync($"EVQty?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return await WriteReadAsync($"EVQty?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从错误队列中读取最早的一个事件/错误(包含代码和详细消息),并将其从队列中弹出
|
/// 从错误队列中读取最早的一个事件/错误(包含代码和详细消息),并将其从队列中弹出 (EVMsg? 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>事件代码和消息字符串</returns>
|
||||||
public virtual async Task<string> 读取单条错误消息Async(CancellationToken ct = default)
|
public virtual async Task<string> 读取单条错误消息Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 返回事件队列中的事件代码和消息
|
|
||||||
return await WriteReadAsync($"EVMsg?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return await WriteReadAsync($"EVMsg?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 读取并清空队列中的所有错误和事件消息
|
/// 读取并清空队列中的所有错误和事件消息 (ALLEv? 指令)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="ct">取消令牌</param>
|
||||||
|
/// <returns>所有事件及其消息字符串</returns>
|
||||||
public virtual async Task<string> 读取所有错误消息Async(CancellationToken ct = default)
|
public virtual async Task<string> 读取所有错误消息Async(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
// 返回所有事件及其消息
|
|
||||||
return await WriteReadAsync($"ALLEv?{ScpiDelimiter}", ScpiDelimiter, ct);
|
return await WriteReadAsync($"ALLEv?{ScpiDelimiter}", ScpiDelimiter, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,20 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace DeviceCommand.Flexible
|
namespace DeviceCommand.Flexible
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 灵活型 Modbus RTU 串口通信类(免实例化,每次调用临时创建串口连接)。
|
||||||
|
/// 支持保持寄存器与线圈的读写操作,内部使用通信锁保证同一时刻只有一个事务在执行,
|
||||||
|
/// 适用于偶发性、无需保持长连接的 Modbus RTU 设备读写场景。
|
||||||
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public static class FModbusRTU
|
public static class FModbusRTU
|
||||||
{
|
{
|
||||||
|
// 通信锁:保证同一时刻只有一个 Modbus 事务在执行
|
||||||
private static readonly SemaphoreSlim _commLock = new(1, 1);
|
private static readonly SemaphoreSlim _commLock = new(1, 1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建串口实例并配置超时参数。
|
||||||
|
/// </summary>
|
||||||
private static SerialPort CreatePort(
|
private static SerialPort CreatePort(
|
||||||
string portName,
|
string portName,
|
||||||
int baudRate,
|
int baudRate,
|
||||||
@@ -29,6 +38,9 @@ namespace DeviceCommand.Flexible
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基于指定串口创建 Modbus RTU 主站。
|
||||||
|
/// </summary>
|
||||||
private static IModbusMaster CreateMaster(SerialPort port)
|
private static IModbusMaster CreateMaster(SerialPort port)
|
||||||
{
|
{
|
||||||
return new ModbusFactory().CreateRtuMaster(port);
|
return new ModbusFactory().CreateRtuMaster(port);
|
||||||
@@ -36,7 +48,22 @@ namespace DeviceCommand.Flexible
|
|||||||
|
|
||||||
#region Holding Register
|
#region Holding Register
|
||||||
|
|
||||||
public static async Task<ushort[]> ReadHoldingRegistersAsync(
|
/// <summary>
|
||||||
|
/// 读取保持寄存器(功能码 03),返回指定数量的寄存器值数组。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="portName">串口名称,如 "COM1"</param>
|
||||||
|
/// <param name="baudRate">波特率,如 9600、115200</param>
|
||||||
|
/// <param name="slaveAddress">Modbus 从站站号 (1-247)</param>
|
||||||
|
/// <param name="startAddress">起始寄存器地址</param>
|
||||||
|
/// <param name="numberOfPoints">读取的寄存器数量</param>
|
||||||
|
/// <param name="dataBits">数据位,默认 8</param>
|
||||||
|
/// <param name="stopBits">停止位,默认 1 位</param>
|
||||||
|
/// <param name="parity">校验位,默认无校验</param>
|
||||||
|
/// <param name="readTimeout">读取超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="writeTimeout">写入超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
/// <returns>读取到的寄存器值数组</returns>
|
||||||
|
public static async Task<ushort[]> 读保持寄存器(
|
||||||
string portName,
|
string portName,
|
||||||
int baudRate,
|
int baudRate,
|
||||||
byte slaveAddress,
|
byte slaveAddress,
|
||||||
@@ -73,7 +100,21 @@ namespace DeviceCommand.Flexible
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task WriteSingleRegisterAsync(
|
/// <summary>
|
||||||
|
/// 写入单个保持寄存器(功能码 06)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="portName">串口名称,如 "COM1"</param>
|
||||||
|
/// <param name="baudRate">波特率,如 9600、115200</param>
|
||||||
|
/// <param name="slaveAddress">Modbus 从站站号 (1-247)</param>
|
||||||
|
/// <param name="registerAddress">要写入的寄存器地址</param>
|
||||||
|
/// <param name="value">要写入的寄存器值 (0-65535)</param>
|
||||||
|
/// <param name="dataBits">数据位,默认 8</param>
|
||||||
|
/// <param name="stopBits">停止位,默认 1 位</param>
|
||||||
|
/// <param name="parity">校验位,默认无校验</param>
|
||||||
|
/// <param name="readTimeout">读取超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="writeTimeout">写入超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
public static async Task 写单个寄存器(
|
||||||
string portName,
|
string portName,
|
||||||
int baudRate,
|
int baudRate,
|
||||||
byte slaveAddress,
|
byte slaveAddress,
|
||||||
@@ -114,7 +155,22 @@ namespace DeviceCommand.Flexible
|
|||||||
|
|
||||||
#region Coil
|
#region Coil
|
||||||
|
|
||||||
public static async Task<bool[]> ReadCoilsAsync(
|
/// <summary>
|
||||||
|
/// 读取线圈状态(功能码 01),返回指定数量的线圈开关状态数组。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="portName">串口名称,如 "COM1"</param>
|
||||||
|
/// <param name="baudRate">波特率,如 9600、115200</param>
|
||||||
|
/// <param name="slaveAddress">Modbus 从站站号 (1-247)</param>
|
||||||
|
/// <param name="startAddress">起始线圈地址</param>
|
||||||
|
/// <param name="numberOfPoints">读取的线圈数量</param>
|
||||||
|
/// <param name="dataBits">数据位,默认 8</param>
|
||||||
|
/// <param name="stopBits">停止位,默认 1 位</param>
|
||||||
|
/// <param name="parity">校验位,默认无校验</param>
|
||||||
|
/// <param name="readTimeout">读取超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="writeTimeout">写入超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
/// <returns>线圈状态数组,true 表示吸合/导通</returns>
|
||||||
|
public static async Task<bool[]> 读线圈(
|
||||||
string portName,
|
string portName,
|
||||||
int baudRate,
|
int baudRate,
|
||||||
byte slaveAddress,
|
byte slaveAddress,
|
||||||
@@ -151,7 +207,21 @@ namespace DeviceCommand.Flexible
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task WriteSingleCoilAsync(
|
/// <summary>
|
||||||
|
/// 写入单个线圈(功能码 05),控制单个开关量输出。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="portName">串口名称,如 "COM1"</param>
|
||||||
|
/// <param name="baudRate">波特率,如 9600、115200</param>
|
||||||
|
/// <param name="slaveAddress">Modbus 从站站号 (1-247)</param>
|
||||||
|
/// <param name="coilAddress">要写入的线圈地址</param>
|
||||||
|
/// <param name="value">线圈状态(true: 吸合/导通, false: 断开)</param>
|
||||||
|
/// <param name="dataBits">数据位,默认 8</param>
|
||||||
|
/// <param name="stopBits">停止位,默认 1 位</param>
|
||||||
|
/// <param name="parity">校验位,默认无校验</param>
|
||||||
|
/// <param name="readTimeout">读取超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="writeTimeout">写入超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
public static async Task 写单个线圈(
|
||||||
string portName,
|
string portName,
|
||||||
int baudRate,
|
int baudRate,
|
||||||
byte slaveAddress,
|
byte slaveAddress,
|
||||||
|
|||||||
@@ -8,11 +8,20 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace DeviceCommand.Flexible
|
namespace DeviceCommand.Flexible
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 灵活型 Modbus TCP 通信类(免实例化,每次调用临时建立 TCP 连接)。
|
||||||
|
/// 支持保持寄存器与线圈的读写操作,内部使用通信锁保证同一时刻只有一个事务在执行,
|
||||||
|
/// 适用于偶发性、无需保持长连接的 Modbus TCP 设备读写场景。
|
||||||
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public static class FModbusTCP
|
public static class FModbusTCP
|
||||||
{
|
{
|
||||||
|
// 通信锁:保证同一时刻只有一个 Modbus 事务在执行
|
||||||
private static readonly SemaphoreSlim _commLock = new(1, 1);
|
private static readonly SemaphoreSlim _commLock = new(1, 1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 建立 TCP 连接并创建 Modbus TCP 主站。
|
||||||
|
/// </summary>
|
||||||
private static async Task<IModbusMaster> ConnectAsync(string ipAddress, int port, int sendTimeout, int receiveTimeout, CancellationToken ct)
|
private static async Task<IModbusMaster> ConnectAsync(string ipAddress, int port, int sendTimeout, int receiveTimeout, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var tcpClient = new TcpClient();
|
var tcpClient = new TcpClient();
|
||||||
@@ -26,7 +35,19 @@ namespace DeviceCommand.Flexible
|
|||||||
|
|
||||||
#region Holding Registers
|
#region Holding Registers
|
||||||
|
|
||||||
public static async Task<ushort[]> ReadHoldingRegistersAsync(
|
/// <summary>
|
||||||
|
/// 读取保持寄存器(功能码 03),返回指定数量的寄存器值数组。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ipAddress">设备 IP 地址</param>
|
||||||
|
/// <param name="port">Modbus TCP 端口号,默认常用 502</param>
|
||||||
|
/// <param name="slaveAddress">Modbus 从站站号(单元标识符)</param>
|
||||||
|
/// <param name="startAddress">起始寄存器地址</param>
|
||||||
|
/// <param name="numberOfPoints">读取的寄存器数量</param>
|
||||||
|
/// <param name="sendTimeout">发送/连接超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="receiveTimeout">接收超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
/// <returns>读取到的寄存器值数组</returns>
|
||||||
|
public static async Task<ushort[]> 读保持寄存器(
|
||||||
string ipAddress,
|
string ipAddress,
|
||||||
int port,
|
int port,
|
||||||
byte slaveAddress,
|
byte slaveAddress,
|
||||||
@@ -51,7 +72,18 @@ namespace DeviceCommand.Flexible
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task WriteSingleRegisterAsync(
|
/// <summary>
|
||||||
|
/// 写入单个保持寄存器(功能码 06)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ipAddress">设备 IP 地址</param>
|
||||||
|
/// <param name="port">Modbus TCP 端口号,默认常用 502</param>
|
||||||
|
/// <param name="slaveAddress">Modbus 从站站号(单元标识符)</param>
|
||||||
|
/// <param name="registerAddress">要写入的寄存器地址</param>
|
||||||
|
/// <param name="value">要写入的寄存器值 (0-65535)</param>
|
||||||
|
/// <param name="sendTimeout">发送/连接超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="receiveTimeout">接收超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
public static async Task 写单个寄存器(
|
||||||
string ipAddress,
|
string ipAddress,
|
||||||
int port,
|
int port,
|
||||||
byte slaveAddress,
|
byte slaveAddress,
|
||||||
@@ -79,7 +111,19 @@ namespace DeviceCommand.Flexible
|
|||||||
|
|
||||||
#region Coils
|
#region Coils
|
||||||
|
|
||||||
public static async Task<bool[]> ReadCoilsAsync(
|
/// <summary>
|
||||||
|
/// 读取线圈状态(功能码 01),返回指定数量的线圈开关状态数组。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ipAddress">设备 IP 地址</param>
|
||||||
|
/// <param name="port">Modbus TCP 端口号,默认常用 502</param>
|
||||||
|
/// <param name="slaveAddress">Modbus 从站站号(单元标识符)</param>
|
||||||
|
/// <param name="startAddress">起始线圈地址</param>
|
||||||
|
/// <param name="numberOfPoints">读取的线圈数量</param>
|
||||||
|
/// <param name="sendTimeout">发送/连接超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="receiveTimeout">接收超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
/// <returns>线圈状态数组,true 表示吸合/导通</returns>
|
||||||
|
public static async Task<bool[]> 读线圈(
|
||||||
string ipAddress,
|
string ipAddress,
|
||||||
int port,
|
int port,
|
||||||
byte slaveAddress,
|
byte slaveAddress,
|
||||||
@@ -104,7 +148,18 @@ namespace DeviceCommand.Flexible
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task WriteSingleCoilAsync(
|
/// <summary>
|
||||||
|
/// 写入单个线圈(功能码 05),控制单个开关量输出。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ipAddress">设备 IP 地址</param>
|
||||||
|
/// <param name="port">Modbus TCP 端口号,默认常用 502</param>
|
||||||
|
/// <param name="slaveAddress">Modbus 从站站号(单元标识符)</param>
|
||||||
|
/// <param name="coilAddress">要写入的线圈地址</param>
|
||||||
|
/// <param name="value">线圈状态(true: 吸合/导通, false: 断开)</param>
|
||||||
|
/// <param name="sendTimeout">发送/连接超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="receiveTimeout">接收超时时间(毫秒),默认 3000</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
public static async Task 写单个线圈(
|
||||||
string ipAddress,
|
string ipAddress,
|
||||||
int port,
|
int port,
|
||||||
byte slaveAddress,
|
byte slaveAddress,
|
||||||
|
|||||||
@@ -7,11 +7,21 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace DeviceCommand.Flexible
|
namespace DeviceCommand.Flexible
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 灵活型串口通信类(免实例化,每次调用临时创建串口连接)。
|
||||||
|
/// 支持只发送指令、发送并读取应答两种最常用操作,
|
||||||
|
/// 内部使用通信锁保证同一时刻只有一个串口事务在执行,
|
||||||
|
/// 适用于偶发性、无需保持长连接的串口设备通信场景(如示波器、电源的 SCPI 指令)。
|
||||||
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public static class FSerialPort
|
public static class FSerialPort
|
||||||
{
|
{
|
||||||
|
// 通信锁:保证同一时刻只有一个串口事务在执行
|
||||||
private static readonly SemaphoreSlim _commLock = new(1, 1);
|
private static readonly SemaphoreSlim _commLock = new(1, 1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建串口实例并配置 UTF8 编码与超时参数。
|
||||||
|
/// </summary>
|
||||||
private static SerialPort CreatePort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, int sendTimeout,int receiveTimeout)
|
private static SerialPort CreatePort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, int sendTimeout,int receiveTimeout)
|
||||||
{
|
{
|
||||||
return new SerialPort(portName, baudRate, parity, dataBits, stopBits)
|
return new SerialPort(portName, baudRate, parity, dataBits, stopBits)
|
||||||
@@ -24,7 +34,19 @@ namespace DeviceCommand.Flexible
|
|||||||
|
|
||||||
#region 最常用:只发送字符串
|
#region 最常用:只发送字符串
|
||||||
|
|
||||||
public static async Task SendAsync(string portName,int baudRate,Parity parity,int dataBits,StopBits stopBits,int sendTimeout,int receiveTimeout,string command,CancellationToken ct = default)
|
/// <summary>
|
||||||
|
/// 向串口发送一条字符串指令(只发送,不等待应答)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="portName">串口名称,如 "COM1"</param>
|
||||||
|
/// <param name="baudRate">波特率,如 9600、115200</param>
|
||||||
|
/// <param name="parity">校验位</param>
|
||||||
|
/// <param name="dataBits">数据位,常用 8</param>
|
||||||
|
/// <param name="stopBits">停止位</param>
|
||||||
|
/// <param name="sendTimeout">发送超时时间(毫秒)</param>
|
||||||
|
/// <param name="receiveTimeout">接收超时时间(毫秒)</param>
|
||||||
|
/// <param name="command">要发送的指令字符串</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
public static async Task 发送指令(string portName,int baudRate,Parity parity,int dataBits,StopBits stopBits,int sendTimeout,int receiveTimeout,string command,CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await _commLock.WaitAsync(ct);
|
await _commLock.WaitAsync(ct);
|
||||||
try
|
try
|
||||||
@@ -52,7 +74,21 @@ namespace DeviceCommand.Flexible
|
|||||||
|
|
||||||
#region 最常用:发送字符串并读取字符串
|
#region 最常用:发送字符串并读取字符串
|
||||||
|
|
||||||
public static async Task<string> SendReadAsync(string portName,int baudRate, Parity parity, int dataBits, StopBits stopBits,int sendTimeout, int receiveTimeout,string command,string delimiter = "\n", CancellationToken ct = default)
|
/// <summary>
|
||||||
|
/// 向串口发送一条字符串指令并读取应答,读取到结束符为止(应答不含结束符)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="portName">串口名称,如 "COM1"</param>
|
||||||
|
/// <param name="baudRate">波特率,如 9600、115200</param>
|
||||||
|
/// <param name="parity">校验位</param>
|
||||||
|
/// <param name="dataBits">数据位,常用 8</param>
|
||||||
|
/// <param name="stopBits">停止位</param>
|
||||||
|
/// <param name="sendTimeout">发送超时时间(毫秒)</param>
|
||||||
|
/// <param name="receiveTimeout">接收超时时间(毫秒),超时未收到结束符抛出超时异常</param>
|
||||||
|
/// <param name="command">要发送的指令字符串</param>
|
||||||
|
/// <param name="delimiter">应答结束符,默认换行符 "\n"</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
/// <returns>去除结束符并去除首尾空白后的应答字符串</returns>
|
||||||
|
public static async Task<string> 发送并读取应答(string portName,int baudRate, Parity parity, int dataBits, StopBits stopBits,int sendTimeout, int receiveTimeout,string command,string delimiter = "\n", CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await _commLock.WaitAsync(ct);
|
await _commLock.WaitAsync(ct);
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -4,14 +4,29 @@ using System.Text;
|
|||||||
|
|
||||||
namespace DeviceCommand.Flexible
|
namespace DeviceCommand.Flexible
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 灵活型 TCP 通信类(免实例化,每次调用临时建立 TCP 连接)。
|
||||||
|
/// 支持字节/文本发送、定长字节读取、按结束符读取文本行四种操作,
|
||||||
|
/// 内部使用通信锁保证同一时刻只有一个 TCP 事务在执行,
|
||||||
|
/// 适用于偶发性、无需保持长连接的 TCP 设备通信场景。
|
||||||
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public static class FTCP
|
public static class FTCP
|
||||||
{
|
{
|
||||||
|
// 通信锁:保证同一时刻只有一个 TCP 事务在执行
|
||||||
private static readonly SemaphoreSlim _commLock = new(1, 1);
|
private static readonly SemaphoreSlim _commLock = new(1, 1);
|
||||||
|
|
||||||
#region Send
|
#region Send
|
||||||
|
|
||||||
public static async Task SendAsync(string ipAddress,int port,int sendTimeout, byte[] buffer, CancellationToken ct = default)
|
/// <summary>
|
||||||
|
/// 向指定 TCP 端点发送一段字节数据(发送完成后立即断开)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ipAddress">设备 IP 地址</param>
|
||||||
|
/// <param name="port">TCP 端口号</param>
|
||||||
|
/// <param name="sendTimeout">发送超时时间(毫秒)</param>
|
||||||
|
/// <param name="buffer">要发送的字节数组</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
public static async Task 发送字节数据(string ipAddress,int port,int sendTimeout, byte[] buffer, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await _commLock.WaitAsync(ct);
|
await _commLock.WaitAsync(ct);
|
||||||
try
|
try
|
||||||
@@ -30,16 +45,33 @@ namespace DeviceCommand.Flexible
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task SendAsync(string ipAddress, int port,int sendTimeout, string text,CancellationToken ct = default)
|
/// <summary>
|
||||||
|
/// 向指定 TCP 端点发送一段文本(以 UTF8 编码为字节后发送,发送完成后立即断开)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ipAddress">设备 IP 地址</param>
|
||||||
|
/// <param name="port">TCP 端口号</param>
|
||||||
|
/// <param name="sendTimeout">发送超时时间(毫秒)</param>
|
||||||
|
/// <param name="text">要发送的文本字符串</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
public static Task 发送文本数据(string ipAddress, int port,int sendTimeout, string text,CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
return SendAsync( ipAddress, port, sendTimeout, Encoding.UTF8.GetBytes(text),ct);
|
return 发送字节数据( ipAddress, port, sendTimeout, Encoding.UTF8.GetBytes(text),ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Read
|
#region Read
|
||||||
|
|
||||||
public static async Task<byte[]> ReadAsync(string ipAddress,int port,int receiveTimeout,int length,CancellationToken ct = default)
|
/// <summary>
|
||||||
|
/// 连接指定 TCP 端点并读取指定长度的字节数据(连接关闭或读满为止)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ipAddress">设备 IP 地址</param>
|
||||||
|
/// <param name="port">TCP 端口号</param>
|
||||||
|
/// <param name="receiveTimeout">接收超时时间(毫秒)</param>
|
||||||
|
/// <param name="length">要读取的字节长度</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
/// <returns>实际读取到的字节数组(对端提前关闭时可能短于请求长度)</returns>
|
||||||
|
public static async Task<byte[]> 读取字节数据(string ipAddress,int port,int receiveTimeout,int length,CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await _commLock.WaitAsync(ct);
|
await _commLock.WaitAsync(ct);
|
||||||
try
|
try
|
||||||
@@ -72,7 +104,16 @@ namespace DeviceCommand.Flexible
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string> ReadLineAsync( string ipAddress, int port, int receiveTimeout, string delimiter = "\n",CancellationToken ct = default)
|
/// <summary>
|
||||||
|
/// 连接指定 TCP 端点并读取一行文本,读取到结束符为止(返回内容不含结束符)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ipAddress">设备 IP 地址</param>
|
||||||
|
/// <param name="port">TCP 端口号</param>
|
||||||
|
/// <param name="receiveTimeout">接收超时时间(毫秒),超时未收到结束符抛出超时异常</param>
|
||||||
|
/// <param name="delimiter">文本行结束符,默认换行符 "\n"</param>
|
||||||
|
/// <param name="ct">异步取消令牌</param>
|
||||||
|
/// <returns>去除结束符并去除首尾空白后的文本行</returns>
|
||||||
|
public static async Task<string> 读取文本行( string ipAddress, int port, int receiveTimeout, string delimiter = "\n",CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
await _commLock.WaitAsync(ct);
|
await _commLock.WaitAsync(ct);
|
||||||
try
|
try
|
||||||
|
|||||||
+60
-55
@@ -10,6 +10,10 @@ using System.Text.Json;
|
|||||||
using TSMaster;
|
using TSMaster;
|
||||||
namespace TSMasterCAN
|
namespace TSMasterCAN
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// TSMaster CAN/CANFD 总线控制类,基于 TSMaster API 实现总线连接管理、
|
||||||
|
/// DBC 信号读写、报文发送(单次/循环)、日志记录等功能,暴露给命令树供测试步骤调用。
|
||||||
|
/// </summary>
|
||||||
[ACPCommand]
|
[ACPCommand]
|
||||||
public class CAN
|
public class CAN
|
||||||
{
|
{
|
||||||
@@ -70,9 +74,10 @@ namespace TSMasterCAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 连接
|
/// 连接 TSMaster CAN 总线:建立总线连接并启动 RBS 仿真系统,
|
||||||
|
/// 成功后置位连接标志并触发 <see cref="ConnectEvent"/> 连接事件。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns>返回代码,0 表示成功,非 0 表示失败(可用 <see cref="GetErrorDescription"/> 查询错误说明)</returns>
|
||||||
public static int Connect()
|
public static int Connect()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -99,9 +104,9 @@ namespace TSMasterCAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 断开
|
/// 断开 TSMaster CAN 总线连接,成功后清除连接标志并触发 <see cref="DisConnectEvent"/> 断开事件。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns>返回代码,0 表示成功,非 0 表示失败(可用 <see cref="GetErrorDescription"/> 查询错误说明)</returns>
|
||||||
public static int DisConnect()
|
public static int DisConnect()
|
||||||
{
|
{
|
||||||
var re = TsMasterApi.tsapp_disconnect();
|
var re = TsMasterApi.tsapp_disconnect();
|
||||||
@@ -161,19 +166,19 @@ namespace TSMasterCAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始记录日志
|
/// 开始记录总线日志,将总线上的报文数据记录到指定文件。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filePath"></param>
|
/// <param name="filePath">日志文件保存路径(自动转换为绝对路径)</param>
|
||||||
/// <returns></returns>
|
/// <returns>返回代码,0 表示成功,非 0 表示失败</returns>
|
||||||
public static int StartLogging(string filePath)
|
public static int StartLogging(string filePath)
|
||||||
{
|
{
|
||||||
return TsMasterApi.tsapp_start_logging(Path.GetFullPath(filePath));
|
return TsMasterApi.tsapp_start_logging(Path.GetFullPath(filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 结束记录日志
|
/// 结束总线日志记录。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns>返回代码,0 表示成功,非 0 表示失败</returns>
|
||||||
public static int StopLogging()
|
public static int StopLogging()
|
||||||
{
|
{
|
||||||
return TsMasterApi.tsapp_stop_logging();
|
return TsMasterApi.tsapp_stop_logging();
|
||||||
@@ -191,12 +196,12 @@ namespace TSMasterCAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取信号值
|
/// 获取 DBC 中定义信号的当前物理值(从总线接收报文中解析)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel"></param>
|
/// <param name="channel">通道号(0 起始)</param>
|
||||||
/// <param name="AMsgName"></param>
|
/// <param name="AMsgName">DBC 中的报文名称</param>
|
||||||
/// <param name="ASgnName"></param>
|
/// <param name="ASgnName">DBC 中的信号名称</param>
|
||||||
/// <returns></returns>
|
/// <returns>信号物理值,获取失败时返回 <see cref="double.NaN"/></returns>
|
||||||
public static double GetSignalValue(byte channel, string AMsgName, string ASgnName)
|
public static double GetSignalValue(byte channel, string AMsgName, string ASgnName)
|
||||||
{
|
{
|
||||||
double value = double.NaN;
|
double value = double.NaN;
|
||||||
@@ -237,16 +242,16 @@ namespace TSMasterCAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置信号值
|
/// 设置 DBC 中定义信号的值(按物理值编码进报文数据),可选择立即发送或周期发送。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel"></param>
|
/// <param name="channel">通道号(0 起始)</param>
|
||||||
/// <param name="AMsgName"></param>
|
/// <param name="AMsgName">DBC 中的报文名称</param>
|
||||||
/// <param name="ASgnName"></param>
|
/// <param name="ASgnName">DBC 中的信号名称</param>
|
||||||
/// <param name="AValue"></param>
|
/// <param name="AValue">要设置的信号物理值</param>
|
||||||
/// <param name="isSend"></param>
|
/// <param name="isSend">是否发送:false 仅更新数据不发送,true 则发送</param>
|
||||||
/// <param name="sendPeriod"></param>
|
/// <param name="sendPeriod">发送周期(毫秒):0 = 只发送一次;>0 = 按该周期循环发送</param>
|
||||||
/// <returns></returns>
|
/// <returns>返回代码,0 表示成功,非 0 表示失败</returns>
|
||||||
/// <exception cref="Exception"></exception>
|
/// <exception cref="Exception">信号编码写入报文失败时抛出</exception>
|
||||||
public static int SetSignalValue(byte channel, string AMsgName, string ASgnName, double AValue, bool isSend = false, float sendPeriod = 0)
|
public static int SetSignalValue(byte channel, string AMsgName, string ASgnName, double AValue, bool isSend = false, float sendPeriod = 0)
|
||||||
{
|
{
|
||||||
var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
|
var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
|
||||||
@@ -271,12 +276,12 @@ namespace TSMasterCAN
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置信号值
|
/// 按报文名称发送 DBC 中定义的报文(使用该报文在 DBC 数据库中的当前数据)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel"></param>
|
/// <param name="channel">通道号</param>
|
||||||
/// <param name="AMsgName"></param>
|
/// <param name="AMsgName">DBC 中的报文名称</param>
|
||||||
/// <param name="sendPeriod"></param>
|
/// <param name="sendPeriod">发送周期(毫秒):0 = 只发送一次;>0 = 按该周期循环发送</param>
|
||||||
/// <returns></returns>
|
/// <returns>返回代码,0 表示成功,非 0 表示失败</returns>
|
||||||
public static int SetSignalValue(APP_CHANNEL channel, string AMsgName, float sendPeriod = 0)
|
public static int SetSignalValue(APP_CHANNEL channel, string AMsgName, float sendPeriod = 0)
|
||||||
{
|
{
|
||||||
var find = DBCParse.MsgDatabase[(byte)channel].First(s => s.msg_name == AMsgName);
|
var find = DBCParse.MsgDatabase[(byte)channel].First(s => s.msg_name == AMsgName);
|
||||||
@@ -302,11 +307,11 @@ namespace TSMasterCAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置报文
|
/// 按帧 ID 更新 DBC 数据库中指定报文的数据区(仅更新内存中的数据,不发送)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel">通道</param>
|
/// <param name="channel">通道号</param>
|
||||||
/// <param name="ID">DBC数据库ID</param>
|
/// <param name="ID">报文帧 ID(DBC 中定义的 FIdentifier)</param>
|
||||||
/// <param name="bytes">报文数组</param>
|
/// <param name="bytes">要写入的报文数据数组,超出报文数据长度的部分会被截断</param>
|
||||||
public static void SetMsg(APP_CHANNEL channel, int ID, byte[] bytes)
|
public static void SetMsg(APP_CHANNEL channel, int ID, byte[] bytes)
|
||||||
{
|
{
|
||||||
var find = DBCParse.MsgDatabase[(byte)channel].FirstOrDefault(s => s.ACANFD.FIdentifier == ID);
|
var find = DBCParse.MsgDatabase[(byte)channel].FirstOrDefault(s => s.ACANFD.FIdentifier == ID);
|
||||||
@@ -317,20 +322,20 @@ namespace TSMasterCAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送自定义报文
|
/// 构造并发送自定义 CAN/CANFD 报文,可选择单次发送或周期发送,并可同步更新 DBC 数据库中同 ID 报文的数据。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="AIdxChn"></param>
|
/// <param name="AIdxChn">通道号</param>
|
||||||
/// <param name="AID"></param>
|
/// <param name="AID">报文帧 ID</param>
|
||||||
/// <param name="AIsTx"></param>
|
/// <param name="AIsTx">是否为发送帧</param>
|
||||||
/// <param name="AIsExt"></param>
|
/// <param name="AIsExt">是否为扩展帧(29 位 ID)</param>
|
||||||
/// <param name="AIsRemote"></param>
|
/// <param name="AIsRemote">是否为远程帧</param>
|
||||||
/// <param name="ADLC"></param>
|
/// <param name="ADLC">数据长度代码(数据字节数,最大 64)</param>
|
||||||
/// <param name="ADataArray"></param>
|
/// <param name="ADataArray">报文数据数组,超过 64 字节的部分会被截断</param>
|
||||||
/// <param name="AIsFD"></param>
|
/// <param name="AIsFD">是否为 CANFD 帧,默认 true</param>
|
||||||
/// <param name="AIsBRS"></param>
|
/// <param name="AIsBRS">是否切换数据段波特率(仅 CANFD 有效),默认 false</param>
|
||||||
/// <param name="isUpdateDBCDatabase"></param>
|
/// <param name="isUpdateDBCDatabase">是否同步更新 DBC 数据库中同帧 ID 报文的数据,默认 false</param>
|
||||||
/// <param name="sendPeriod"></param>
|
/// <param name="sendPeriod">发送周期(毫秒):0 = 只发送一次;>0 = 按该周期循环发送</param>
|
||||||
/// <returns></returns>
|
/// <returns>返回代码,0 表示成功,非 0 表示失败</returns>
|
||||||
public static int SendMsg(APP_CHANNEL AIdxChn, int AID, bool AIsTx, bool AIsExt,
|
public static int SendMsg(APP_CHANNEL AIdxChn, int AID, bool AIsTx, bool AIsExt,
|
||||||
bool AIsRemote, byte ADLC, byte[] ADataArray, bool AIsFD = true, bool AIsBRS = false,
|
bool AIsRemote, byte ADLC, byte[] ADataArray, bool AIsFD = true, bool AIsBRS = false,
|
||||||
bool isUpdateDBCDatabase = false, float sendPeriod = 0)
|
bool isUpdateDBCDatabase = false, float sendPeriod = 0)
|
||||||
@@ -375,12 +380,12 @@ namespace TSMasterCAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加循环发送报文
|
/// 将 DBC 中定义的报文加入循环发送列表,按指定周期持续发送。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel"></param>
|
/// <param name="channel">通道号(0 起始)</param>
|
||||||
/// <param name="AMsgName"></param>
|
/// <param name="AMsgName">DBC 中的报文名称</param>
|
||||||
/// <param name="sendPeriod"></param>
|
/// <param name="sendPeriod">发送周期(毫秒)</param>
|
||||||
/// <returns></returns>
|
/// <returns>返回代码,0 表示成功,非 0 表示失败</returns>
|
||||||
public static int AddCyclicMsg(byte channel, string AMsgName, float sendPeriod)
|
public static int AddCyclicMsg(byte channel, string AMsgName, float sendPeriod)
|
||||||
{
|
{
|
||||||
var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
|
var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
|
||||||
@@ -389,19 +394,19 @@ namespace TSMasterCAN
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清除循环发送的报文
|
/// 清除所有循环发送的报文,停止全部周期发送任务。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns>返回代码,0 表示成功,非 0 表示失败</returns>
|
||||||
public static int DeleteCyclicMsgs()
|
public static int DeleteCyclicMsgs()
|
||||||
{
|
{
|
||||||
return TsMasterApi.tsapp_delete_cyclic_msgs();
|
return TsMasterApi.tsapp_delete_cyclic_msgs();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取错误提示
|
/// 根据错误代码获取对应的错误文字描述,用于诊断 TSMaster API 返回码。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="errorCode">错误代码</param>
|
/// <param name="errorCode">TSMaster API 返回的错误代码</param>
|
||||||
/// <returns></returns>
|
/// <returns>错误描述文本,未知错误代码时返回提示信息</returns>
|
||||||
public static string GetErrorDescription(int errorCode)
|
public static string GetErrorDescription(int errorCode)
|
||||||
{
|
{
|
||||||
IntPtr ADesc = IntPtr.Zero;
|
IntPtr ADesc = IntPtr.Zero;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<UseWPF>false</UseWPF>
|
<UseWPF>false</UseWPF>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -192,21 +192,26 @@ namespace TestingModule.ViewModels
|
|||||||
var assembly = Assembly.LoadFrom(dllPath);
|
var assembly = Assembly.LoadFrom(dllPath);
|
||||||
Assemblies.Add(assembly);
|
Assemblies.Add(assembly);
|
||||||
|
|
||||||
// 加载对应的XML注释文件 (项目没有用到)
|
//加载对应的XML注释文件
|
||||||
//string xmlPath = Path.ChangeExtension(dllPath, ".xml");
|
string xmlPath = Path.ChangeExtension(dllPath, ".xml");
|
||||||
//if (File.Exists(xmlPath))
|
if (File.Exists(xmlPath))
|
||||||
//{
|
{
|
||||||
// try
|
try
|
||||||
// {
|
{
|
||||||
// XmlDocument xmlDoc = new XmlDocument();
|
XmlDocument xmlDoc = new XmlDocument();
|
||||||
// xmlDoc.Load(xmlPath);
|
xmlDoc.Load(xmlPath);
|
||||||
// _xmlDocumentCache[assembly.FullName!] = xmlDoc;
|
XmlDocumentCache[assembly.FullName!] = xmlDoc;
|
||||||
// }
|
LoggerHelper.Info($"[XML注释] 成功加载: {Path.GetFileName(xmlPath)} -> 程序集 [{assembly.FullName}]");
|
||||||
// catch (Exception xmlEx)
|
}
|
||||||
// {
|
catch (Exception xmlEx)
|
||||||
// LoggerHelper.WarnWithNotify($"加载XML注释失败: {Path.GetFileName(xmlPath)} - {xmlEx.Message}");
|
{
|
||||||
// }
|
LoggerHelper.Warn($"加载XML注释失败: {Path.GetFileName(xmlPath)} - {xmlEx.Message}");
|
||||||
//}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LoggerHelper.Warn($"[XML注释] XML文件不存在: {xmlPath}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -284,6 +289,7 @@ namespace TestingModule.ViewModels
|
|||||||
{
|
{
|
||||||
Name = subProgram.Name,
|
Name = subProgram.Name,
|
||||||
Tag = subProgram,
|
Tag = subProgram,
|
||||||
|
Tooltip = subProgram.FilePath
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,6 +374,7 @@ namespace TestingModule.ViewModels
|
|||||||
{
|
{
|
||||||
Name = $"{method.Name}({paramText})",
|
Name = $"{method.Name}({paramText})",
|
||||||
Tag = method,
|
Tag = method,
|
||||||
|
Tooltip = GetMethodDocumentation(method),
|
||||||
};
|
};
|
||||||
|
|
||||||
typeNode.Children.Add(methodNode);
|
typeNode.Children.Add(methodNode);
|
||||||
@@ -433,6 +440,95 @@ namespace TestingModule.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 添加获取注释的方法
|
||||||
|
private string? GetMethodDocumentation(MethodInfo method)
|
||||||
|
{
|
||||||
|
if (method.DeclaringType == null) return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string assemblyName = method.DeclaringType.Assembly.FullName!;
|
||||||
|
if (!_xmlDocumentCache.TryGetValue(assemblyName, out XmlDocument? xmlDoc))
|
||||||
|
{
|
||||||
|
LoggerHelper.Warn($"[XML注释] 缓存未命中: 程序集 [{assemblyName}],缓存包含 { _xmlDocumentCache.Count} 个条目: [{string.Join(", ", _xmlDocumentCache.Keys)}]");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成XML文档中的成员ID
|
||||||
|
string memberName = $"M:{method.DeclaringType.FullName}.{method.Name}";
|
||||||
|
var parameters = method.GetParameters();
|
||||||
|
if (parameters.Length > 0)
|
||||||
|
{
|
||||||
|
memberName += "(" + string.Join(",", parameters.Select(p => p.ParameterType.FullName)) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找注释节点
|
||||||
|
XmlNode? memberNode = xmlDoc.SelectSingleNode($"//member[@name='{memberName}']");
|
||||||
|
if (memberNode == null)
|
||||||
|
{
|
||||||
|
LoggerHelper.Warn($"[XML注释] 节点未找到: {memberName}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取摘要(summary)
|
||||||
|
var summaryNode = memberNode.SelectSingleNode("summary");
|
||||||
|
string documentation = "";
|
||||||
|
|
||||||
|
if (summaryNode != null)
|
||||||
|
{
|
||||||
|
documentation += CleanXmlContent(summaryNode.InnerXml);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取参数注释(param)
|
||||||
|
var paramNodes = memberNode.SelectNodes("param");
|
||||||
|
if (paramNodes != null && paramNodes.Count > 0)
|
||||||
|
{
|
||||||
|
documentation += "\n\n参数:";
|
||||||
|
foreach (XmlNode paramNode in paramNodes)
|
||||||
|
{
|
||||||
|
string? paramName = paramNode.Attributes?["name"]?.Value;
|
||||||
|
if (!string.IsNullOrEmpty(paramName))
|
||||||
|
{
|
||||||
|
documentation += $"\n • {paramName}: {CleanXmlContent(paramNode.InnerXml)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取返回值注释(returns)
|
||||||
|
var returnsNode = memberNode.SelectSingleNode("returns");
|
||||||
|
if (returnsNode != null)
|
||||||
|
{
|
||||||
|
documentation += $"\n\n返回值: {CleanXmlContent(returnsNode.InnerXml)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.IsNullOrWhiteSpace(documentation)
|
||||||
|
? null
|
||||||
|
: System.Net.WebUtility.HtmlDecode(documentation.Trim());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.Warn($"获取注释失败: {method.Name} - {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助方法:清理XML内容
|
||||||
|
private string CleanXmlContent(string xmlContent)
|
||||||
|
{
|
||||||
|
return xmlContent
|
||||||
|
.Replace("<see cref=\"", "")
|
||||||
|
.Replace("\"/>", "")
|
||||||
|
.Replace("<para>", "\n")
|
||||||
|
.Replace("</para>", "")
|
||||||
|
.Replace("<seealso", "")
|
||||||
|
.Replace("/>", "")
|
||||||
|
.Replace("<c>", "") // 处理代码标签
|
||||||
|
.Replace("</c>", "")
|
||||||
|
.Replace("<code>", "")
|
||||||
|
.Replace("</code>", "")
|
||||||
|
.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region 指令添加
|
#region 指令添加
|
||||||
|
|
||||||
|
|||||||
@@ -178,10 +178,15 @@ namespace TestingModule.ViewModels
|
|||||||
|
|
||||||
private void SelectionChanged(object parameter)
|
private void SelectionChanged(object parameter)
|
||||||
{
|
{
|
||||||
var selectedList = parameter as IList;
|
if (parameter is IList list && list.Count > 0)
|
||||||
if (selectedList != null)
|
|
||||||
{
|
{
|
||||||
SelectedItems = selectedList.Cast<StepVM>().ToList();
|
SelectedItems = list.Cast<StepVM>().ToList();
|
||||||
|
}
|
||||||
|
else if (parameter is IEnumerable enumerable && parameter is not string)
|
||||||
|
{
|
||||||
|
var items = enumerable.Cast<StepVM>().ToList();
|
||||||
|
if (items.Count > 0)
|
||||||
|
SelectedItems = items;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,13 +205,19 @@ namespace TestingModule.ViewModels
|
|||||||
}
|
}
|
||||||
private void CopyStep()
|
private void CopyStep()
|
||||||
{
|
{
|
||||||
if (_globalInfo.IsAdmin && SelectedItems.Any())
|
if (!_globalInfo.IsAdmin) return;
|
||||||
|
|
||||||
|
// 优先用多选列表,回退到单选
|
||||||
|
var source = (SelectedItems != null && SelectedItems.Any())
|
||||||
|
? SelectedItems
|
||||||
|
: (SelectedStep != null ? new List<StepVM> { SelectedStep } : null);
|
||||||
|
|
||||||
|
if (source == null || !source.Any()) return;
|
||||||
|
|
||||||
|
tmpCopyList.Clear();
|
||||||
|
foreach (var item in source)
|
||||||
{
|
{
|
||||||
tmpCopyList.Clear();
|
tmpCopyList.Add(item);
|
||||||
foreach (var item in SelectedItems)
|
|
||||||
{
|
|
||||||
tmpCopyList.Add(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void PasteStep()
|
private void PasteStep()
|
||||||
@@ -243,31 +254,29 @@ namespace TestingModule.ViewModels
|
|||||||
}
|
}
|
||||||
private void DeleteStep()
|
private void DeleteStep()
|
||||||
{
|
{
|
||||||
// 确保有选中的项
|
if (!_globalInfo.IsAdmin) return;
|
||||||
if (_globalInfo.IsAdmin && SelectedItems != null && SelectedItems.Any())
|
|
||||||
|
// 优先用多选列表,回退到单选
|
||||||
|
var source = (SelectedItems != null && SelectedItems.Any())
|
||||||
|
? SelectedItems.ToList()
|
||||||
|
: (SelectedStep != null ? new List<StepVM> { SelectedStep } : null);
|
||||||
|
|
||||||
|
if (source == null || !source.Any()) return;
|
||||||
|
|
||||||
|
foreach (var item in source)
|
||||||
{
|
{
|
||||||
// 创建一个副本进行循环,防止在 Remove 过程中集合变化导致的问题
|
_eventAggregator.GetEvent<DeletedStepEvent>().Publish(item.ID);
|
||||||
var toDelete = SelectedItems.ToList();
|
|
||||||
|
|
||||||
foreach (var item in toDelete)
|
if (_ScopedContext.SelectedStepList == "主程序")
|
||||||
{
|
Program.StepCollection.Remove(item);
|
||||||
_eventAggregator.GetEvent<DeletedStepEvent>().Publish(item.ID);
|
else if (_ScopedContext.SelectedStepList == "错误程序")
|
||||||
|
Program.ErrorStepCollection.Remove(item);
|
||||||
if (_ScopedContext.SelectedStepList == "主程序")
|
|
||||||
{
|
|
||||||
Program.StepCollection.Remove(item);
|
|
||||||
}
|
|
||||||
else if (_ScopedContext.SelectedStepList == "错误程序")
|
|
||||||
{
|
|
||||||
Program.ErrorStepCollection.Remove(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 清空 ViewModel 的选中状态,避免悬挂引用
|
|
||||||
SelectedStep = null;
|
|
||||||
SelectedItems.Clear();
|
|
||||||
_ScopedContext.SelectedStep = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清空 ViewModel 的选中状态,避免悬挂引用
|
||||||
|
SelectedStep = null;
|
||||||
|
SelectedItems?.Clear();
|
||||||
|
_ScopedContext.SelectedStep = null;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -313,6 +322,7 @@ namespace TestingModule.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnSubProgramNavigate(SubProgramNavigatePayload payload)
|
private void OnSubProgramNavigate(SubProgramNavigatePayload payload)
|
||||||
{
|
{
|
||||||
|
if (_ScopedContext == null || payload == null) return;
|
||||||
var nav = payload.IsErrorProgram ? _ScopedContext.ErrorNav : _ScopedContext.MainNav;
|
var nav = payload.IsErrorProgram ? _ScopedContext.ErrorNav : _ScopedContext.MainNav;
|
||||||
if (payload.Action == NavigateAction.Enter && payload.SubProgram != null)
|
if (payload.Action == NavigateAction.Enter && payload.SubProgram != null)
|
||||||
{
|
{
|
||||||
@@ -381,6 +391,12 @@ namespace TestingModule.ViewModels
|
|||||||
UnsubscribeStepCollections();
|
UnsubscribeStepCollections();
|
||||||
SubscribeStepCollections();
|
SubscribeStepCollections();
|
||||||
|
|
||||||
|
// 通知 UI 刷新 DisplaySteps(导航状态虽然引用同一 Program,但集合实例已变)
|
||||||
|
RaisePropertyChanged(nameof(MainDisplaySteps));
|
||||||
|
RaisePropertyChanged(nameof(ErrorDisplaySteps));
|
||||||
|
RaisePropertyChanged(nameof(MainCurrentProgram));
|
||||||
|
RaisePropertyChanged(nameof(ErrorCurrentProgram));
|
||||||
|
|
||||||
// 集合被整体替换后,对新集合重新编号
|
// 集合被整体替换后,对新集合重新编号
|
||||||
Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
|
Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
|
||||||
{
|
{
|
||||||
@@ -433,7 +449,7 @@ namespace TestingModule.ViewModels
|
|||||||
Program.PropertyChanged -= Program_PropertyChanged;
|
Program.PropertyChanged -= Program_PropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 【核心修复】必须显式退订 Prism 全局事件
|
// 3. 显式退订全局 Prism 事件
|
||||||
_eventAggregator?.GetEvent<AlarmEvent>()?.Unsubscribe(null);
|
_eventAggregator?.GetEvent<AlarmEvent>()?.Unsubscribe(null);
|
||||||
_eventAggregator?.GetEvent<SubProgramNavigateEvent>()?.Unsubscribe(null);
|
_eventAggregator?.GetEvent<SubProgramNavigateEvent>()?.Unsubscribe(null);
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,8 @@
|
|||||||
<TreeView.Resources>
|
<TreeView.Resources>
|
||||||
<HierarchicalDataTemplate DataType="{x:Type model:InstructionNodeVM}"
|
<HierarchicalDataTemplate DataType="{x:Type model:InstructionNodeVM}"
|
||||||
ItemsSource="{Binding Children}">
|
ItemsSource="{Binding Children}">
|
||||||
<TextBlock Text="{Binding Name}" />
|
<TextBlock Text="{Binding Name}" ToolTip="{Binding Tooltip}"/>
|
||||||
|
|
||||||
</HierarchicalDataTemplate>
|
</HierarchicalDataTemplate>
|
||||||
</TreeView.Resources>
|
</TreeView.Resources>
|
||||||
<!-- 双击 -->
|
<!-- 双击 -->
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace UIShare.UIViewModel
|
|||||||
public class InstructionNodeVM : BindableBase
|
public class InstructionNodeVM : BindableBase
|
||||||
{
|
{
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get => _name;
|
get => _name;
|
||||||
@@ -32,5 +32,12 @@ namespace UIShare.UIViewModel
|
|||||||
get => _tag;
|
get => _tag;
|
||||||
set => SetProperty(ref _tag, value);
|
set => SetProperty(ref _tag, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string? _tooltip;
|
||||||
|
public string? Tooltip
|
||||||
|
{
|
||||||
|
get => _tooltip;
|
||||||
|
set => SetProperty(ref _tooltip, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user