移植程序

This commit is contained in:
“hsc”
2026-07-29 13:28:31 +08:00
parent 8cf45d36b9
commit d8a22a15b1
36 changed files with 2 additions and 7721 deletions

View File

@@ -1,540 +0,0 @@
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace DeviceCommand.Devices
{
[ACPCommand]
public class GantryControlTcp : ModbusTcp
{
private readonly byte _slaveAddress=1;
// 向后兼容TcpDevice 即自身(继承自 ModbusTcp
public ModbusTcp TcpDevice => this;
public GantryControlTcp(TcpConfig config) : base(config)
{
}
// =================================================================
// ------------------ Coil / Bit 状态与控制 (位元件) ------------------
// =================================================================
private const ushort ADDR_M_ESTOP = 20496; // 0x5010: 紧停
private const ushort ADDR_M_X_STOP = 41; // 0x29: X轴停止
private const ushort ADDR_M_Y_STOP = 42; // 0x2A: Y轴停止
private const ushort ADDR_M_Z_STOP = 43; // 0x2B: Z轴停止
private const ushort ADDR_M_X_START = 30; // 0x1E: X轴指定位置启动
private const ushort ADDR_M_Y_START = 31; // 0x1F: Y轴指定位置启动
private const ushort ADDR_M_Z_START = 35; // 0x23: Z轴指定位置启动
private const ushort ADDR_M_HOME_TRIGGER = 100; // 0x64: 回原点触发
// =================================================================
// ------------------ 轴使能控制 (HM 寄存器) ------------------
// =================================================================
private const ushort ADDR_HM_AXIS1_ENABLE = 49408; // 0xC100: 轴1使能 (X轴)
private const ushort ADDR_HM_AXIS2_ENABLE = 49409; // 0xC101: 轴2使能 (Y轴)
private const ushort ADDR_HM_AXIS3_ENABLE = 49410; // 0xC102: 轴3使能 (Z轴)
private const ushort ADDR_HM_AXIS4_ENABLE = 49411; // 0xC103: 轴4使能
private const ushort ADDR_HM_AXIS5_ENABLE = 49412; // 0xC104: 轴5使能
private const ushort ADDR_HM_AXIS6_ENABLE = 49413; // 0xC105: 轴6使能
// =================================================================
// ------------------ 速度与位置参数 (HD 32位数据寄存器) --------------
// =================================================================
private const ushort ADDR_HD_HOME_POS_SPEED = 41288; // 0xA148: 原点定位速度 (32位)
// 轴原点位置
private const ushort ADDR_HD_X_HOME_POS = 41198; // 0xA0EE: X轴原点位 (32位)
private const ushort ADDR_HD_Z_HOME_POS = 41208; // 0xA0F8: Z轴原点位 (32位)
private const ushort ADDR_HD_Y_HOME_POS = 41218; // 0xA102: Y轴原点位 (32位)
// 轴运行目标位置
private const ushort ADDR_HD_Y_TARGET = 41228; // 0xA10C: Y轴指定位置 (32位)
private const ushort ADDR_HD_Z_TARGET = 41238; // 0xA116: Z轴指定位置 (32位)
private const ushort ADDR_HD_X_TARGET = 41248; // 0xA120: X轴指定位置 (32位)
// 轴运行速度
private const ushort ADDR_HD_X_SPEED = 41318; // 0xA166: X轴速度 (32位)
private const ushort ADDR_HD_Z_SPEED = 41328; // 0xA170: Z轴速度 (32位)
private const ushort ADDR_HD_Y_SPEED = 41338; // 0xA17A: Y轴速度 (32位)
// =================================================================
// ------------------ 轴绝对位置(只读,相对原点)------------------
// =================================================================
private const ushort ADDR_ABS_AXIS1_POS = 47232; // 轴1绝对位置 (32位)
private const ushort ADDR_ABS_AXIS2_POS = 47236; // 轴2绝对位置 (32位)
private const ushort ADDR_ABS_AXIS3_POS = 47240; // 轴3绝对位置 (32位)
private const ushort ADDR_ABS_AXIS4_POS = 47244; // 轴4绝对位置 (32位)
private const ushort ADDR_ABS_AXIS5_POS = 47248; // 轴5绝对位置 (32位)
private const ushort ADDR_ABS_AXIS6_POS = 47252; // 轴6绝对位置 (32位)
// =================================================================
// ------------------ 核心控制逻辑与参数读写 ------------------------
// =================================================================
/// <summary>
/// 轴使能控制
/// </summary>
/// <param name="axis">轴编号 (1 - 6)</param>
public async Task SetAxisEnableAsync(int axis, bool enable, CancellationToken ct = default)
{
ushort address = axis switch
{
1 => ADDR_HM_AXIS1_ENABLE,
2 => ADDR_HM_AXIS2_ENABLE,
3 => ADDR_HM_AXIS3_ENABLE,
4 => ADDR_HM_AXIS4_ENABLE,
5 => ADDR_HM_AXIS5_ENABLE,
6 => ADDR_HM_AXIS6_ENABLE,
_ => throw new ArgumentException("轴通道错误,仅支持 1 - 6", nameof(axis))
};
await WriteSingleCoilAsync(_slaveAddress, address, enable, ct);
}
/// <summary>
/// 读取指定轴的使能状态
/// </summary>
/// <param name="axis">1: X轴, 2: Y轴, 3: Z轴</param>
public async Task<bool> GetAxisEnableAsync(int axis, CancellationToken ct = default)
{
ushort address = axis switch
{
1 => ADDR_HM_AXIS1_ENABLE,
2 => ADDR_HM_AXIS2_ENABLE,
3 => ADDR_HM_AXIS3_ENABLE,
_ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis))
};
bool[] coils = await ReadCoilsAsync(_slaveAddress, address, 1, ct);
return coils != null && coils.Length > 0 && coils[0];
}
/// <summary>
/// 同时设置 X/Y/Z 轴的原点位置(带各自独立的范围检查)
/// </summary>
/// <param name="xPos">X轴原点位置 (范围: 0 ~ 50000)</param>
/// <param name="yPos">Y轴原点位置 (范围: 0 ~ 50000)</param>
/// <param name="zPos">Z轴原点位置 (范围: 0 ~ 20000)</param>
public async Task SetHomePositionAsync(int xPos, int yPos, int zPos, CancellationToken ct = default)
{
if (xPos < 0 || xPos > 50000)
throw new ArgumentOutOfRangeException(nameof(xPos), $"X轴原点设置值 [{xPos}] 超出合法范围 (0 - 50000)");
if (yPos < 0 || yPos > 50000)
throw new ArgumentOutOfRangeException(nameof(yPos), $"Y轴原点设置值 [{yPos}] 超出合法范围 (0 - 50000)");
if (zPos < 0 || zPos > 20000)
throw new ArgumentOutOfRangeException(nameof(zPos), $"Z轴原点设置值 [{zPos}] 超出合法范围 (0 - 20000)");
await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_X_HOME_POS, Int32ToUshorts(xPos), ct);
await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Y_HOME_POS, Int32ToUshorts(yPos), ct);
await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Z_HOME_POS, Int32ToUshorts(zPos), ct);
}
/// <summary>
/// 批量查询当前 X、Y、Z 三轴设定的原点位置值
/// </summary>
/// <returns>返回包含三轴原点位置的元组 (X, Y, Z)</returns>
public async Task<(int X, int Y, int Z)> GetHomePositionAsync(CancellationToken ct = default)
{
// 41218(Y) - 41198(X) = 20加Y轴自身的 2 个寄存器,共批量读取 22 个连续寄存器
ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, ADDR_HD_X_HOME_POS, 22, ct);
if (registers == null || registers.Length < 22)
throw new InvalidOperationException("从 PLC 读取三轴原点位置失败,返回数据长度不足。");
int xHomePos = UshortsToInt32(new ushort[] { registers[0], registers[1] });
int zHomePos = UshortsToInt32(new ushort[] { registers[10], registers[11] });
int yHomePos = UshortsToInt32(new ushort[] { registers[20], registers[21] });
return (xHomePos, yHomePos, zHomePos);
}
/// <summary>
/// 设置回原点定位速度(带 0 - 100000 范围检查)
/// </summary>
public async Task SetHomePositionSpeedAsync(int speed, CancellationToken ct = default)
{
if (speed < 0 || speed > 100000)
throw new ArgumentOutOfRangeException(nameof(speed), $"回原点定位速度值 [{speed}] 超出合法范围 (0 - 100000)");
await WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_HOME_POS_SPEED, Int32ToUshorts(speed), ct);
}
/// <summary>
/// 查询当前设定的回原点定位速度
/// </summary>
public async Task<int> GetHomePositionSpeedAsync(CancellationToken ct = default)
{
ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, ADDR_HD_HOME_POS_SPEED, 2, ct);
if (registers == null || registers.Length < 2)
throw new InvalidOperationException("从 PLC 读取回原点定位速度失败,返回数据长度不足。");
return UshortsToInt32(registers);
}
/// <summary>
/// 设置指定轴的运行速度(带 0 - 100000 范围检查)
/// </summary>
/// <param name="axis">1: X轴, 2: Y轴, 3: Z轴</param>
public async Task SetAxisSpeedAsync(int axis, int speed, CancellationToken ct = default)
{
if (speed < 0 || speed > 100000)
throw new ArgumentOutOfRangeException(nameof(speed), $"轴速度设置值 [{speed}] 超出合法范围 (0 - 100000)");
ushort address = axis switch
{
1 => ADDR_HD_X_SPEED,
2 => ADDR_HD_Y_SPEED,
3 => ADDR_HD_Z_SPEED,
_ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis))
};
await WriteMultipleRegistersAsync(_slaveAddress, address, Int32ToUshorts(speed), ct);
}
/// <summary>
/// 读取指定轴当前设定的运行速度
/// </summary>
public async Task<int> GetAxisSpeedAsync(int axis, CancellationToken ct = default)
{
ushort address = axis switch
{
1 => ADDR_HD_X_SPEED,
2 => ADDR_HD_Y_SPEED,
3 => ADDR_HD_Z_SPEED,
_ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis))
};
ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, address, 2, ct);
if (registers == null || registers.Length < 2)
throw new InvalidOperationException($"从 PLC 读取轴 {axis} 速度失败。");
return UshortsToInt32(registers);
}
/// <summary>
/// 写入指定轴的目标位置(动态安全校验:目标位置不能超过 [轴最大物理极限 - 当前轴原点设置值]
/// </summary>
public async Task SetAxisTargetPositionAsync(int axis, int targetPos, CancellationToken ct = default)
{
var (xHome, yHome, zHome) = await GetHomePositionAsync(ct);
ushort targetAddress;
int maxLimit;
int currentHomePos;
switch (axis)
{
case 1:
targetAddress = ADDR_HD_X_TARGET;
maxLimit = 50000;
currentHomePos = xHome;
break;
case 2:
targetAddress = ADDR_HD_Y_TARGET;
maxLimit = 50000;
currentHomePos = yHome;
break;
case 3:
targetAddress = ADDR_HD_Z_TARGET;
maxLimit = 20000;
currentHomePos = zHome;
break;
default:
throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis));
}
int allowedMaxLimit = maxLimit - currentHomePos;
if (targetPos < 0 || targetPos > allowedMaxLimit)
{
throw new ArgumentOutOfRangeException(
nameof(targetPos),
$"轴 {axis} 目标位置 [{targetPos}] 不合法!当前原点为 [{currentHomePos}],允许的有效写入范围为: 0 - {allowedMaxLimit}"
);
}
await WriteMultipleRegistersAsync(_slaveAddress, targetAddress, Int32ToUshorts(targetPos), ct);
}
/// <summary>
/// 读取指定轴当前设定的目标指定位置
/// </summary>
public async Task<int> GetAxisTargetPositionAsync(int axis, CancellationToken ct = default)
{
ushort address = axis switch
{
1 => ADDR_HD_X_TARGET,
2 => ADDR_HD_Y_TARGET,
3 => ADDR_HD_Z_TARGET,
_ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis))
};
ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, address, 2, ct);
if (registers == null || registers.Length < 2)
throw new InvalidOperationException($"从 PLC 读取轴 {axis} 目标位置失败。");
return UshortsToInt32(registers);
}
/// <summary>
/// 设置系统紧停锁定状态 (true: 锁定激活, false: 解除锁定)
/// </summary>
public async Task SetEStopStateAsync(bool state, CancellationToken ct = default)
{
await WriteSingleCoilAsync(_slaveAddress, ADDR_M_ESTOP, state, ct);
}
/// <summary>
/// 设置指定轴的停止控制状态 (true: 持续输出停止信号, false: 释放停止信号)
/// </summary>
public async Task SetStopStateAsync(int axis, bool state, CancellationToken ct = default)
{
ushort address = axis switch
{
1 => ADDR_M_X_STOP,
2 => ADDR_M_Y_STOP,
3 => ADDR_M_Z_STOP,
_ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis))
};
await WriteSingleCoilAsync(_slaveAddress, address, state, ct);
}
/// <summary>
/// 全局回零(安全校验版:先检查回原点速度是否为 0为0则拒绝触发
/// </summary>
public async Task HomeAsync(CancellationToken ct = default)
{
int currentSpeed = await GetHomePositionSpeedAsync(ct);
if (currentSpeed == 0)
throw new InvalidOperationException("无法触发回原点!当前回原点定位速度为 0请先设置合法的回零速度。");
await TriggerCoilAsync(ADDR_M_HOME_TRIGGER, ct);
}
/// <summary>
/// 单轴指定位置启动(含速度判定、使能自动补齐、动作目标位置独立范围校验)
/// </summary>
/// <param name="axis">1: X轴, 2: Y轴, 3: Z轴</param>
public async Task StartSingleAxisAsync(int axis, CancellationToken ct = default)
{
ushort startAddress;
int maxLimit;
int currentHomePos;
// 1. 获取基础参数与校验边界
var (xHome, yHome, zHome) = await GetHomePositionAsync(ct);
switch (axis)
{
case 1:
startAddress = ADDR_M_X_START;
maxLimit = 50000;
currentHomePos = xHome;
break;
case 2:
startAddress = ADDR_M_Y_START;
maxLimit = 50000;
currentHomePos = yHome;
break;
case 3:
startAddress = ADDR_M_Z_START;
maxLimit = 20000;
currentHomePos = zHome;
break;
default:
throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)", nameof(axis));
}
// 2. 检查动作轴的速度
int currentSpeed = await GetAxisSpeedAsync(axis, ct);
if (currentSpeed == 0)
throw new InvalidOperationException($"轴 {axis} 无法启动!当前设定速度为 0。");
// 3. 检查动作轴使能,若为 false 则自动补写 true 激活驱动器
bool isEnabled = await GetAxisEnableAsync(axis, ct);
if (!isEnabled)
{
await SetAxisEnableAsync(axis, true, ct);
await Task.Delay(100, ct); // 等待硬件继电器响应与伺服驱动就绪
}
// 4. 精准独立校验当前需要动作轴的目标定位是否越界
int currentTarget = await GetAxisTargetPositionAsync(axis, ct);
int allowedMaxLimit = maxLimit - currentHomePos;
if (currentTarget < 0 || currentTarget > allowedMaxLimit)
{
throw new ArgumentOutOfRangeException($"轴 {axis} 无法启动!当前指定目标位置 [{currentTarget}] 超过了允许的最大安全极限值 [{allowedMaxLimit}]。");
}
// 5. 校验完成,边缘触发点动启动
await TriggerCoilAsync(startAddress, ct);
}
/// <summary>
/// 三轴同时启动全开严格校验全部运行轴速度、批量检测与补正1~6号轴使能、联动校验三轴目标范围极限
/// </summary>
public async Task StartAllAxesAsync(CancellationToken ct = default)
{
// 1. 一次性读取三轴速度,严禁任何一轴速度为 0
int xSpeed = await GetAxisSpeedAsync(1, ct);
int ySpeed = await GetAxisSpeedAsync(2, ct);
int zSpeed = await GetAxisSpeedAsync(3, ct);
if (xSpeed == 0 || ySpeed == 0 || zSpeed == 0)
throw new InvalidOperationException($"无法全开启动!存在运行速度为 0 的轴。当前速度 -> X:{xSpeed}, Y:{ySpeed}, Z:{zSpeed}");
// 2. 批量读取 1 ~ 6 号轴连续的使能状态线圈,极大地优化网络性能
bool[] enableStates = await ReadCoilsAsync(_slaveAddress, ADDR_HM_AXIS1_ENABLE, 6, ct);
if (enableStates == null || enableStates.Length < 6)
throw new InvalidOperationException("从 PLC 读取 1~6 号轴使能状态失败。");
bool hasModifiedEnable = false;
ushort[] enableAddresses = { ADDR_HM_AXIS1_ENABLE, ADDR_HM_AXIS2_ENABLE, ADDR_HM_AXIS3_ENABLE, ADDR_HM_AXIS4_ENABLE, ADDR_HM_AXIS5_ENABLE, ADDR_HM_AXIS6_ENABLE };
for (int i = 0; i < 6; i++)
{
if (!enableStates[i])
{
await WriteSingleCoilAsync(_slaveAddress, enableAddresses[i], true, ct);
hasModifiedEnable = true;
}
}
// 如果执行过使能补齐补齐写入在循环外进行统一延时保证PLC时序安全
if (hasModifiedEnable)
await Task.Delay(100, ct);
// 3. 获取三轴原点及当前设定的目标指定位置
var (xHome, yHome, zHome) = await GetHomePositionAsync(ct);
int xTarget = await GetAxisTargetPositionAsync(1, ct);
int yTarget = await GetAxisTargetPositionAsync(2, ct);
int zTarget = await GetAxisTargetPositionAsync(3, ct);
// X轴安全范围联动校验
int xMaxAllowed = 50000 - xHome;
if (xTarget < 0 || xTarget > xMaxAllowed)
throw new ArgumentOutOfRangeException(nameof(xTarget), $"X轴目标位置 [{xTarget}] 越界,当前原点下最大范围 0-{xMaxAllowed}");
// Y轴安全范围联动校验
int yMaxAllowed = 50000 - yHome;
if (yTarget < 0 || yTarget > yMaxAllowed)
throw new ArgumentOutOfRangeException(nameof(yTarget), $"Y轴目标位置 [{yTarget}] 越界,当前原点下最大范围 0-{yMaxAllowed}");
// Z轴安全范围联动校验
int zMaxAllowed = 20000 - zHome;
if (zTarget < 0 || zTarget > zMaxAllowed)
throw new ArgumentOutOfRangeException(nameof(zTarget), $"Z轴目标位置 [{zTarget}] 越界,当前原点下最大范围 0-{zMaxAllowed}");
// 4. 全部联动校验通过,三轴点动同步启动
await WriteSingleCoilAsync(_slaveAddress, ADDR_M_X_START, true, ct);
await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Y_START, true, ct);
await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Z_START, true, ct);
await Task.Delay(100, ct); // 保持高电平状态以适配 PLC 扫描周期
await WriteSingleCoilAsync(_slaveAddress, ADDR_M_X_START, false, ct);
await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Y_START, false, ct);
await WriteSingleCoilAsync(_slaveAddress, ADDR_M_Z_START, false, ct);
}
#region
/// <summary>
/// 触发点动脉冲信号(置 1 后,等待 100ms 自动置 0 释放)
/// </summary>
private async Task TriggerCoilAsync(ushort address, CancellationToken ct = default)
{
await WriteSingleCoilAsync(_slaveAddress, address, true, ct);
await Task.Delay(100, ct);
await WriteSingleCoilAsync(_slaveAddress, address, false, ct);
}
/// <summary>
/// 将 32 位整型数据转换为 Modbus 的 2 个 16 位无符号整数(低字在前 CDAB 格式)
/// </summary>
private ushort[] Int32ToUshorts(int value)
{
ushort lowWord = (ushort)(value & 0xFFFF);
ushort highWord = (ushort)((value >> 16) & 0xFFFF);
return new ushort[] { lowWord, highWord };
}
/// <summary>
/// 将 Modbus 的 2 个 16 位无符号整数转换为 32 位整型(低字在前 CDAB 格式)
/// </summary>
private int UshortsToInt32(ushort[] registers)
{
uint lowWord = registers[0];
uint highWord = registers[1];
return (int)((highWord << 16) | lowWord);
}
#endregion
#region
/// <summary>
/// 读取指定轴的绝对位置(相对原点的实时位置,只读)
/// </summary>
/// <param name="axis">轴编号 (1-6)</param>
public async Task<int> GetAbsolutePositionAsync(int axis, CancellationToken ct = default)
{
ushort address = axis switch
{
1 => ADDR_ABS_AXIS1_POS,
2 => ADDR_ABS_AXIS2_POS,
3 => ADDR_ABS_AXIS3_POS,
4 => ADDR_ABS_AXIS4_POS,
5 => ADDR_ABS_AXIS5_POS,
6 => ADDR_ABS_AXIS6_POS,
_ => throw new ArgumentException("轴编号错误,仅支持 1-6", nameof(axis))
};
ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, address, 2, ct);
if (registers == null || registers.Length < 2)
throw new InvalidOperationException($"读取轴 {axis} 绝对位置失败。");
return UshortsToInt32(registers);
}
/// <summary>
/// 批量读取 1-6 轴的绝对位置(一次性读取 22 个寄存器,高效)
/// </summary>
/// <returns>返回 6 轴绝对位置元组</returns>
public async Task<(int Axis1, int Axis2, int Axis3, int Axis4, int Axis5, int Axis6)> GetAllAbsolutePositionsAsync(CancellationToken ct = default)
{
// 从 47232 开始连续读取 22 个寄存器(覆盖 47232-47253
ushort[] registers = await ReadHoldingRegistersAsync(_slaveAddress, ADDR_ABS_AXIS1_POS, 22, ct);
if (registers == null || registers.Length < 22)
throw new InvalidOperationException("批量读取 6 轴绝对位置失败,返回数据长度不足。");
// 每轴间隔 4 个寄存器2个数据 + 2个间隙提取各轴数据
int axis1 = UshortsToInt32(new ushort[] { registers[0], registers[1] });
int axis2 = UshortsToInt32(new ushort[] { registers[4], registers[5] });
int axis3 = UshortsToInt32(new ushort[] { registers[8], registers[9] });
int axis4 = UshortsToInt32(new ushort[] { registers[12], registers[13] });
int axis5 = UshortsToInt32(new ushort[] { registers[16], registers[17] });
int axis6 = UshortsToInt32(new ushort[] { registers[20], registers[21] });
return (axis1, axis2, axis3, axis4, axis5, axis6);
}
#endregion
}
}

View File

@@ -1,263 +0,0 @@
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
#region
/// <summary>
/// 电源电气/耦合模式
/// </summary>
public enum PowerCouplingMode
{
/// <summary> 纯交流模式 </summary>
AC,
/// <summary> 纯直流模式 </summary>
DC,
/// <summary> 交直流混合模式 </summary>
ACDC,
/// <summary> 直交流混合模式 </summary>
DCAC
}
/// <summary>
/// 设备操作运行角色/模式
/// </summary>
public enum DeviceOperationMode
{
/// <summary> 电压源模式(常规源) </summary>
VOLTage,
/// <summary> 电子负载模式(放电拉载) </summary>
LOAD,
/// <summary> 电流源模式 </summary>
CURRent
}
#endregion
[ACPCommand]
public class IT7800E : Tcp
{
// 八台产品共用一个,使用换行符 \n (ASCII 0x0A) 作为 SCPI 结束符[cite: 1]
private const string ScpiDelimiter = "\n";
public IT7800E(TcpConfig config) : base(config)
{
}
#region 1. IEEE 488.2
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*CLS{ScpiDelimiter}", ct); //[cite: 1]
}
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*RST{ScpiDelimiter}", ct); //[cite: 1]
}
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*STB?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
#endregion
#region 2.
/// <summary>
/// 设置电源输出源的电气模式/工作耦合模式 (AC, DC, ACDC, DCAC)[cite: 1]
/// </summary>
public virtual async Task (PowerCouplingMode , CancellationToken ct = default)
{
await SendAsync($":SOURce:FUNCtion {模式}{ScpiDelimiter}", ct); //[cite: 1]
}
/// <summary>
/// 查询电源当前的工作电气模式[cite: 1]
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":SOURce:FUNCtion?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
public virtual async Task DC输出(bool , CancellationToken ct = default)
{
string = ? "ON" : "OFF"; //[cite: 1]
await SendAsync($":OUTPut {参数}{ScpiDelimiter}", ct); //[cite: 1]
}
public virtual async Task<string> DC输出状态(CancellationToken ct = default)
{
return await WriteReadAsync($":OUTPut?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
#endregion
#region 3. (AC //DC )
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce:VOLTage {0:F2}{1}", , ScpiDelimiter); //[cite: 1]
await SendAsync(cmd, ct);
}
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce:VOLTage:DC {0:F2}{1}", , ScpiDelimiter); //[cite: 1]
await SendAsync(cmd, ct);
}
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce:FREQuency {0:F2}{1}", , ScpiDelimiter); //[cite: 1]
await SendAsync(cmd, ct);
}
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce:CURRent {0:F3}{1}", , ScpiDelimiter); //[cite: 1]
await SendAsync(cmd, ct);
}
#endregion
#region 4.
[Monitorable("交流电源电压")]
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":MEASure:VOLTage?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
[Monitorable("交流电源电流")]
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":MEASure:CURRent?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
[Monitorable("交流电源功率")]
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":MEASure:POWer?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":MEASure:POWer:APParent?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":MEASure:FREQuency?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":MEASure:POWer:PFACtor?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
#endregion
#region 5.
public virtual async Task _OCP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce:CURRent:PROTection:RMS {0:F3}{1}", , ScpiDelimiter); //[cite: 1]
await SendAsync(cmd, ct);
}
public virtual async Task _OVP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce:VOLTage:PROTection:PEAK {0:F2}{1}", , ScpiDelimiter); //[cite: 1]
await SendAsync(cmd, ct);
}
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":SYSTem:ERRor?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($":SYSTem:REMote{ScpiDelimiter}", ct); //[cite: 1]
}
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($":SYSTem:LOCal{ScpiDelimiter}", ct); //[cite: 1]
}
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($":OUTPut:PROTection:CLEar{ScpiDelimiter}", ct); //[cite: 1]
}
#endregion
#region 6.
/// <summary>
/// 清除最近的安时Ah与瓦时Wh统计数据[cite: 1]
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"SENSe:AHOur:RESet{ScpiDelimiter}", ct); //[cite: 1]
await SendAsync($"SENSe:WHOur:RESet{ScpiDelimiter}", ct); //[cite: 1]
}
/// <summary>
/// 读取当前充放电累计的安时值 (单位: Ah)[cite: 1]
/// </summary>
public virtual async Task<string> _Ah(CancellationToken ct = default)
{
return await WriteReadAsync($"FETCh:AHOur?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
/// <summary>
/// 读取当前充放电累计的瓦时值 (单位: Wh)[cite: 1]
/// </summary>
public virtual async Task<string> _Wh(CancellationToken ct = default)
{
return await WriteReadAsync($"FETCh:WHOur?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
/// <summary>
/// 读取充放电积分持续时间 (单位: 秒)[cite: 1]
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"FETCh:ENERgy:TIME?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
/// <summary>
/// 切换设备的操作模式 (VOLTage: 电源模式, LOAD: 负载模式/放电, CURRent: 电流源)[cite: 1]
/// </summary>
public virtual async Task (DeviceOperationMode , CancellationToken ct = default)
{
await SendAsync($"SYSTem:OPERation:MODE {模式}{ScpiDelimiter}", ct); //[cite: 1]
}
/// <summary>
/// 设置放电截止电压/电压下限 (单位: V用于防止电池过放)[cite: 1]
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, ":SOURce:VOLTage:LIMit:LOW {0:F2}{1}", , ScpiDelimiter); //[cite: 1]
await SendAsync(cmd, ct);
}
#endregion
}
}

View File

@@ -1,386 +0,0 @@
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
//[ACPCommand]
public class N36200 : Tcp
{
//只有一个,八台产品一起用一个
// 手册第 9 页 2.2.4 明确规定:命令结束符为换行符 (ASCII 字符 LF即 \n)
private const string ScpiDelimiter = "\n";
/// <summary>
/// 构造函数:传入 <see cref="TcpConfig"/> 一次性初始化 N36200/N36300 设备通信参数。
/// </summary>
public N36200(TcpConfig config) : base(config)
{
}
#region 3.1. IEEE 488.2
/// <summary>
/// 3.1.1. 清除标准事件状态寄存器和错误队列
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*CLS{ScpiDelimiter}", ct);
}
/// <summary>
/// 3.1.4. 读取直流电源相关信息(制造商、产品型号、系统 SN、软件版本号
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.1.7. 恢复出厂设置 (注意:设备重置保存数据大约需要 10 秒)
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*RST{ScpiDelimiter}", ct);
}
/// <summary>
/// 3.1.8. 读取状态字节寄存器(只读寄存器,读取时不会清除位)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*STB?{ScpiDelimiter}", ScpiDelimiter, ct);
}
#endregion
#region 3.2.
/// <summary>
/// 3.2.1. 设定输出电压值 (单位: V)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "SOURce:VOLTage {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.2.1. 查询输出电压设定值 (单位: V)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"SOURce:VOLTage?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.2.2. 设置输出限流值 (单位: A)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "SOURce:CURRent {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.2.2. 查询输出限流值设定值 (单位: A)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"SOURce:CURRent?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.2.3. 设置输出模拟内阻值 (单位: mΩ)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "SOURce:INTErnalres {0:F1}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.2.4. 保存当前测试参数到指定存储组 (范围: 1-10)
/// </summary>
public virtual async Task (int , CancellationToken ct = default)
{
if ( < 1 || > 10) throw new ArgumentOutOfRangeException(nameof(), "组别有效范围为 1~10");
await SendAsync($"SOURce:FUNCtion:SAVe {组别}{ScpiDelimiter}", ct);
}
/// <summary>
/// 3.2.5. 调用指定存储组的测试参数 (范围: 1-10)
/// </summary>
public virtual async Task (int , CancellationToken ct = default)
{
if ( < 1 || > 10) throw new ArgumentOutOfRangeException(nameof(), "组别有效范围为 1~10");
await SendAsync($"SOURce:FUNCtion:RECAll {组别}{ScpiDelimiter}", ct);
}
#endregion
#region 3.3.
/// <summary>
/// 3.3.1. 控制电源输出开关 (True: 开启, False: 关闭)
/// </summary>
public virtual async Task DC输出(bool , CancellationToken ct = default)
{
string = ? "ON" : "OFF";
await SendAsync($"OUTPut:ONOFF {参数}{ScpiDelimiter}", ct);
}
/// <summary>
/// 3.3.1. 查询电源输出开关状态 (返回 "ON" 或 "OFF")
/// </summary>
public virtual async Task<string> DC输出开关状态(CancellationToken ct = default)
{
return await WriteReadAsync($"OUTPut:ONOFF?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.3.2. 设定电源工作模式
/// (NORMal: 普通模式, CHARge: 电池充电, SEQuence: 序列模式, CPOWer: 恒功率模式, CARWave: 汽车测试, APG: 外部编程)
/// </summary>
public virtual async Task (string , CancellationToken ct = default)
{
await SendAsync($"OUTPut:MODE {模式}{ScpiDelimiter}", ct);
}
/// <summary>
/// 3.3.2. 查询电源当前运行工作模式
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"OUTPut:MODE?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.3.11. 设置电源输出 CV/CC 优先权 (CV 或 CC)
/// </summary>
public virtual async Task CVCC优先权(string , CancellationToken ct = default)
{
if ( != "CV" && != "CC") throw new ArgumentException("优先模式只能为 'CV' 或 'CC'");
await SendAsync($"OUTPut:PRIority {优先模式}{ScpiDelimiter}", ct);
}
/// <summary>
/// 3.3.12. 获取电源状态字(通过解析返回整数的二进制 Bit 位获取全状态环路及告警)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"OUTPut:STATe?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.3.13. 获取电源事件告警状态值 (返回整数通过位定义标识 UVP/OVP/OCP/OPP/OTP)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"OUTPut:EVENT?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.3.13. 清除当前的告警状态
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"OUTPut:EVENT 0{ScpiDelimiter}", ct);
}
/// <summary>
/// 3.3.16. 打开/关闭设备定时关机功能
/// </summary>
public virtual async Task (bool , CancellationToken ct = default)
{
string = ? "ON" : "OFF";
await SendAsync($"OUTPut:TIMing:SWITch {参数}{ScpiDelimiter}", ct);
}
/// <summary>
/// 3.3.17. 设定设备定时关机倒计时时间 (单位: s)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "OUTPut:TIMing:DWELI {0:F1}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.3.18. 控制泄放电路(Bleeder)开关状态
/// </summary>
public virtual async Task (bool , CancellationToken ct = default)
{
string = ? "ON" : "OFF";
await SendAsync($"OUTPut:DISRes {参数}{ScpiDelimiter}", ct);
}
#endregion
#region 3.4. ()
/// <summary>
/// 3.4.1. 回读通道输出端子上的实时测得电压值 (单位: V)
/// </summary>
[Monitorable("高压直流电源电压")]
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:VOLTage?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.4.2. 回读通道输出端子上的实时测得电流值 (单位: A)
/// </summary>
[Monitorable("高压直流电源电流")]
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:CURRent?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.4.3. 回读通道输出端子上的实时测得功率值 (单位: W)
/// </summary>
[Monitorable("高压直流电源功率")]
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:POWer?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.4.4. 回读电池充电模式下当前累计已充入的容量值 (单位: mAh)
/// </summary>
public virtual async Task<string> MAH(CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:MAH?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.4.5. 获取当前电源的硬件额定电压上限值 (单位: V)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:VOLTage:MAXimum?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 3.4.6. 获取当前电源的硬件额定电流上限值 (单位: A)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:CURRent:MAXimum?{ScpiDelimiter}", ScpiDelimiter, ct);
}
#endregion
#region 3.5.
/// <summary>
/// 3.5.1. 设置欠压保护门限值 (单位: V)
/// </summary>
public virtual async Task _UVP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "PROTect:LESS:VOLTage {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.5.4. 设置过压保护门限值 (单位: V)
/// </summary>
public virtual async Task _OVP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "PROTect:OVER:VOLTage {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.5.6. 设置硬件硬件过流保护硬指标参数 (单位: A)
/// </summary>
public virtual async Task _OCP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "PROTect:CURRent {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.5.8. 设置硬件过功率保护门限值 (单位: W)
/// </summary>
public virtual async Task _OPP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "PROTect:POWer {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.5.12. 设置可调节的用户软输出电压下限值 (单位: V)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "SOURce:VOLTage:LEVel:LIMit:LOW {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.5.13. 设置可调节的用户软输出电压上限值 (单位: V)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "SOURce:VOLTage:LEVel:LIMit {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.5.14. 设置可调节的用户软输出电流下限值 (单位: A)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "SOURce:CURRent:LEVel:LIMit:LOW {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.5.15. 设置可调节的用户软输出电流上限值 (单位: A)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "SOURce:CURRent:LEVel:LIMit {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
#endregion
#region 3.6. (CPOWer)
/// <summary>
/// 3.6.1. 设定恒功率工作模式下的限定电压值 (单位: V)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "CPOWer:VOLTage {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.6.2. 设定恒功率工作模式下的限定电流值 (单位: A)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "CPOWer:CURRent {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.6.3. 设定恒功率工作模式下的运行功率目标值 (单位: W)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "CPOWer:POWer {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
#endregion
}
}

View File

@@ -1,484 +0,0 @@
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.ComponentModel;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
[ACPCommand]
public class N36600 : Tcp
{
private CancellationTokenSource? _heartbeatCts;
private Task? _heartbeatTask;
private const int HeartbeatInterval = 3000; // 心跳间隔 3 秒
public bool IsActive { get; private set; } = false;
public int ReConnectionAttempts { get; private set; } = 0;
public const int MaxReconnectAttempts = 10;
// 手册第 4 页明确规定:每条命令后面都要加结束符 0x0A (\n)
private const string SCPIDelimiter = "\n";
public N36600(TcpConfig config) : base(config)
{
}
/// <summary>
/// 建立 TCP 连接,成功后自动激活心跳
/// </summary>
public new async Task<bool> ConnectAsync(CancellationToken ct = default)
{
bool isConnected = await base.ConnectAsync(ct);
if (isConnected)
{
IsActive = true;
ReConnectionAttempts = 0;
StartHeartbeat();
}
return isConnected;
}
public override void Close()
{
StopHeartbeat();
base.Close();
}
#region 线
[Browsable(false)]
public void StartHeartbeat()
{
if (_heartbeatTask != null && !_heartbeatTask.IsCompleted)
return;
_heartbeatCts?.Cancel();
_heartbeatCts?.Dispose();
_heartbeatCts = new CancellationTokenSource();
_heartbeatTask = Task.Run(() => HeartbeatLoop(_heartbeatCts.Token));
}
[Browsable(false)]
public void StopHeartbeat()
{
IsActive = false;
if (_heartbeatCts != null && !_heartbeatCts.IsCancellationRequested)
{
_heartbeatCts.Cancel();
}
_heartbeatTask = null;
}
private async Task HeartbeatLoop(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
try
{
await Task.Delay(HeartbeatInterval, ct);
if (ct.IsCancellationRequested) break;
// 使用公共查询命令发送心跳,确保通道连接正常,且不破坏远程或本地锁定状态
await SendAsync($"*IDN?{SCPIDelimiter}", ct);
IsActive = true;
ReConnectionAttempts = 0;
}
catch (Exception)
{
IsActive = false;
ReConnectionAttempts++;
if (ReConnectionAttempts > MaxReconnectAttempts)
{
StopHeartbeat();
base.Close();
return;
}
await ReconnectDeviceAsync(ct);
}
}
}
private async Task ReconnectDeviceAsync(CancellationToken ct)
{
try
{
await ConnectAsync(ct);
}
catch (Exception)
{
// 静默处理,等待下一轮心跳重试
}
}
#endregion
#region 3.1 IEEE 488.2
/// <summary>
/// 3.1.1 读取电源的相关信息(制造商, 产品标号, 产品序列号, 软件版本号)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*IDN?{SCPIDelimiter}", SCPIDelimiter, ct);
}
/// <summary>
/// 3.1.2 从指定的单位中恢复 *SAV 命令保存的设定值 (参数1~99)
/// </summary>
public virtual async Task (int , CancellationToken ct = default)
{
if ( < 1 || > 99) throw new ArgumentOutOfRangeException(nameof(), "组别有效范围为 1~99");
await SendAsync($"*RCL {组别}{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.1.3 将仪器当前系统状态保存到非易失性内存中 (参数1~99)
/// </summary>
public virtual async Task (int , CancellationToken ct = default)
{
if ( < 1 || > 99) throw new ArgumentOutOfRangeException(nameof(), "组别有效范围为 1~99");
await SendAsync($"*SAV {组别}{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.1.4 远程控制触发一次
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*TRG{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.1.5 返回状态、采集电压、采集电流 (格式: 状态码,电压值,电流值)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*ALL?{SCPIDelimiter}", SCPIDelimiter, ct);
}
#endregion
#region 3.2 APPLy
/// <summary>
/// 3.2.1 设置输出电压和输出电流值
/// </summary>
public virtual async Task (double , double , CancellationToken ct = default)
{
// 修正:去除前缀冒号,规范应用 APPL 短格式
string cmd = string.Format(CultureInfo.InvariantCulture, "APPL {0:F3},{1:F3}{2}", , , SCPIDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.2.1 查询当前设定的输出电压和电流值
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
// 修正:去除前缀冒号
return await WriteReadAsync($"APPL?{SCPIDelimiter}", SCPIDelimiter, ct);
}
#endregion
#region 3.5 MEASure
/// <summary>
/// 3.5.1 查询通道输出端子上测得的直流电流值 (A)
/// </summary>
[Monitorable("低压直流电源电流")]
public virtual async Task<string> (CancellationToken ct = default)
{
// 修正:去除前缀冒号,改用标准 MEAS:CURR?
return await WriteReadAsync($"MEAS:CURR?{SCPIDelimiter}", SCPIDelimiter, ct);
}
/// <summary>
/// 3.5.2 查询通道输出端子上测得的直流功率值 (W)
/// </summary>
[Monitorable("低压直流电源功率")]
public virtual async Task<string> (CancellationToken ct = default)
{
// 修正:去除前缀冒号,改用标准 MEAS:POW?
return await WriteReadAsync($"MEAS:POW?{SCPIDelimiter}", SCPIDelimiter, ct);
}
/// <summary>
/// 3.5.3 查询通道输出端子上测得的直流电压值 (V)
/// </summary>
[Monitorable("低压直流电源电压")]
public virtual async Task<string> (CancellationToken ct = default)
{
// 修正:去除前缀冒号,改用标准 MEAS:VOLT?
return await WriteReadAsync($"MEAS:VOLT?{SCPIDelimiter}", SCPIDelimiter, ct);
}
/// <summary>
/// 3.5.4 查询通道输出端子上测得的电压、电流和功率的组合值
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
// 修正:去除前缀冒号
return await WriteReadAsync($"MEAS:VAP?{SCPIDelimiter}", SCPIDelimiter, ct);
}
/// <summary>
/// 3.5.5 查询通道输出端子上测得的输出时间长度
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
// 修正:去除前缀冒号
return await WriteReadAsync($"MEAS:TIME:OUTP?{SCPIDelimiter}", SCPIDelimiter, ct);
}
#endregion
#region 3.6 OUTPut
/// <summary>
/// 3.6.1 设置电源输出开关
/// </summary>
public virtual async Task DC输出(bool , CancellationToken ct = default)
{
// 修正:去除前缀冒号,改用 OUTP 短格式
string = ? "ON" : "OFF";
await SendAsync($"OUTP {状态}{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.6.1 查询通道输出状态 (返回 ON 或 OFF)
/// </summary>
public virtual async Task<string> DC输出状态(CancellationToken ct = default)
{
// 修正:去除前缀冒号
return await WriteReadAsync($"OUTP?{SCPIDelimiter}", SCPIDelimiter, ct);
}
/// <summary>
/// 3.6.2 控制电源输出定时器的开关状态
/// </summary>
public virtual async Task (bool , CancellationToken ct = default)
{
// 修正:去除前缀冒号
string = ? "ON" : "OFF";
await SendAsync($"OUTP:TIME {状态}{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.6.3 设定电源输出定时器的时间 (单位: s, 范围: 0.1 ~ 999999.9)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
// 修正:去除前缀冒号
string cmd = string.Format(CultureInfo.InvariantCulture, "OUTP:TIME:DATA {0:F1}{1}", , SCPIDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.6.4 设定电源输出的模式优先权 (CV优先 或 CC优先)
/// </summary>
public virtual async Task (bool CV优先, CancellationToken ct = default)
{
// 修正:去除前缀冒号
string = CV优先 ? "CV" : "CC";
await SendAsync($"OUTP:MODE {模式}{SCPIDelimiter}", ct);
}
#endregion
#region 3.7 SOURce
/// <summary>
/// 3.7.1.1 清除输出电流保护(OCP)电路状态
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
// 修正:去除前缀冒号
await SendAsync($"CURR:PROT:CLE{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.7.1.2 使能或禁止当前输出电流保护(OCP)电路
/// </summary>
public virtual async Task 使(bool , CancellationToken ct = default)
{
// 修正:去除前缀冒号,将 STATE 改为更常用的 STAT 简写
string = ? "ON" : "OFF";
await SendAsync($"CURR:PROT:STAT {状态}{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.7.1.4 设置输出电流保护(OCP)阀值 (A)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
// 修正:去除前缀冒号。按 NGI 通用指令树,加上层级限制或者直接作用于 CURR:PROT
string cmd = string.Format(CultureInfo.InvariantCulture, "CURR:PROT {0:F3}{1}", , SCPIDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.7.1.7 设置电源的输出电流值 (A)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
// 修正:去除前缀冒号,改用标准 CURR 短格式
string cmd = string.Format(CultureInfo.InvariantCulture, "CURR {0:F3}{1}", , SCPIDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.7.2.1 清除输出电压保护(OVP)电路状态
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
// 修正:去除前缀冒号
await SendAsync($"VOLT:PROT:CLE{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.7.2.2 使能或禁止当前输出电压保护(OVP)电路
/// </summary>
public virtual async Task 使(bool , CancellationToken ct = default)
{
// 修正:去除前缀冒号
string = ? "ON" : "OFF";
await SendAsync($"VOLT:PROT:STAT {状态}{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.7.2.4 设置输出电压保护(OVP)阀值 (V)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
// 修正:去除前缀冒号
string cmd = string.Format(CultureInfo.InvariantCulture, "VOLT:PROT {0:F3}{1}", , SCPIDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.7.2.7 设置电源的输出电压值 (V)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
// 修正:去除前缀冒号,改用标准 VOLT 短格式
string cmd = string.Format(CultureInfo.InvariantCulture, "VOLT {0:F3}{1}", , SCPIDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.7.2.8 设定电压输出范围的上限电压值 (V)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
// 修正:去除前缀冒号
string cmd = string.Format(CultureInfo.InvariantCulture, "VOLT:LIM {0:F3}{1}", , SCPIDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.7.2.9 清除电压上限限制(恢复为设备物理允许的最大电压值)
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
// 发送 MAXimum 设为最大值以达到“清除限制”的效果
await SendAsync($"VOLT:LIMIT MAX{SCPIDelimiter}", ct); // 对应手册 3.7.2.8
}
/// <summary>
/// 3.7.3.1 设置输出功率值 (W)
/// </summary>
public virtual async Task (double , CancellationToken ct = default)
{
// 修正:去除前缀冒号,改用标准 POW 短格式
string cmd = string.Format(CultureInfo.InvariantCulture, "POW {0:F3}{1}", , SCPIDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 3.7.3.2 禁止或使能当前恒功率(CP)输出
/// </summary>
public virtual async Task 使(bool , CancellationToken ct = default)
{
// 修正:去除前缀冒号
string = ? "ON" : "OFF";
await SendAsync($"POW:STAT {状态}{SCPIDelimiter}", ct);
}
#endregion
#region 3.9 SYSTem
/// <summary>
/// 3.9.1 控制蜂鸣器开关
/// </summary>
public virtual async Task (bool , CancellationToken ct = default)
{
// 修正:去除前缀冒号
string = ? "ON" : "OFF";
await SendAsync($"SYST:BEEP:STAT {状态}{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.9.2 使蜂鸣器强制鸣叫一声
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
// 修正:去除前缀冒号
await SendAsync($"SYST:BEEP{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.9.4 查询仪器当前出错记录数量 (最大 18 组)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
// 修正:去除前缀冒号
return await WriteReadAsync($"SYST:ERR:COUN?{SCPIDelimiter}", SCPIDelimiter, ct);
}
/// <summary>
/// 3.9.5 读取仪器的出错信息 (成功返回 0,"No error")
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
// 修正:去除前缀冒号
return await WriteReadAsync($"SYST:ERR?{SCPIDelimiter}", SCPIDelimiter, ct);
}
/// <summary>
/// 3.9.7 设置电源为面板控制模式 (本地 Local 状态,前面板按键可用)
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
// 修正:去除前缀冒号
await SendAsync($"SYST:LOC{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.9.8 设置电源为远程控制模式 (Remote 状态)
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
// 修正:去除前缀冒号
await SendAsync($"SYST:REM{SCPIDelimiter}", ct);
}
/// <summary>
/// 3.9.9 通过通信接口设置电源为远程控制锁定模式
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
// 修正:去除前缀冒号
await SendAsync($"SYST:RWL{SCPIDelimiter}", ct);
}
#endregion
}
}

View File

@@ -1,575 +0,0 @@
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
[ACPCommand]
public class N69200 : Tcp
{
// 手册第 15 页 2.2.4 明确规定:命令结束符为换行符 (ASCII 字符 LF即 \n)
private const string ScpiDelimiter = "\n";
/// <summary>
/// 构造函数:传入 <see cref="TcpConfig"/> 一次性初始化 N69200 电子负载通信参数。
/// </summary>
public N69200(TcpConfig config) : base(config)
{
}
#region 3.1. IEEE 488.2
/// <summary>
/// 清除状态命令。清除标准事件状态寄存器和错误队列 (*CLS)
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*CLS{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询错误信息
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":SYSTem:ERRor?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
/// <summary>
/// 读取电子负载设备识别字符串 (*IDN?)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 复位命令。使电子负载恢复到出厂默认配置状态 (*RST)
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*RST{ScpiDelimiter}", ct);
}
/// <summary>
/// 读取标准状态字节寄存器 (*STB?)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*STB?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 保存当前系统参数到指定的存储单元 (1~100)
/// </summary>
public virtual async Task (int , CancellationToken ct = default)
{
if ( < 1 || > 100)
throw new ArgumentOutOfRangeException(nameof(), "存储单元位置应在 1~100 之间");
await SendAsync($"*SAV {单元}{ScpiDelimiter}", ct);
}
/// <summary>
/// 调用指定存储单元中保存的系统参数 (1~100)
/// </summary>
public virtual async Task (int , CancellationToken ct = default)
{
if ( < 1 || > 100)
throw new ArgumentOutOfRangeException(nameof(), "存储单元位置应在 1~100 之间");
await SendAsync($"*RCL {单元}{ScpiDelimiter}", ct);
}
#endregion
#region 3.2.
/// <summary>
/// 控制电子负载的输入控制开关INPut:STATe <bool>
/// </summary>
public virtual async Task DC输入(bool , CancellationToken ct = default)
{
string = ? "1" : "0";
await SendAsync($"INPut:STATe {参数}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询电子负载当前的拉载开关状态 (返回 0 或 1)
/// </summary>
public virtual async Task<string> DC输入状态(CancellationToken ct = default)
{
return await WriteReadAsync($"INPut:STATe?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 设置电子负载的基本工作模式 (INPut:FUNCtion <mode>)
/// (支持 CC, CV, CR, CP, CCD, CVD, CRD, CPD, OCP, OPP, ESR, MPP, SWEEP 等)
/// </summary>
public enum DeviceWorkMode
{
CC,
CV,
CR,
CP,
CCD,
ESR,
AUTO,
DISCHARGE,
CHARGE,
OCP,
CVD,
CRD,
MPP,
CVCC,
CRCC,
CPCC,
CVCR,
WAVE,
SWEEP,
OPP,
CPD,
SZ
}
public virtual async Task (DeviceWorkMode , CancellationToken ct = default)
{
await SendAsync($"INPut:FUNCtion {Enum.GetName(模式)}{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询电子负载当前处于何种工作模式
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"INPut:FUNCtion?{ScpiDelimiter}", ScpiDelimiter, ct);
}
#endregion
#region 3.3. (CC / CV / CP / CR )
/// <summary>
/// 设定恒电流模式(CC)大量程下的拉载电流目标值 (单位: A)
/// </summary>
public virtual async Task CC(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "STATic:CC:HIGH:LEVel {0:F4}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 查询恒电流模式大量程下设定的拉载电流值
/// </summary>
public virtual async Task<string> CC设定(CancellationToken ct = default)
{
return await WriteReadAsync($"STATic:CC:HIGH:LEVel?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 设定恒电压模式(CV)大量程下的拉载电压目标值 (单位: V)
/// </summary>
public virtual async Task CV(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "STATic:CV:HIGH:LEVel {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 查询恒电压模式大量程下设定的拉载电压值
/// </summary>
public virtual async Task<string> CV设定(CancellationToken ct = default)
{
return await WriteReadAsync($"STATic:CV:HIGH:LEVel?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 设定恒功率模式(CP)大量程下的拉载功率目标值 (单位: W)
/// </summary>
public virtual async Task CP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "STATic:CP:HIGH:LEVel {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 查询恒功率模式大量程下设定的拉载功率值
/// </summary>
public virtual async Task<string> CP设定(CancellationToken ct = default)
{
return await WriteReadAsync($"STATic:CP:HIGH:LEVel?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 设定恒电阻模式(CR)大量程下的等效拉载电阻阻值 (单位: Ω)
/// </summary>
public virtual async Task CR(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "STATic:CR:HIGH:LEVel {0:F4}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 查询恒电阻模式大量程下设定的拉载电阻值
/// </summary>
public virtual async Task<string> CR设定(CancellationToken ct = default)
{
return await WriteReadAsync($"STATic:CR:HIGH:LEVel?{ScpiDelimiter}", ScpiDelimiter, ct);
}
#endregion
#region 3.4.
/// <summary>
/// 回读电子负载输入端子上的实时测得电压值 (单位: V)
/// </summary>
[Monitorable("高压直流负载电压")]
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:VOLTage?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 回读电子负载输入端子上的实时测得电流值 (单位: A)
/// </summary>
[Monitorable("高压直流负载电流")]
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:CURRent?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 回读电子负载输入端子上的实时测得功率值 (单位: W)
/// </summary>
[Monitorable("高压直流负载功率")]
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:POWer?{ScpiDelimiter}", ScpiDelimiter, ct);
}
#endregion
#region 3.5.
/// <summary>
/// 设置电子负载的电流软保护阈值 (单位: A, 设置为 0 表示关闭)
/// </summary>
public virtual async Task _OCP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "INPut:CURRent:PROTection {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 设置电子负载的功率软保护阈值 (单位: W, 设置为 0 表示关闭)
/// </summary>
public virtual async Task _OPP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "INPut:POWer:PROTection {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 设置电子负载的电压软保护阈值 (单位: V, 设置为 0 表示关闭)
/// </summary>
public virtual async Task _OVP(double , CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "INPut:VOLTage:PROTection {0:F3}{1}", , ScpiDelimiter);
await SendAsync(cmd, ct);
}
#endregion
#region 3.6.
/// <summary>
/// 读取负载报警/事件寄存器信息 (MEASure:EVENT?)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"MEASure:EVENT?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 清除负载当前的保护触发锁定状态 (INPut:CLearPROTect)
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"INPut:CLearPROTect{ScpiDelimiter}", ct);
}
#endregion
#region 3.7. 112~124
#region (COMBination:*)
public virtual async Task _CVCC(int , CancellationToken ct = default)
=> await SendAsync($"COMBination:CVCC:RANGE {量程}{ScpiDelimiter}", ct);
public virtual async Task _CVCC(int , CancellationToken ct = default)
=> await SendAsync($"COMBination:CVCC:HIGH:RATE {速率}{ScpiDelimiter}", ct);
public virtual async Task _CVCC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CVCC:HIGH:LEVel {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task _CVCC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CVCC:CLIMit {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task _CRCC(int , CancellationToken ct = default)
=> await SendAsync($"COMBination:CRCC:RANGE {量程}{ScpiDelimiter}", ct);
public virtual async Task _CRCC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CRCC:LOW:LEVel {0:F4}{1}", , ScpiDelimiter), ct);
public virtual async Task _CRCC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CRCC:CLIMit {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task _CRCC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CRCC:LOW:SLEWRate:RAIse {0:F1}{1}", , ScpiDelimiter), ct);
public virtual async Task _CRCC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CRCC:LOW:SLEWRate:FALL {0:F1}{1}", , ScpiDelimiter), ct);
public virtual async Task _CPCC(int , CancellationToken ct = default)
=> await SendAsync($"COMBination:CPCC:RANGE {量程}{ScpiDelimiter}", ct);
public virtual async Task _CPCC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CPCC:LOW:LEVel {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task _CPCC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CPCC:CLIMit {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task _CVCR(int , CancellationToken ct = default)
=> await SendAsync($"COMBination:CVCR:RANGE {量程}{ScpiDelimiter}", ct);
public virtual async Task _CVCR(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CVCR:HIGH:LEVel {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task _CVCR(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "COMBination:CVCR:CLIMit {0:F4}{1}", , ScpiDelimiter), ct);
#endregion
#region (DYNAmic:*)
public virtual async Task _CC(int , CancellationToken ct = default)
=> await SendAsync($"DYNAmic:CC:MODe {模式}{ScpiDelimiter}", ct); // 0-连续, 1-单次, 2-A/B
public virtual async Task _CC(int , CancellationToken ct = default)
=> await SendAsync($"DYNAmic:CC:RANGE {量程}{ScpiDelimiter}", ct);
public virtual async Task _CC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CC:HIGH:LEVel:MAIN {0:F4}{1}", , ScpiDelimiter), ct);
public virtual async Task _CC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CC:HIGH:LEVel:TRANSient {0:F4}{1}", , ScpiDelimiter), ct);
public virtual async Task _CC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CC:HIGH:SLEWRate:RAIse {0:F1}{1}", , ScpiDelimiter), ct);
public virtual async Task _CC(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CC:HIGH:SLEWRate:FALL {0:F1}{1}", , ScpiDelimiter), ct);
public virtual async Task _CC(double _ms, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CC:WIDth:MAIN {0:F1}{1}", _ms, ScpiDelimiter), ct);
public virtual async Task _CC(double _ms, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CC:WIDth:TRANSient {0:F1}{1}", _ms, ScpiDelimiter), ct);
public virtual async Task _CV(int , CancellationToken ct = default)
=> await SendAsync($"DYNAmic:CV:MODe {模式}{ScpiDelimiter}", ct);
public virtual async Task _CV(int , CancellationToken ct = default)
=> await SendAsync($"DYNAmic:CV:RANGE {量程}{ScpiDelimiter}", ct);
public virtual async Task _CV(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CV:HIGH:LEVel:MAIN {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task _CV(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CV:HIGH:LEVel:TRANSient {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task _CV(double _ms, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CV:WIDth:MAIN {0:F1}{1}", _ms, ScpiDelimiter), ct);
public virtual async Task _CV(double _ms, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DYNAmic:CV:WIDth:TRANSient {0:F1}{1}", _ms, ScpiDelimiter), ct);
#endregion
#region (DISCHarge:* / CHARge:*)
public virtual async Task (double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DISCHarge:CURRent {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task (double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DISCHarge:VOLTage {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task (double _s, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DISCHarge:TIMe {0:F0}{1}", _s, ScpiDelimiter), ct);
public virtual async Task (double _Ah, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "DISCHarge:CAPacity {0:F3}{1}", _Ah, ScpiDelimiter), ct);
public virtual async Task<string> (CancellationToken ct = default)
=> await WriteReadAsync($"DISCHarge:ECHO:TIMe?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> (CancellationToken ct = default)
=> await WriteReadAsync($"DISCHarge:ECHo:CAPacity?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task (double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "CHARge:CURRent {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task (double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "CHARge:VOLTage {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task (int _s, CancellationToken ct = default)
=> await SendAsync($"CHARge:TIMe {时间_s}{ScpiDelimiter}", ct);
#endregion
#region OCP / OPP (OCP:* / OPP:*)
public virtual async Task OCP初始电流(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "OCP:BCURrent {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task OCP步进电流(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "OCP:SCURrent {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task OCP单步时间(double _s, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "OCP:Time {0:F1}{1}", _s, ScpiDelimiter), ct);
public virtual async Task OCP终止电压(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "OCP:EVOLtage {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task<string> OCP状态(CancellationToken ct = default)
=> await WriteReadAsync($"OCP:STAtus?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> OCP结果电流(CancellationToken ct = default)
=> await WriteReadAsync($"OCP:RCURrent?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task OPP初始功率(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "OPP:BPOWer {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task OPP步进功率(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "OPP:SPOWer {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task OPP单步时间(double _s, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "OPP:TIME {0:F1}{1}", _s, ScpiDelimiter), ct);
public virtual async Task OPP终止电压(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "OPP:EVOLtage {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task<string> OPP状态(CancellationToken ct = default)
=> await WriteReadAsync($"OPP:STAtus?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> OPP结果功率(CancellationToken ct = default)
=> await WriteReadAsync($"OPP:RPOWer?{ScpiDelimiter}", ScpiDelimiter, ct);
#endregion
#region SWEEP WAVE (SWEEP:* / WAVE:*)
public virtual async Task (double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "SWEEP:TCURrent {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task (double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "SWEEP:MCURrent {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task (double _Hz, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "SWEEP:SFRequency {0:F1}{1}", _Hz, ScpiDelimiter), ct);
public virtual async Task (double _Hz, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "SWEEP:EFRequency {0:F1}{1}", _Hz, ScpiDelimiter), ct);
public virtual async Task (double _ms, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "SWEEP:STPTime {0:F1}{1}", _ms, ScpiDelimiter), ct);
public virtual async Task (double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "SWEEP:DUTYcycle {0:F1}{1}", , ScpiDelimiter), ct);
public virtual async Task<string> (CancellationToken ct = default)
=> await WriteReadAsync($"SWEEP:CFRequency?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> (CancellationToken ct = default)
=> await WriteReadAsync($"SWEEP:RESult?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task (int , CancellationToken ct = default)
=> await SendAsync($"WAVE:RANGe {量程}{ScpiDelimiter}", ct);
public virtual async Task (int , CancellationToken ct = default)
=> await SendAsync($"WAVE:TYPe {类型}{ScpiDelimiter}", ct); // 0-正弦波, 1-方波, 2-三角波, 3-锯齿波, 4-自定义
public virtual async Task (double _Hz, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "WAVE:FREQuency {0:F1}{1}", _Hz, ScpiDelimiter), ct);
public virtual async Task (double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "WAVE:SETValue {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task (double _ms, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "WAVE:TIMe {0:F1}{1}", _ms, ScpiDelimiter), ct);
public virtual async Task (double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "WAVE:BVALue {0:F3}{1}", , ScpiDelimiter), ct);
#endregion
#region ESR (ESR:*)
public virtual async Task ESR带载量程(int , CancellationToken ct = default)
=> await SendAsync($"ESR:LOADRange {量程}{ScpiDelimiter}", ct);
public virtual async Task ESR大量程带载电流(double , CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "ESR:CURRenthigh {0:F3}{1}", , ScpiDelimiter), ct);
public virtual async Task ESR测量方法(int , CancellationToken ct = default)
=> await SendAsync($"ESR:MODE {方法}{ScpiDelimiter}", ct); // 0-方波平均法, 1-单脉冲法
public virtual async Task ESR采样量程(int , CancellationToken ct = default)
=> await SendAsync($"ESR:MEASurerange {量程}{ScpiDelimiter}", ct); // 0-1000mV, 1-100mV, 2-10mV
public virtual async Task<string> ESR状态(CancellationToken ct = default)
=> await WriteReadAsync($"ESR:STAtus?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> ESR结果(CancellationToken ct = default)
=> await WriteReadAsync($"ESR:RESult?{ScpiDelimiter}", ScpiDelimiter, ct);
#endregion
#region MPPT (MPP:*)
public virtual async Task MPPT步进电压(double _V, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "MPP:BVOLtage {0:F3}{1}", _V, ScpiDelimiter), ct);
public virtual async Task MPPT步进时间(double _s, CancellationToken ct = default)
=> await SendAsync(string.Format(CultureInfo.InvariantCulture, "MPP:TIME {0:F1}{1}", _s, ScpiDelimiter), ct);
public virtual async Task MPPT模式(int , CancellationToken ct = default)
=> await SendAsync($"MPP:MODE {模式}{ScpiDelimiter}", ct); // 0-扫描模式, 1-跟踪模式
public virtual async Task<string> MPPT状态(CancellationToken ct = default)
=> await WriteReadAsync($"MPP:STATus?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> MPPT最大功率(CancellationToken ct = default)
=> await WriteReadAsync($"MPP:MPOWer?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> MPPT最大功率电压(CancellationToken ct = default)
=> await WriteReadAsync($"MPP:MVOLtage?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> MPPT最大功率电流(CancellationToken ct = default)
=> await WriteReadAsync($"MPP:MCURrent?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> MPPT开路电压(CancellationToken ct = default)
=> await WriteReadAsync($"MPP:OVOLtage?{ScpiDelimiter}", ScpiDelimiter, ct);
public virtual async Task<string> MPPT短路电流(CancellationToken ct = default)
=> await WriteReadAsync($"MPP:SCURrent?{ScpiDelimiter}", ScpiDelimiter, ct);
#endregion
#endregion
}
}

View File

@@ -1,326 +0,0 @@
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
[ACPCommand]
public class SDS2000X_HD : Tcp
{
// 示波器底层 Socket 字符串命令以换行符 \n 结束
private const string ScpiDelimiter = "\n";
/// <summary>
/// 构造函数:传入 <see cref="TcpConfig"/> 一次性初始化示波器通信参数。
/// </summary>
public SDS2000X_HD(TcpConfig config) : base(config)
{
}
#region 1. IEEE 488.2
/// <summary>
/// 清除标准事件状态寄存器和错误队列
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*CLS{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询错误信息
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":SYSTem:ERRor?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
}
/// <summary>
/// 读取示波器识别字符串(制造商、型号、序列号、固件版本)
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 复位命令。使示波器恢复到默认的出厂设置
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*RST{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询先前操作是否完成。
/// </summary>
public virtual async Task<bool> _OPC(CancellationToken ct = default)
{
string res = await WriteReadAsync($"*OPC?{ScpiDelimiter}", ScpiDelimiter, ct);
return res.Trim() == "1";
}
#endregion
#region 2. (Run / Stop / Single)
/// <summary>
/// 控制示波器开始捕获波形
/// </summary>
public virtual async Task _RUN(CancellationToken ct = default)
{
await SendAsync($":TRIGger:RUN{ScpiDelimiter}", ct);
}
/// <summary>
/// 停止捕获波形
/// </summary>
public virtual async Task _STOP(CancellationToken ct = default)
{
await SendAsync($"TRIGger:STOP{ScpiDelimiter}", ct);
}
/// <summary>
/// 强制示波器进入单次触发捕获模式
/// </summary>
public virtual async Task _SINGLE(CancellationToken ct = default)
{
await SendAsync($":TRIGger:MODE SINGle{ScpiDelimiter}", ct);
}
/// <summary>
/// 触发一次波形采样
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"::TRIGger:MODE FTRIG{ScpiDelimiter}", ct);
}
/// <summary>
/// 示波器触发控制模式(符合 SDS2000X-HD 规范)。
/// </summary>
public enum TriggerMode
{
/// <summary>
/// 自动触发模式 (即使无触发信号也周期性刷屏)
/// </summary>
AUTO,
/// <summary>
/// 普通触发模式 (仅当满足触发条件时才刷新)
/// </summary>
NORM,
/// <summary>
/// 单次触发模式 (捕捉到一次满足条件的信号后立刻 STOP)
/// </summary>
SINGLE
}
/// <summary>
/// 设置触发模式 (AUTO 自动, NORM 普通, SINGLE 单次)
/// </summary>
/// <param name="mode">触发模式枚举</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (TriggerMode mode, CancellationToken ct = default)
{
// 例如发送TRMD AUTO\n、TRMD NORM\n 或 TRMD SINGLE\n
string cmd = $"TRMD {mode}{ScpiDelimiter}";
await SendAsync(cmd, ct);
}
#endregion
#region 3. Channel (C1 ~ C4)
/// <summary>
/// 开启或关闭指定的模拟通道 (符合手册 57 页规范)
/// </summary>
public virtual async Task (int channel, bool enable, CancellationToken ct = default)
{
string state = enable ? "ON" : "OFF";
await SendAsync($"C{channel}:TRAce {state}{ScpiDelimiter}", ct);
}
/// <summary>
/// 设置指定通道的垂直电压档位 (Volts/Div)
/// </summary>
public virtual async Task (int channel, double volts, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "C{0}:VDIV {1:F4}{2}", channel, volts, ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 查询指定通道当前的电压档位
/// </summary>
public virtual async Task<string> (int channel, CancellationToken ct = default)
{
return await WriteReadAsync($"C{channel}:VDIV?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 设置指定通道的垂直偏移量 (Offset)
/// </summary>
public virtual async Task (int channel, double offset, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "C{0}:OFST {1:F4}{2}", channel, offset, ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 示波器通道输入阻抗类型。
/// </summary>
public enum ImpedanceType
{
/// <summary>50Ω 阻抗</summary>
FIFty,
/// <summary>1MΩ 阻抗</summary>
ONEM
}
public virtual async Task (int channel, ImpedanceType impedance, CancellationToken ct = default)
{
// 例如发送C1:IMPedance FIFty\n 或 C1:IMPedance ONEM\n
string cmd = $"CHANnel{channel}:IMPedance {impedance}{ScpiDelimiter}";
await SendAsync(cmd, ct);
}
#endregion
#region 4. Timebase
/// <summary>
/// 设置示波器的水平时基档位 (Time/Div)
/// </summary>
public virtual async Task (double scale, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "TDIV {0:E6}{1}", scale, ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 设置示波器的触发水平延迟位置 (Horizontal Delay)
/// </summary>
public virtual async Task (double delay, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "TRDL {0:E6}{1}", delay, ScpiDelimiter);
await SendAsync(cmd, ct);
}
#endregion
#region 5. Trigger
/// <summary>
/// 设置边沿触发的电平值 (Trigger Level)
/// </summary>
public virtual async Task (double level, CancellationToken ct = default)
{
string cmd = string.Format(CultureInfo.InvariantCulture, "TRIGger:EDGE:LEVel {0:F3}{1}", level, ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 设置边沿触发的触发源 (例如: C1, C2, C3, C4, EX, LINE)
/// </summary>
public virtual async Task (string source, CancellationToken ct = default)
{
await SendAsync($"TRSE EDGE,SR,{source.ToUpper()}{ScpiDelimiter}", ct);
}
#endregion
#region 6. Measure
/// <summary>
/// 查询指定通道自动测量项的当前实时测量数值
/// </summary>
public virtual async Task<string> (int channel, string paramName, CancellationToken ct = default)
{
string query = string.Format(CultureInfo.InvariantCulture, "C{0}:PAVA? {1}{2}", channel, paramName.ToUpper(), ScpiDelimiter);
return await WriteReadAsync(query, ScpiDelimiter, ct);
}
/// <summary>
/// 查询指定通道的电压峰峰值 (Vpp)
/// </summary>
public virtual async Task<string> (int channel, CancellationToken ct = default)
{
return await (channel, "PKPK", ct);
}
/// <summary>
/// 查询指定通道的频率值 (Frequency)
/// </summary>
public virtual async Task<string> (int channel, CancellationToken ct = default)
{
return await (channel, "FREQ", ct);
}
/// <summary>
/// 查询指定通道的真均方根电压值 (Vrms)
/// </summary>
public virtual async Task<string> (int channel, CancellationToken ct = default)
{
return await (channel, "RMS", ct);
}
#endregion
#region 7.
/// 【一键获取并保存截图】
/// 自动下发 :PRINt? PNG 指令,接收示波器返回的纯 PNG 二进制流并直接保存到指定路径。
/// </summary>
/// <param name="saveFilePath">本地绝对保存路径 (例如: @"D:\Oscilloscope\Screen_01.png")</param>
/// <param name="ct">取消令牌</param>
/// <returns>返回是否获取并保存成功</returns>
public virtual async Task<bool> (string saveFilePath, CancellationToken ct = default)
{
try
{
// 1. 调用我们在基类 Tcp 中全新实现的 ReadRawAsync
// 它会在内部下发 ":PRINt? PNG\n",自动接收完整的网络字节流
byte[] pureImageBytes = await ReadAllBytesAsync($":PRINt? PNG{ScpiDelimiter}", ct);
// 2. 校验返回数据
if (pureImageBytes == null || pureImageBytes.Length < 8)
{
System.Diagnostics.Debug.WriteLine("错误:接收到的图片数据为空或长度不足。");
return false;
}
// 3. 核心校验:验证是否为标准的 PNG 文件格式 (PNG 头通常为 89 50 4E 47)
if (pureImageBytes[0] != 0x89 || pureImageBytes[1] != 'P' || pureImageBytes[2] != 'N' || pureImageBytes[3] != 'G')
{
System.Diagnostics.Debug.WriteLine("错误:接收到的二进制数据不符合标准 PNG 格式头!");
return false;
}
// 4. 如果传入的目标文件夹路径不存在,自动帮其创建
string directory = Path.GetDirectoryName(saveFilePath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 5. 使用文件流直接将 PNG 字节数据落地写入本地硬盘
using (FileStream fs = new FileStream(saveFilePath, FileMode.Create, FileAccess.Write))
{
await fs.WriteAsync(pureImageBytes, 0, pureImageBytes.Length, ct);
await fs.FlushAsync(ct); // 强制刷新,确保数据完整落地
}
System.Diagnostics.Debug.WriteLine($"成功:截图已保存至路径: {saveFilePath}");
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"崩溃:保存截图时发生未知异常: {ex.Message}");
return false;
}
}
#endregion
}
}

View File

@@ -1,259 +0,0 @@
using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
[ACPCommand]
public class SPAW7000 : Tcp
{
//只有两个,八台产品公用两两分组各用一个
// 根据通用 SCPI 与远宽指令规范,使用换行符 (ASCII 字符 LF即 \n) 作为标准结束符
private const string ScpiDelimiter = "\n";
/// <summary>
/// 构造函数:传入 <see cref="TcpConfig"/> 一次性初始化 SPAW7000 功率分析记录仪通信参数。
/// </summary>
public SPAW7000(TcpConfig config) : base(config)
{
}
#region 1. IEEE 488.2
/// <summary>
/// 清除状态命令。清除标准事件状态寄存器和错误队列
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*CLS{ScpiDelimiter}", ct);
}
/// <summary>
/// 查询错误信息 发hsl居然可以但是手册上没有而且软件上也用不了这个命令
/// </summary>
//public virtual async Task<string> 查询错误信息(CancellationToken ct = default)
//{
// string query = string.Format(":SYSTem:ERRor?", ScpiDelimiter);
// return await WriteReadAsync(query, ScpiDelimiter, ct);
//}
/// <summary>
/// 读取功率分析仪识别字符串(制造商、产品型号、系统 SN、软件版本号
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
}
/// <summary>
/// 复位命令。使功率分析仪恢复到出厂默认配置状态
/// </summary>
public virtual async Task (CancellationToken ct = default)
{
await SendAsync($"*RST{ScpiDelimiter}", ct);
}
/// <summary>
/// 读取标准状态字节寄存器
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($"*STB?{ScpiDelimiter}", ScpiDelimiter, ct);
}
#endregion
#region 2. NUMeric ()
/// <summary>
/// 查询指定通道的实时 RMS 电压值 (单位: V)
/// </summary>
public virtual async Task<string> (int channel, CancellationToken ct = default)
{
// 1. 先配置 ITEM1 为指定通道的电压有效值 (URMS)
string setItem = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:ITEM1 URMS,{0}{1}", channel, ScpiDelimiter);
await SendAsync(setItem, ct);
// 2. 再读取 ITEM1 的值
string query = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:VALue? 1{0}", ScpiDelimiter);
return await WriteReadAsync(query, ScpiDelimiter, ct);
}
/// <summary>
/// 查询指定通道的实时 RMS 电流值 (单位: A)
/// </summary>
public virtual async Task<string> (int channel, CancellationToken ct = default)
{
// 1. 配置 ITEM1 为指定通道的电流有效值 (IRMS)
string setItem = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:ITEM1 IRMS,{0}{1}", channel, ScpiDelimiter);
await SendAsync(setItem, ct);
// 2. 读取 ITEM1 的值
string query = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:VALue? 1{0}", ScpiDelimiter);
return await WriteReadAsync(query, ScpiDelimiter, ct);
}
/// <summary>
/// 查询指定通道的实时有功功率值 (单位: W)
/// </summary>
public virtual async Task<string> (int channel, CancellationToken ct = default)
{
// 1. 配置 ITEM1 为指定通道的有功功率 (P)
string setItem = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:ITEM1 P,{0}{1}", channel, ScpiDelimiter);
await SendAsync(setItem, ct);
// 2. 读取 ITEM1 的值
string query = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:VALue? 1{0}", ScpiDelimiter);
return await WriteReadAsync(query, ScpiDelimiter, ct);
}
/// <summary>
/// 查询指定通道的实时频率值 (单位: Hz)
/// </summary>
public virtual async Task<string> (int channel, CancellationToken ct = default)
{
// 1. 配置 ITEM1 为指定通道的电压频率 (FU)
string setItem = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:ITEM1 FU,{0}{1}", channel, ScpiDelimiter);
await SendAsync(setItem, ct);
// 2. 读取 ITEM1 的值
string query = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:VALue? 1{0}", ScpiDelimiter);
return await WriteReadAsync(query, ScpiDelimiter, ct);
}
/// <summary>
/// 查询指定通道的功率因数 (Power Factor)
/// </summary>
public virtual async Task<string> (int channel, CancellationToken ct = default)
{
// 1. 配置 ITEM1 为指定通道的功率因数 (LAMBda)
string setItem = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:ITEM1 LAMBda,{0}{1}", channel, ScpiDelimiter);
await SendAsync(setItem, ct);
// 2. 读取 ITEM1 的值
string query = string.Format(CultureInfo.InvariantCulture, ":NUMeric:NORMal:VALue? 1{0}", ScpiDelimiter);
return await WriteReadAsync(query, ScpiDelimiter, ct);
}
#endregion
#region 3. INPut
/// <summary>
/// SPAW7000 电压量程枚举 (单位: V)
/// </summary>
public enum VoltageRange
{
V_15 = 15,
V_30 = 30,
V_60 = 60,
V_100 = 100,
V_150 = 150,
V_300 = 300,
V_600 = 600,
V_1000 = 1000
}
/// <summary>
/// SPAW7000 电流量程枚举 (单位: A)
/// </summary>
public enum CurrentRange
{
A_1 = 1,
A_2 = 2,
A_5 = 5,
A_10 = 10,
A_20 = 20,
A_50 = 50
}
/// <summary>
/// 设置指定通道的电压量程
/// </summary>
/// <param name="channel">通道号/单元号 (1 - 7)</param>
/// <param name="range">电压量程枚举</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int channel, VoltageRange range, CancellationToken ct = default)
{
// 正确格式例如: :INPut:VOLTage:RANGe:ELEMent1 300\n
string cmd = string.Format(CultureInfo.InvariantCulture,
":INPut:VOLTage:RANGe:ELEMent{0} {1}{2}",
channel, (int)range, ScpiDelimiter);
await SendAsync(cmd, ct);
}
/// <summary>
/// 设置指定通道的电流量程
/// </summary>
/// <param name="channel">通道号/单元号 (1 - 7)</param>
/// <param name="range">电流量程枚举</param>
/// <param name="ct">取消令牌</param>
public virtual async Task (int channel, CurrentRange range, CancellationToken ct = default)
{
// 正确格式例如: :INPut:CURRent:RANGe:ELEMent1 5\n
string cmd = string.Format(CultureInfo.InvariantCulture,
":INPut:CURRent:RANGe:ELEMent{0} {1}{2}",
channel, (int)range, ScpiDelimiter);
await SendAsync(cmd, ct);
}
#endregion
#region 4. SYSTem
/// <summary>
/// 14. 查询仪器型号名称
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":SYSTem:MODel?{ScpiDelimiter}", ScpiDelimiter, ct); //
}
/// <summary>
/// 16. 查询仪器唯一序列号
/// </summary>
public virtual async Task<string> (CancellationToken ct = default)
{
return await WriteReadAsync($":SYSTem:SERial?{ScpiDelimiter}", ScpiDelimiter, ct); //
}
/// <summary>
/// 15. 设置数值数据显示的分辨率 (5位或6位)
/// </summary>
/// <param name="resolution">有效值只能为 5 或 6</param>
public virtual async Task (int resolution, CancellationToken ct = default)
{
if (resolution != 5 && resolution != 6) throw new ArgumentException("分辨率只能设置为 5 或 6 位");
await SendAsync($":SYSTem:RESolution {resolution}{ScpiDelimiter}", ct); //
}
/// <summary>
/// 13. 设置或查询屏幕 LCD 的亮度级别 (1-10)
/// </summary>
public virtual async Task (int brightness, CancellationToken ct = default)
{
if (brightness < 1 || brightness > 10) throw new ArgumentOutOfRangeException(nameof(brightness), "亮度范围必须在 1~10 之间");
await SendAsync($":SYSTem:LCD:BRIGhtness {brightness}{ScpiDelimiter}", ct); //
}
/// <summary>
/// 18. 设置或查询触摸锁的开/关状态 (锁定时防止人工误触触控屏)
/// </summary>
public virtual async Task (bool isLocked, CancellationToken ct = default)
{
string state = isLocked ? "ON" : "OFF";
await SendAsync($":SYSTem:TLOCK {state}{ScpiDelimiter}", ct); //
}
/// <summary>
/// 17. 设置或读取分析仪当前的系统内部时间
/// </summary>
/// <param name="timeStr">格式必须为 "HH:MM:SS"</param>
public virtual async Task (string timeStr, CancellationToken ct = default)
{
await SendAsync($":SYSTem:TIME \"{timeStr}\"{ScpiDelimiter}", ct); //
}
#endregion
}
}