移植程序
This commit is contained in:
7
ACP.sln
7
ACP.sln
@@ -37,8 +37,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceEditModule", "DeviceE
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZLGUSBCANFD", "ZLGUSBCANFD\ZLGUSBCANFD.csproj", "{542FE380-2344-4343-9AC6-F0C587C13B88}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchMovementModule", "BenchMovementModule\BenchMovementModule.csproj", "{31F84D0E-3634-4C70-A830-21AF412E3BBF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CANModule", "CANModule\CANModule.csproj", "{AF2533DD-599D-49D7-942B-B0C26534D15F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "加密狗", "加密狗\加密狗.csproj", "{A35CA316-7B5B-4183-8636-4ECA532B1489}"
|
||||
@@ -119,10 +117,6 @@ Global
|
||||
{542FE380-2344-4343-9AC6-F0C587C13B88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{542FE380-2344-4343-9AC6-F0C587C13B88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{542FE380-2344-4343-9AC6-F0C587C13B88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{31F84D0E-3634-4C70-A830-21AF412E3BBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{31F84D0E-3634-4C70-A830-21AF412E3BBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{31F84D0E-3634-4C70-A830-21AF412E3BBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{31F84D0E-3634-4C70-A830-21AF412E3BBF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AF2533DD-599D-49D7-942B-B0C26534D15F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AF2533DD-599D-49D7-942B-B0C26534D15F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AF2533DD-599D-49D7-942B-B0C26534D15F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -155,7 +149,6 @@ Global
|
||||
{3456C3AC-E7FF-45F8-A68F-BEED9969812C} = {1E92D601-68FC-45F6-8251-BD0F39226E5B}
|
||||
{850A5BE8-0BC1-4D6A-8351-DD812C9C4427} = {1E92D601-68FC-45F6-8251-BD0F39226E5B}
|
||||
{170AD4C1-189D-4FBE-B10D-2A4304527834} = {1E92D601-68FC-45F6-8251-BD0F39226E5B}
|
||||
{31F84D0E-3634-4C70-A830-21AF412E3BBF} = {1E92D601-68FC-45F6-8251-BD0F39226E5B}
|
||||
{AF2533DD-599D-49D7-942B-B0C26534D15F} = {1E92D601-68FC-45F6-8251-BD0F39226E5B}
|
||||
{84006890-9288-44C4-9D17-FA88F3FDECFA} = {1E92D601-68FC-45F6-8251-BD0F39226E5B}
|
||||
{8923122F-F7D3-4AE7-9E86-9E78F1296A11} = {1E92D601-68FC-45F6-8251-BD0F39226E5B}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BenchMovementModule\BenchMovementModule.csproj" />
|
||||
<ProjectReference Include="..\CANModule\CANModule.csproj" />
|
||||
<ProjectReference Include="..\Command\Command.csproj" />
|
||||
<ProjectReference Include="..\CurveModule\CurveModule.csproj" />
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
using System.Reflection;
|
||||
using BenchMovementModule.Views;
|
||||
|
||||
namespace BenchMovementModule
|
||||
{
|
||||
public class BenchMovementModule : IModule
|
||||
{
|
||||
public void OnInitialized(IContainerProvider containerProvider)
|
||||
{
|
||||
IRegionManager regionManager = containerProvider.Resolve<IRegionManager>();
|
||||
regionManager.RegisterViewWithRegion("ShellViewManager", typeof(BenchMovementView));
|
||||
}
|
||||
|
||||
public void RegisterTypes(IContainerRegistry containerRegistry)
|
||||
{
|
||||
containerRegistry.RegisterForNavigation<BenchMovementView>("BenchMovementView");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UIShare\UIShare.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,164 +0,0 @@
|
||||
using DeviceCommand.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BenchMovementModule.HardwareDrive
|
||||
{
|
||||
public abstract class GantryControlBase
|
||||
{
|
||||
protected readonly IModbusDevice _device;
|
||||
protected readonly byte _slaveAddress;
|
||||
|
||||
// 默认 PLC Modbus 映射地址
|
||||
protected const ushort ADDR_HM_X_ENABLE = 0xC100; // HM0: X轴使能
|
||||
protected const ushort ADDR_HM_Y_ENABLE = 0xC101; // HM1: Y轴使能
|
||||
protected const ushort ADDR_HM_Z_ENABLE = 0xC102; // HM2: Z轴使能
|
||||
|
||||
protected const ushort ADDR_M_X_START = 30; // M30: X轴指定位置启动
|
||||
protected const ushort ADDR_M_Y_START = 31; // M31: Y轴指定位置启动
|
||||
protected const ushort ADDR_M_Z_START = 35; // M35: Z轴指定位置启动
|
||||
|
||||
protected const ushort ADDR_M_ALL_STOP = 40; // M40: 全停
|
||||
protected const ushort ADDR_M_X_STOP = 41; // M41: X轴停止
|
||||
protected const ushort ADDR_M_Y_STOP = 42; // M42: Y轴停止
|
||||
protected const ushort ADDR_M_Z_STOP = 43; // M43: Z轴停止
|
||||
|
||||
protected const ushort ADDR_M_HOME = 100; // M100: 回原点触发
|
||||
|
||||
protected const ushort ADDR_HD_X_SPEED = 0xA166; // HD230: X轴速度 (32位)
|
||||
protected const ushort ADDR_HD_Y_SPEED = 0xA17A; // HD250: Y轴速度 (32位)
|
||||
protected const ushort ADDR_HD_Z_SPEED = 0xA170; // HD240: Z轴速度 (32位)
|
||||
|
||||
protected const ushort ADDR_HD_X_TARGET = 0xA10C; // HD140: X轴指定位置 (32位)
|
||||
protected const ushort ADDR_HD_Y_TARGET = 0xA120; // HD160: Y轴指定位置 (32位)
|
||||
protected const ushort ADDR_HD_Z_TARGET = 0xA116; // HD150: Z轴指定位置 (32位)
|
||||
|
||||
public bool IsConnected => _device?.IsConnected ?? false;
|
||||
|
||||
protected GantryControlBase(IModbusDevice device, byte slaveAddress = 1)
|
||||
{
|
||||
_device = device ?? throw new ArgumentNullException(nameof(device));
|
||||
_slaveAddress = slaveAddress;
|
||||
}
|
||||
|
||||
public async Task<bool> ConnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
return await _device.ConnectAsync(ct);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_device.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 轴使能控制
|
||||
/// </summary>
|
||||
public async Task SetAxisEnableAsync(int axis, bool enable, CancellationToken ct = default)
|
||||
{
|
||||
ushort address = axis switch
|
||||
{
|
||||
1 => ADDR_HM_X_ENABLE, // X
|
||||
2 => ADDR_HM_Y_ENABLE, // Y
|
||||
3 => ADDR_HM_Z_ENABLE, // Z
|
||||
_ => throw new ArgumentException("轴通道错误,仅支持 1(X), 2(Y), 3(Z)")
|
||||
};
|
||||
|
||||
await _device.WriteSingleCoilAsync(_slaveAddress, address, enable, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 左右移动(X轴)
|
||||
/// </summary>
|
||||
/// <param name="position">目标绝对位置(脉冲数/单位值)</param>
|
||||
/// <param name="speed">运行速度</param>
|
||||
public async Task MoveLeftRightAsync(int position, int speed, CancellationToken ct = default)
|
||||
{
|
||||
// 1. 写入速度与目标位置(32位数据,写入连续的2个保持寄存器)
|
||||
await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_X_SPEED, Int32ToUshorts(speed), ct);
|
||||
await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_X_TARGET, Int32ToUshorts(position), ct);
|
||||
|
||||
// 2. 边缘触发启动信号 M30
|
||||
await TriggerCoilAsync(ADDR_M_X_START, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上下移动(Z轴)
|
||||
/// </summary>
|
||||
/// <param name="position">目标绝对位置</param>
|
||||
/// <param name="speed">运行速度</param>
|
||||
public async Task MoveUpDownAsync(int position, int speed, CancellationToken ct = default)
|
||||
{
|
||||
// 1. 写入速度与目标位置(32位数据)
|
||||
await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Z_SPEED, Int32ToUshorts(speed), ct);
|
||||
await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Z_TARGET, Int32ToUshorts(position), ct);
|
||||
|
||||
// 2. 边缘触发启动信号 M35
|
||||
await TriggerCoilAsync(ADDR_M_Z_START, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 前后移动(Y轴 - 预留拓展)
|
||||
/// </summary>
|
||||
public async Task MoveFrontBackAsync(int position, int speed, CancellationToken ct = default)
|
||||
{
|
||||
await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Y_SPEED, Int32ToUshorts(speed), ct);
|
||||
await _device.WriteMultipleRegistersAsync(_slaveAddress, ADDR_HD_Y_TARGET, Int32ToUshorts(position), ct);
|
||||
await TriggerCoilAsync(ADDR_M_Y_START, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全局回零
|
||||
/// </summary>
|
||||
public async Task HomeAsync(CancellationToken ct = default)
|
||||
{
|
||||
await TriggerCoilAsync(ADDR_M_HOME, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 轴停止
|
||||
/// </summary>
|
||||
/// <param name="axis">1:X轴, 2:Y轴, 3:Z轴, 0:全停</param>
|
||||
public async Task StopAsync(int axis = 0, CancellationToken ct = default)
|
||||
{
|
||||
ushort address = axis switch
|
||||
{
|
||||
0 => ADDR_M_ALL_STOP,
|
||||
1 => ADDR_M_X_STOP,
|
||||
2 => ADDR_M_Y_STOP,
|
||||
3 => ADDR_M_Z_STOP,
|
||||
_ => ADDR_M_ALL_STOP
|
||||
};
|
||||
|
||||
await TriggerCoilAsync(address, ct);
|
||||
}
|
||||
|
||||
#region 内部工具方法
|
||||
|
||||
/// <summary>
|
||||
/// 触发一个点动信号(置 1 后,延时 100ms 自动置 0)
|
||||
/// </summary>
|
||||
protected async Task TriggerCoilAsync(ushort address, CancellationToken ct = default)
|
||||
{
|
||||
await _device.WriteSingleCoilAsync(_slaveAddress, address, true, ct);
|
||||
await Task.Delay(100, ct); // 给予 PLC 扫描周期足够的响应时间
|
||||
await _device.WriteSingleCoilAsync(_slaveAddress, address, false, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 32 位整型数据转换为 Modbus 的 2 个 16 位无符号整数(高低字转换)
|
||||
/// </summary>
|
||||
protected ushort[] Int32ToUshorts(int value)
|
||||
{
|
||||
// 本处采用低字在前(CDAB),如果PLC高字在前(ABCD),可将返回数组顺序颠倒
|
||||
ushort lowWord = (ushort)(value & 0xFFFF);
|
||||
ushort highWord = (ushort)((value >> 16) & 0xFFFF);
|
||||
return new ushort[] { lowWord, highWord };
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using DeviceCommand.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BenchMovementModule.HardwareDrive
|
||||
{
|
||||
public class GantryControlRtu : GantryControlBase
|
||||
{
|
||||
// 暴露出底层的 ModbusRtu 实例以便修改串口配置
|
||||
public ModbusRtu RtuDevice => (ModbusRtu)_device;
|
||||
|
||||
public GantryControlRtu(string portName, int baudRate = 9600, byte slaveAddress = 1)
|
||||
: base(new ModbusRtu(), slaveAddress)
|
||||
{
|
||||
RtuDevice.ConfigureDevice(portName, baudRate);
|
||||
}
|
||||
|
||||
public GantryControlRtu(string portName, int baudRate, int dataBits, StopBits stopBits, Parity parity, byte slaveAddress = 1)
|
||||
: base(new ModbusRtu(), slaveAddress)
|
||||
{
|
||||
RtuDevice.ConfigureDevice(portName, baudRate, dataBits, stopBits, parity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using DeviceCommand.Base;
|
||||
using Model.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BenchMovementModule.HardwareDrive
|
||||
{
|
||||
public class GantryControlTcp : GantryControlBase
|
||||
{
|
||||
// 暴露出底层的 ModbusTcp 实例以便修改网络配置
|
||||
public ModbusTcp TcpDevice => (ModbusTcp)_device;
|
||||
|
||||
public GantryControlTcp(TcpConfig config, byte slaveAddress = 1)
|
||||
: base(new ModbusTcp(config), slaveAddress)
|
||||
{
|
||||
}
|
||||
|
||||
public GantryControlTcp(string ipAddress, int port = 502, byte slaveAddress = 1)
|
||||
: base(new ModbusTcp(), slaveAddress)
|
||||
{
|
||||
TcpDevice.ConfigureDevice(ipAddress, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,522 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using DeviceCommand.Devices;
|
||||
using Logger;
|
||||
using Prism.Ioc;
|
||||
using UIShare.GlobalVariable;
|
||||
using UIShare.ViewModelBase;
|
||||
|
||||
namespace BenchMovementModule.ViewModels
|
||||
{
|
||||
public class BenchMovementViewModel : NavigateViewModelBase, IRegionMemberLifetime, IDisposable
|
||||
{
|
||||
#region 属性
|
||||
|
||||
public bool KeepAlive => true;
|
||||
|
||||
// ===== GantryControlTcp 实例(从 DeviceManager 获取)=====
|
||||
private GantryControlTcp? _gantry;
|
||||
private DeviceManager? _deviceManager;
|
||||
private readonly GlobalInfo _globalInfo;
|
||||
|
||||
// ===== 连接状态 =====
|
||||
private bool _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get => _isConnected;
|
||||
set => SetProperty(ref _isConnected, value);
|
||||
}
|
||||
|
||||
private string _connectionStatus = "未连接";
|
||||
public string ConnectionStatus
|
||||
{
|
||||
get => _connectionStatus;
|
||||
set => SetProperty(ref _connectionStatus, value);
|
||||
}
|
||||
|
||||
// ===== 6轴绝对位置显示(相对原点的实时位置,只读)=====
|
||||
private int _absPos1;
|
||||
public int AbsPos1 { get => _absPos1; set => SetProperty(ref _absPos1, value); }
|
||||
|
||||
private int _absPos2;
|
||||
public int AbsPos2 { get => _absPos2; set => SetProperty(ref _absPos2, value); }
|
||||
|
||||
private int _absPos3;
|
||||
public int AbsPos3 { get => _absPos3; set => SetProperty(ref _absPos3, value); }
|
||||
|
||||
private int _absPos4;
|
||||
public int AbsPos4 { get => _absPos4; set => SetProperty(ref _absPos4, value); }
|
||||
|
||||
private int _absPos5;
|
||||
public int AbsPos5 { get => _absPos5; set => SetProperty(ref _absPos5, value); }
|
||||
|
||||
private int _absPos6;
|
||||
public int AbsPos6 { get => _absPos6; set => SetProperty(ref _absPos6, value); }
|
||||
|
||||
// ===== 寸动目标位置 =====
|
||||
private int _targetX;
|
||||
public int TargetX { get => _targetX; set => SetProperty(ref _targetX, value); }
|
||||
|
||||
private int _targetY;
|
||||
public int TargetY { get => _targetY; set => SetProperty(ref _targetY, value); }
|
||||
|
||||
private int _targetZ;
|
||||
public int TargetZ { get => _targetZ; set => SetProperty(ref _targetZ, value); }
|
||||
|
||||
// ===== 扫描参数 =====
|
||||
private int _scanStepX = 1000;
|
||||
public int ScanStepX { get => _scanStepX; set => SetProperty(ref _scanStepX, value); }
|
||||
|
||||
private int _scanStartX;
|
||||
public int ScanStartX { get => _scanStartX; set => SetProperty(ref _scanStartX, value); }
|
||||
|
||||
private int _scanEndX = 50000;
|
||||
public int ScanEndX { get => _scanEndX; set => SetProperty(ref _scanEndX, value); }
|
||||
|
||||
private int _scanStepY = 1000;
|
||||
public int ScanStepY { get => _scanStepY; set => SetProperty(ref _scanStepY, value); }
|
||||
|
||||
private int _scanStartY;
|
||||
public int ScanStartY { get => _scanStartY; set => SetProperty(ref _scanStartY, value); }
|
||||
|
||||
private int _scanEndY = 50000;
|
||||
public int ScanEndY { get => _scanEndY; set => SetProperty(ref _scanEndY, value); }
|
||||
|
||||
private int _scanStepZ = 100;
|
||||
public int ScanStepZ { get => _scanStepZ; set => SetProperty(ref _scanStepZ, value); }
|
||||
|
||||
private int _scanStartZ;
|
||||
public int ScanStartZ { get => _scanStartZ; set => SetProperty(ref _scanStartZ, value); }
|
||||
|
||||
private int _scanEndZ = 20000;
|
||||
public int ScanEndZ { get => _scanEndZ; set => SetProperty(ref _scanEndZ, value); }
|
||||
|
||||
// ===== 速度设定(脉冲)=====
|
||||
private int _speedX = 5000;
|
||||
public int SpeedX { get => _speedX; set => SetProperty(ref _speedX, value); }
|
||||
|
||||
private int _speedY = 5000;
|
||||
public int SpeedY { get => _speedY; set => SetProperty(ref _speedY, value); }
|
||||
|
||||
private int _speedZ = 2000;
|
||||
public int SpeedZ { get => _speedZ; set => SetProperty(ref _speedZ, value); }
|
||||
|
||||
private int _homeSpeed = 3000;
|
||||
public int HomeSpeed { get => _homeSpeed; set => SetProperty(ref _homeSpeed, value); }
|
||||
|
||||
// ===== 零点设定 =====
|
||||
private int _homeX;
|
||||
public int HomeX { get => _homeX; set => SetProperty(ref _homeX, value); }
|
||||
|
||||
private int _homeY;
|
||||
public int HomeY { get => _homeY; set => SetProperty(ref _homeY, value); }
|
||||
|
||||
private int _homeZ;
|
||||
public int HomeZ { get => _homeZ; set => SetProperty(ref _homeZ, value); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
public ICommand ConnectCommand { get; }
|
||||
public ICommand DisconnectCommand { get; }
|
||||
public ICommand MoveXCommand { get; }
|
||||
public ICommand MoveYCommand { get; }
|
||||
public ICommand MoveZCommand { get; }
|
||||
public ICommand MoveAllCommand { get; }
|
||||
public ICommand GoHomeCommand { get; }
|
||||
public ICommand EmergencyStopCommand { get; }
|
||||
public ICommand StopXCommand { get; }
|
||||
public ICommand StopYCommand { get; }
|
||||
public ICommand StopZCommand { get; }
|
||||
public ICommand SetSpeedCommand { get; }
|
||||
public ICommand SetHomeCommand { get; }
|
||||
public ICommand ReadStatusCommand { get; }
|
||||
#endregion
|
||||
|
||||
#region 私有字段
|
||||
private readonly DispatcherTimer _pollTimer;
|
||||
private bool _isInitiated = false;
|
||||
#endregion
|
||||
|
||||
public BenchMovementViewModel(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_globalInfo = containerProvider.Resolve<GlobalInfo>();
|
||||
ConnectCommand = new DelegateCommand(OnConnect);
|
||||
DisconnectCommand = new DelegateCommand(OnDisconnect);
|
||||
MoveXCommand = new DelegateCommand(OnMoveX);
|
||||
MoveYCommand = new DelegateCommand(OnMoveY);
|
||||
MoveZCommand = new DelegateCommand(OnMoveZ);
|
||||
MoveAllCommand = new DelegateCommand(OnMoveAll);
|
||||
GoHomeCommand = new DelegateCommand(OnGoHome);
|
||||
EmergencyStopCommand = new DelegateCommand(OnEmergencyStop);
|
||||
StopXCommand = new DelegateCommand(OnStopX);
|
||||
StopYCommand = new DelegateCommand(OnStopY);
|
||||
StopZCommand = new DelegateCommand(OnStopZ);
|
||||
SetSpeedCommand = new DelegateCommand(OnSetSpeed);
|
||||
SetHomeCommand = new DelegateCommand(OnSetHome);
|
||||
ReadStatusCommand = new DelegateCommand(OnReadStatus);
|
||||
|
||||
// 位置轮询定时器(500ms)
|
||||
_pollTimer = new DispatcherTimer(DispatcherPriority.Background)
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(500)
|
||||
};
|
||||
_pollTimer.Tick += OnPollTick;
|
||||
}
|
||||
|
||||
#region 命令处理
|
||||
|
||||
private async void OnConnect()
|
||||
{
|
||||
if (_gantry == null) return;
|
||||
try
|
||||
{
|
||||
ConnectionStatus = "连接中...";
|
||||
bool ok = await _gantry.ConnectAsync();
|
||||
if (ok)
|
||||
{
|
||||
IsConnected = true;
|
||||
ConnectionStatus = "已连接";
|
||||
_pollTimer.Start();
|
||||
await ReadDeviceParametersAsync();
|
||||
LoggerHelper.Info("[BenchMovement] 台架连接成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectionStatus = "连接失败";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] 连接失败: {ex.Message}");
|
||||
ConnectionStatus = $"连接失败: {ex.Message}";
|
||||
}
|
||||
UpdateConnectionStatus();
|
||||
}
|
||||
|
||||
private void OnDisconnect()
|
||||
{
|
||||
if (_gantry == null) return;
|
||||
try
|
||||
{
|
||||
_pollTimer.Stop();
|
||||
_gantry.Close();
|
||||
IsConnected = false;
|
||||
ConnectionStatus = "未连接";
|
||||
LoggerHelper.Info("[BenchMovement] 台架已断开");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] 断开失败: {ex.Message}");
|
||||
}
|
||||
UpdateConnectionStatus();
|
||||
}
|
||||
|
||||
private async void OnMoveX()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetAxisTargetPositionAsync(1, TargetX);
|
||||
await _gantry.StartSingleAxisAsync(1);
|
||||
LoggerHelper.Info($"[BenchMovement] X轴移动到 {TargetX}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] X轴移动失败: {ex.Message}");
|
||||
ShowErrorMessageBox($"X轴移动失败: {ex.Message}", () => { });
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnMoveY()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetAxisTargetPositionAsync(2, TargetY);
|
||||
await _gantry.StartSingleAxisAsync(2);
|
||||
LoggerHelper.Info($"[BenchMovement] Y轴移动到 {TargetY}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] Y轴移动失败: {ex.Message}");
|
||||
ShowErrorMessageBox($"Y轴移动失败: {ex.Message}", () => { });
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnMoveZ()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetAxisTargetPositionAsync(3, TargetZ);
|
||||
await _gantry.StartSingleAxisAsync(3);
|
||||
LoggerHelper.Info($"[BenchMovement] Z轴移动到 {TargetZ}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] Z轴移动失败: {ex.Message}");
|
||||
ShowErrorMessageBox($"Z轴移动失败: {ex.Message}", () => { });
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnMoveAll()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetAxisTargetPositionAsync(1, TargetX);
|
||||
await _gantry.SetAxisTargetPositionAsync(2, TargetY);
|
||||
await _gantry.SetAxisTargetPositionAsync(3, TargetZ);
|
||||
await _gantry.StartAllAxesAsync();
|
||||
LoggerHelper.Info($"[BenchMovement] 三轴同时移动: X={TargetX}, Y={TargetY}, Z={TargetZ}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] 三轴移动失败: {ex.Message}");
|
||||
ShowErrorMessageBox($"三轴移动失败: {ex.Message}", () => { });
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnGoHome()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.HomeAsync();
|
||||
LoggerHelper.Info("[BenchMovement] 回原点已触发");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] 回原点失败: {ex.Message}");
|
||||
ShowErrorMessageBox($"回原点失败: {ex.Message}", () => { });
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnEmergencyStop()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetEStopStateAsync(true);
|
||||
LoggerHelper.Info("[BenchMovement] 急停已触发");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] 急停失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnStopX()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetStopStateAsync(1, true);
|
||||
await Task.Delay(100);
|
||||
await _gantry.SetStopStateAsync(1, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] X轴停止失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnStopY()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetStopStateAsync(2, true);
|
||||
await Task.Delay(100);
|
||||
await _gantry.SetStopStateAsync(2, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] Y轴停止失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnStopZ()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetStopStateAsync(3, true);
|
||||
await Task.Delay(100);
|
||||
await _gantry.SetStopStateAsync(3, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] Z轴停止失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnSetSpeed()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetAxisSpeedAsync(1, SpeedX);
|
||||
await _gantry.SetAxisSpeedAsync(2, SpeedY);
|
||||
await _gantry.SetAxisSpeedAsync(3, SpeedZ);
|
||||
await _gantry.SetHomePositionSpeedAsync(HomeSpeed);
|
||||
LoggerHelper.Info($"[BenchMovement] 速度设定完成: X={SpeedX}, Y={SpeedY}, Z={SpeedZ}, 回零={HomeSpeed}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] 速度设定失败: {ex.Message}");
|
||||
ShowErrorMessageBox($"速度设定失败: {ex.Message}", () => { });
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnSetHome()
|
||||
{
|
||||
if (!EnsureConnected()) return;
|
||||
try
|
||||
{
|
||||
await _gantry!.SetHomePositionAsync(HomeX, HomeY, HomeZ);
|
||||
LoggerHelper.Info($"[BenchMovement] 零点设定完成: X={HomeX}, Y={HomeY}, Z={HomeZ}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] 零点设定失败: {ex.Message}");
|
||||
ShowErrorMessageBox($"零点设定失败: {ex.Message}", () => { });
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnReadStatus()
|
||||
{
|
||||
await ReadDeviceParametersAsync();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助方法
|
||||
|
||||
private bool EnsureConnected()
|
||||
{
|
||||
if (_gantry == null || !_gantry.IsConnected)
|
||||
{
|
||||
ShowErrorMessageBox("设备未连接,请先连接台架", () => { });
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateConnectionStatus()
|
||||
{
|
||||
IsConnected = _gantry?.IsConnected ?? false;
|
||||
ConnectionStatus = IsConnected ? "已连接" : "未连接";
|
||||
}
|
||||
|
||||
private async Task ReadDeviceParametersAsync()
|
||||
{
|
||||
if (_gantry == null || !_gantry.IsConnected) return;
|
||||
try
|
||||
{
|
||||
var (x, y, z) = await _gantry.GetHomePositionAsync();
|
||||
HomeX = x; HomeY = y; HomeZ = z;
|
||||
|
||||
SpeedX = await _gantry.GetAxisSpeedAsync(1);
|
||||
SpeedY = await _gantry.GetAxisSpeedAsync(2);
|
||||
SpeedZ = await _gantry.GetAxisSpeedAsync(3);
|
||||
HomeSpeed = await _gantry.GetHomePositionSpeedAsync();
|
||||
|
||||
// 读取 6 轴绝对位置
|
||||
var positions = await _gantry.GetAllAbsolutePositionsAsync();
|
||||
AbsPos1 = positions.Axis1; AbsPos2 = positions.Axis2; AbsPos3 = positions.Axis3;
|
||||
AbsPos4 = positions.Axis4; AbsPos5 = positions.Axis5; AbsPos6 = positions.Axis6;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] 读取设备参数失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnPollTick(object? sender, EventArgs e)
|
||||
{
|
||||
if (_gantry == null || !_gantry.IsConnected) return;
|
||||
try
|
||||
{
|
||||
// 批量读取 6 轴绝对位置(一次性通信,高效)
|
||||
var pos = await _gantry.GetAllAbsolutePositionsAsync();
|
||||
AbsPos1 = pos.Axis1; AbsPos2 = pos.Axis2; AbsPos3 = pos.Axis3;
|
||||
AbsPos4 = pos.Axis4; AbsPos5 = pos.Axis5; AbsPos6 = pos.Axis6;
|
||||
}
|
||||
catch { /* 忽略轮询错误 */ }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 生命周期
|
||||
|
||||
public override void OnNavigatedTo(NavigationContext navigationContext)
|
||||
{
|
||||
base.OnNavigatedTo(navigationContext);
|
||||
if (!_isInitiated)
|
||||
{
|
||||
_isInitiated = true;
|
||||
InitGantryFromDeviceManager();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 DeviceManager.DeviceMap 中查找 GantryControlTcp 实例,
|
||||
/// 优先使用当前打开的作用域,找不到则取任意已注册作用域。
|
||||
/// </summary>
|
||||
private void InitGantryFromDeviceManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 优先使用当前打开的作用域
|
||||
IScopedProvider? scope = null;
|
||||
if (!string.IsNullOrEmpty(_globalInfo.CurrentOpeningScope)
|
||||
&& _globalInfo.ScopeDic.TryGetValue(_globalInfo.CurrentOpeningScope, out scope))
|
||||
{
|
||||
// 找到了
|
||||
}
|
||||
else
|
||||
{
|
||||
// 退而求其次,取任意可用作用域
|
||||
scope = _globalInfo.ScopeDic.Values.FirstOrDefault();
|
||||
}
|
||||
|
||||
if (scope == null)
|
||||
{
|
||||
LoggerHelper.Warn("[BenchMovement] 无可用的作用域,无法解析 DeviceManager。");
|
||||
return;
|
||||
}
|
||||
|
||||
_deviceManager = scope.Resolve<DeviceManager>();
|
||||
_gantry = _deviceManager.DeviceMap.Values.OfType<GantryControlTcp>().FirstOrDefault();
|
||||
|
||||
if (_gantry != null)
|
||||
{
|
||||
LoggerHelper.Info($"[BenchMovement] 已从 DeviceManager 获取 GantryControlTcp 实例。");
|
||||
UpdateConnectionStatus();
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggerHelper.Warn("[BenchMovement] DeviceManager 中未找到 GantryControlTcp 设备,请检查设备配置。");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Error($"[BenchMovement] 初始化 GantryControlTcp 失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pollTimer.Stop();
|
||||
// GantryControlTcp 由 DeviceManager 统一管理生命周期,此处仅停止轮询
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,394 +0,0 @@
|
||||
<UserControl x:Class="BenchMovementModule.Views.BenchMovementView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
d:DesignHeight="1080" d:DesignWidth="1920">
|
||||
|
||||
<UserControl.Resources>
|
||||
<Style TargetType="TextBlock" x:Key="HeaderStyle">
|
||||
<Setter Property="Foreground" Value="#333333"/>
|
||||
<Setter Property="FontSize" Value="18"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="Margin" Value="2,2,2,5"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TextBlock" x:Key="LabelStyle">
|
||||
<Setter Property="Foreground" Value="#555555"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="5"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TextBlock" x:Key="ValueStyle">
|
||||
<Setter Property="Foreground" Value="#0056B3"/>
|
||||
<Setter Property="FontSize" Value="26"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TextBox">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="Foreground" Value="#333333"/>
|
||||
<Setter Property="BorderBrush" Value="#CCCCCC"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="4,2"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background" Value="#F5F5F5"/>
|
||||
<Setter Property="Foreground" Value="#333333"/>
|
||||
<Setter Property="BorderBrush" Value="#B8B8B8"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="12,5"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Height" Value="34"/>
|
||||
<Setter Property="Margin" Value="0,0,0,8"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="btnBorder"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="3">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="btnBorder" Property="Background" Value="#EAEAEA"/>
|
||||
<Setter TargetName="btnBorder" Property="BorderBrush" Value="#4A90E2"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="btnBorder" Property="Background" Value="#DCDCDC"/>
|
||||
<Setter TargetName="btnBorder" Property="BorderBrush" Value="#2A6099"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button" x:Key="StopButtonStyle" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Background" Value="#FFF0F0"/>
|
||||
<Setter Property="Foreground" Value="#C00000"/>
|
||||
<Setter Property="BorderBrush" Value="#E0A0A0"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="btnBorder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" CornerRadius="3">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="btnBorder" Property="Background" Value="#FFE0E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="btnBorder" Property="Background" Value="#F0C0C0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button" x:Key="EmergencyButtonStyle" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Background" Value="#D9534F"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#D43F3A"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="btnBorder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" CornerRadius="4">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="btnBorder" Property="Background" Value="#C9302C"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="btnBorder" Property="Background" Value="#AC2925"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Button" x:Key="ConnectButtonStyle" BasedOn="{StaticResource {x:Type Button}}">
|
||||
<Setter Property="Background" Value="#5CB85C"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#4CAE4C"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="btnBorder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" CornerRadius="3">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="btnBorder" Property="Background" Value="#449D44"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="btnBorder" Property="Background" Value="#3D8B3D"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="GroupBox">
|
||||
<Setter Property="BorderBrush" Value="#D0D0D0"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Margin" Value="6"/>
|
||||
<Setter Property="Padding" Value="10"/>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Background="#F0F2F5">
|
||||
<TabControl Background="Transparent" BorderThickness="0">
|
||||
<TabControl.Resources>
|
||||
<Style TargetType="TabItem">
|
||||
<Setter Property="Background" Value="#E0E4E8"/>
|
||||
<Setter Property="Foreground" Value="#333333"/>
|
||||
<Setter Property="FontSize" Value="15"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="Padding" Value="25,6"/>
|
||||
<Setter Property="Margin" Value="2,0,2,0"/>
|
||||
</Style>
|
||||
</TabControl.Resources>
|
||||
|
||||
<!-- ======================= 1. 控制面板 ======================= -->
|
||||
<TabItem Header="控制">
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="4*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 顶部:连接状态条 -->
|
||||
<Border Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Background="White" BorderBrush="#D0D0D0" BorderThickness="1" CornerRadius="3" Padding="15,8" Margin="0,0,0,10">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Ellipse Width="14" Height="14" Margin="0,0,8,0">
|
||||
<Ellipse.Style>
|
||||
<Style TargetType="Ellipse">
|
||||
<Setter Property="Fill" Value="#999999"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Fill" Value="#5CB85C"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Ellipse.Style>
|
||||
</Ellipse>
|
||||
<TextBlock Text="{Binding ConnectionStatus}" FontSize="16" FontWeight="Bold" VerticalAlignment="Center" Margin="0,0,20,0"/>
|
||||
<Button Content="连接" Width="80" Margin="0" Style="{StaticResource ConnectButtonStyle}" Command="{Binding ConnectCommand}"/>
|
||||
<Button Content="断开" Width="80" Margin="8,0,0,0" Style="{StaticResource StopButtonStyle}" Command="{Binding DisconnectCommand}"/>
|
||||
<Button Content="刷新状态" Width="90" Margin="8,0,0,0" Command="{Binding ReadStatusCommand}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 左中:位置显示 & 寸动目标 -->
|
||||
<Grid Grid.Row="1" Grid.Column="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 6轴绝对位置 -->
|
||||
<GroupBox Grid.Column="0">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="绝对位置(只读)" Style="{StaticResource HeaderStyle}"/>
|
||||
</GroupBox.Header>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="轴1" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding AbsPos1}" Style="{StaticResource ValueStyle}"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="轴2" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding AbsPos2}" Style="{StaticResource ValueStyle}"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="轴3" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding AbsPos3}" Style="{StaticResource ValueStyle}"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="轴4" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding AbsPos4}" Style="{StaticResource ValueStyle}"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Text="轴5" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBlock Grid.Row="4" Grid.Column="1" Text="{Binding AbsPos5}" Style="{StaticResource ValueStyle}"/>
|
||||
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Text="轴6" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBlock Grid.Row="5" Grid.Column="1" Text="{Binding AbsPos6}" Style="{StaticResource ValueStyle}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 寸动目标位置 -->
|
||||
<GroupBox Grid.Column="1">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="寸动目标" Style="{StaticResource HeaderStyle}"/>
|
||||
</GroupBox.Header>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="X目标" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding TargetX}" Margin="5"/>
|
||||
<Button Grid.Row="0" Grid.Column="2" Content="移动" Width="60" Margin="5,0,5,0" Command="{Binding MoveXCommand}"/>
|
||||
<Button Grid.Row="0" Grid.Column="3" Content="停止" Width="60" Margin="0,0,5,0" Style="{StaticResource StopButtonStyle}" Command="{Binding StopXCommand}"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Y目标" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TargetY}" Margin="5"/>
|
||||
<Button Grid.Row="1" Grid.Column="2" Content="移动" Width="60" Margin="5,0,5,0" Command="{Binding MoveYCommand}"/>
|
||||
<Button Grid.Row="1" Grid.Column="3" Content="停止" Width="60" Margin="0,0,5,0" Style="{StaticResource StopButtonStyle}" Command="{Binding StopYCommand}"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="Z目标" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding TargetZ}" Margin="5"/>
|
||||
<Button Grid.Row="2" Grid.Column="2" Content="移动" Width="60" Margin="5,0,5,0" Command="{Binding MoveZCommand}"/>
|
||||
<Button Grid.Row="2" Grid.Column="3" Content="停止" Width="60" Margin="0,0,5,0" Style="{StaticResource StopButtonStyle}" Command="{Binding StopZCommand}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
<!-- 右侧:控制面板 -->
|
||||
<Grid Grid.Row="1" Grid.Column="1" Margin="6,6,0,6">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0">
|
||||
<Button Content="↩ 回原点" Command="{Binding GoHomeCommand}"/>
|
||||
<Button Content="⬆ 三轴同动" Command="{Binding MoveAllCommand}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="单轴控制" Style="{StaticResource LabelStyle}" HorizontalAlignment="Center" Margin="0,10,0,10"/>
|
||||
<Button Content="↕ X 移动" Command="{Binding MoveXCommand}"/>
|
||||
<Button Content="↔ Y 移动" Command="{Binding MoveYCommand}"/>
|
||||
<Button Content="↕ Z 移动" Command="{Binding MoveZCommand}"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Row="2" Content="❌ 急 停" Style="{StaticResource EmergencyButtonStyle}" FontWeight="Bold" FontSize="18" Height="55" Margin="0" Command="{Binding EmergencyStopCommand}"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
<!-- ======================= 2. 设置 ======================= -->
|
||||
<TabItem Header="设置">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Margin="10">
|
||||
|
||||
<!-- 移动速度设定(脉冲) -->
|
||||
<GroupBox>
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="移动速度设定" Style="{StaticResource HeaderStyle}"/>
|
||||
</GroupBox.Header>
|
||||
<StackPanel Margin="5">
|
||||
<Grid Margin="0,0,0,6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="X速度(脉冲)" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding SpeedX}"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,0,0,6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="Y速度(脉冲)" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding SpeedY}"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,0,0,6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="Z速度(脉冲)" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding SpeedZ}"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,0,0,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="回零速度(脉冲)" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding HomeSpeed}"/>
|
||||
</Grid>
|
||||
<Button Content="速度设定" Width="110" HorizontalAlignment="Left" Margin="0" Command="{Binding SetSpeedCommand}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 零点设定 -->
|
||||
<GroupBox>
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="零点设定" Style="{StaticResource HeaderStyle}"/>
|
||||
</GroupBox.Header>
|
||||
<StackPanel Margin="5">
|
||||
<Grid Margin="0,0,0,6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="X零点" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding HomeX}"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,0,0,6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="Y零点" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding HomeY}"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,0,0,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="Z零点" Style="{StaticResource LabelStyle}"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding HomeZ}"/>
|
||||
</Grid>
|
||||
<Button Content="零点设定" Width="110" HorizontalAlignment="Left" Margin="0" Command="{Binding SetHomeCommand}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BenchMovementModule.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// BenchMovementView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class BenchMovementView : UserControl
|
||||
{
|
||||
public BenchMovementView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -15,18 +15,8 @@ namespace DeviceEditModule
|
||||
containerRegistry.RegisterDialog<DialogMangerView, DialogMangerViewModel>("DialogMangerView");
|
||||
|
||||
// 设备编辑 View 注册为 Navigation(被动态解析后作为 Tab 内容嵌入 DialogMangerView)
|
||||
containerRegistry.RegisterForNavigation<IT7800EView>("IT7800EView");
|
||||
containerRegistry.RegisterForNavigation<N36200View>("N36200View");
|
||||
containerRegistry.RegisterForNavigation<N36600View>("N36600View");
|
||||
containerRegistry.RegisterForNavigation<N69200View>("N69200View");
|
||||
containerRegistry.RegisterForNavigation<SDS2000X_HDView>("SDS2000X_HDView");
|
||||
containerRegistry.RegisterForNavigation<SPAW7000View>("SPAW7000View");
|
||||
containerRegistry.Register<IT7800EViewModel>();
|
||||
containerRegistry.Register<N36200ViewModel>();
|
||||
containerRegistry.Register<N36600ViewModel>();
|
||||
containerRegistry.Register<N69200ViewModel>();
|
||||
containerRegistry.Register<SDS2000X_HDViewModel>();
|
||||
containerRegistry.Register<SPAW7000ViewModel>();
|
||||
//containerRegistry.RegisterForNavigation<IT7800EView>("IT7800EView");
|
||||
//containerRegistry.Register<SPAW7000ViewModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,310 +0,0 @@
|
||||
using DeviceCommand.Devices;
|
||||
using Prism.Commands;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows.Input;
|
||||
using UIShare.GlobalVariable;
|
||||
using UIShare.ViewModelBase;
|
||||
|
||||
namespace DeviceEditModule.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// IT7800E 交直流电源控制面板 ViewModel。
|
||||
/// <para>
|
||||
/// 注册为 Navigation View,既可由 Region 导航进入,
|
||||
/// 也可由外部直接实例化后作为 Tab 内容塞入 DialogMangerView:
|
||||
/// <code>
|
||||
/// var view = container.Resolve<IT7800EView>();
|
||||
/// (view.DataContext as IT7800EViewModel)?.Initialize("IT7800E");
|
||||
/// _eventAggregator.GetEvent<AddDialogTabEvent>().Publish(
|
||||
/// new DialogTabInfo { Title = "IT7800E", Content = view });
|
||||
/// </code>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class IT7800EViewModel : NavigateViewModelBase, IDisposable
|
||||
{
|
||||
#region 私有字段
|
||||
|
||||
private readonly DeviceManager _deviceManager;
|
||||
private IT7800E? _device;
|
||||
private CancellationTokenSource? _cts;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 设备信息属性
|
||||
|
||||
private string _deviceName = "IT7800E";
|
||||
public string DeviceName
|
||||
{
|
||||
get => _deviceName;
|
||||
set => SetProperty(ref _deviceName, value);
|
||||
}
|
||||
|
||||
private bool _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get => _isConnected;
|
||||
set => SetProperty(ref _isConnected, value);
|
||||
}
|
||||
|
||||
private bool _isBusy;
|
||||
/// <summary>正在执行设备命令时为 true,用于 UI 忙碌状态指示。</summary>
|
||||
public bool IsBusy
|
||||
{
|
||||
get => _isBusy;
|
||||
set => SetProperty(ref _isBusy, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 输入参数属性
|
||||
|
||||
private double _acVoltage = 220.0;
|
||||
/// <summary>待设置的交流电压值(V)。</summary>
|
||||
public double AcVoltage
|
||||
{
|
||||
get => _acVoltage;
|
||||
set => SetProperty(ref _acVoltage, value);
|
||||
}
|
||||
|
||||
private double _dcVoltage = 0.0;
|
||||
/// <summary>待设置的直流偏置电压值(V)。</summary>
|
||||
public double DcVoltage
|
||||
{
|
||||
get => _dcVoltage;
|
||||
set => SetProperty(ref _dcVoltage, value);
|
||||
}
|
||||
|
||||
private double _frequency = 50.0;
|
||||
/// <summary>待设置的交流频率(Hz)。</summary>
|
||||
public double Frequency
|
||||
{
|
||||
get => _frequency;
|
||||
set => SetProperty(ref _frequency, value);
|
||||
}
|
||||
|
||||
private double _currentLimit = 10.0;
|
||||
/// <summary>待设置的限流值(A)。</summary>
|
||||
public double CurrentLimit
|
||||
{
|
||||
get => _currentLimit;
|
||||
set => SetProperty(ref _currentLimit, value);
|
||||
}
|
||||
|
||||
private PowerCouplingMode _selectedMode = PowerCouplingMode.AC;
|
||||
/// <summary>待设置的电源工作模式:AC / DC / ACDC。</summary>
|
||||
public PowerCouplingMode SelectedMode
|
||||
{
|
||||
get => _selectedMode;
|
||||
set => SetProperty(ref _selectedMode, value);
|
||||
}
|
||||
|
||||
private double _ovpValue = 260.0;
|
||||
/// <summary>过压保护值(V)。</summary>
|
||||
public double OvpValue
|
||||
{
|
||||
get => _ovpValue;
|
||||
set => SetProperty(ref _ovpValue, value);
|
||||
}
|
||||
|
||||
private double _ocpValue = 15.0;
|
||||
/// <summary>过流保护值(A)。</summary>
|
||||
public double OcpValue
|
||||
{
|
||||
get => _ocpValue;
|
||||
set => SetProperty(ref _ocpValue, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 测量结果属性
|
||||
|
||||
private string _measuredVoltage = "—";
|
||||
public string MeasuredVoltage
|
||||
{
|
||||
get => _measuredVoltage;
|
||||
set => SetProperty(ref _measuredVoltage, value);
|
||||
}
|
||||
|
||||
private string _measuredCurrent = "—";
|
||||
public string MeasuredCurrent
|
||||
{
|
||||
get => _measuredCurrent;
|
||||
set => SetProperty(ref _measuredCurrent, value);
|
||||
}
|
||||
|
||||
private string _measuredPower = "—";
|
||||
public string MeasuredPower
|
||||
{
|
||||
get => _measuredPower;
|
||||
set => SetProperty(ref _measuredPower, value);
|
||||
}
|
||||
|
||||
private string _measuredFrequency = "—";
|
||||
public string MeasuredFrequency
|
||||
{
|
||||
get => _measuredFrequency;
|
||||
set => SetProperty(ref _measuredFrequency, value);
|
||||
}
|
||||
|
||||
private string _responseLog = string.Empty;
|
||||
/// <summary>命令响应日志(最新消息在顶部)。</summary>
|
||||
public string ResponseLog
|
||||
{
|
||||
get => _responseLog;
|
||||
set => SetProperty(ref _responseLog, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand QueryIdentityCommand { get; }
|
||||
public ICommand ResetDeviceCommand { get; }
|
||||
public ICommand OutputOnCommand { get; }
|
||||
public ICommand OutputOffCommand { get; }
|
||||
public ICommand SetModeCommand { get; }
|
||||
public ICommand SetAcVoltageCommand { get; }
|
||||
public ICommand SetDcVoltageCommand { get; }
|
||||
public ICommand SetFrequencyCommand { get; }
|
||||
public ICommand SetCurrentCommand { get; }
|
||||
public ICommand QueryAllMeasureCommand { get; }
|
||||
public ICommand SetRemoteModeCommand { get; }
|
||||
public ICommand SetLocalModeCommand { get; }
|
||||
public ICommand SetOvpCommand { get; }
|
||||
public ICommand SetOcpCommand { get; }
|
||||
public ICommand ClearAlarmCommand { get; }
|
||||
public ICommand ClearErrorCommand { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
public IT7800EViewModel(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_deviceManager = containerProvider.Resolve<DeviceManager>();
|
||||
|
||||
QueryIdentityCommand = new DelegateCommand(async () => await Exec(async () => AppendLog("IDN: " + await _device!.查询设备标识(Ct()))));
|
||||
ResetDeviceCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.重置设备(Ct()); AppendLog("设备已重置"); }));
|
||||
OutputOnCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置DC输出(true, Ct()); AppendLog("输出已开启"); }));
|
||||
OutputOffCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置DC输出(false, Ct()); AppendLog("输出已关闭"); }));
|
||||
SetModeCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置电源模式(SelectedMode, Ct()); AppendLog($"模式已设为 {SelectedMode}"); }));
|
||||
SetAcVoltageCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置交流电压(AcVoltage, Ct()); AppendLog($"AC电压已设为 {AcVoltage} V"); }));
|
||||
SetDcVoltageCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置直流电压(DcVoltage, Ct()); AppendLog($"DC偏置已设为 {DcVoltage} V"); }));
|
||||
SetFrequencyCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置频率(Frequency, Ct()); AppendLog($"频率已设为 {Frequency} Hz"); }));
|
||||
SetCurrentCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置电流(CurrentLimit, Ct()); AppendLog($"限流已设为 {CurrentLimit} A"); }));
|
||||
SetOvpCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过压保护_OVP(OvpValue, Ct()); AppendLog($"OVP已设为 {OvpValue} V"); }));
|
||||
SetOcpCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过流保护_OCP(OcpValue, Ct()); AppendLog($"OCP已设为 {OcpValue} A"); }));
|
||||
SetRemoteModeCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.切换远程控制模式(Ct()); AppendLog("已切换到远程控制模式"); }));
|
||||
SetLocalModeCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.切换本地控制模式(Ct()); AppendLog("已切换到本地控制模式"); }));
|
||||
ClearAlarmCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.清除保护告警(Ct()); AppendLog("保护告警已清除"); }));
|
||||
ClearErrorCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.清除错误队列和状态字节(Ct()); AppendLog("错误队列已清除"); }));
|
||||
|
||||
QueryAllMeasureCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
MeasuredVoltage = await _device!.查询实际电压(Ct());
|
||||
MeasuredCurrent = await _device!.查询实际电流(Ct());
|
||||
MeasuredPower = await _device!.查询实际功率(Ct());
|
||||
MeasuredFrequency = await _device!.查询实际频率(Ct());
|
||||
AppendLog($"测量 → 电压:{MeasuredVoltage}V 电流:{MeasuredCurrent}A 功率:{MeasuredPower}W 频率:{MeasuredFrequency}Hz");
|
||||
}));
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#region 初始化 / Navigation
|
||||
|
||||
/// <summary>
|
||||
/// 从 DeviceManager 中查找 IT7800E 设备实例。
|
||||
/// 优先按 <paramref name="deviceName"/> 查找,否则取第一个匹配类型的设备。
|
||||
/// </summary>
|
||||
public void Initialize(string? deviceName = null)
|
||||
{
|
||||
IT7800E? found = null;
|
||||
string? foundName = null;
|
||||
|
||||
if (deviceName != null &&
|
||||
_deviceManager.DeviceMap.TryGetValue(deviceName, out var d) &&
|
||||
d is IT7800E e)
|
||||
{
|
||||
found = e;
|
||||
foundName = deviceName;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var kv in _deviceManager.DeviceMap)
|
||||
{
|
||||
if (kv.Value is IT7800E it)
|
||||
{
|
||||
found = it;
|
||||
foundName = kv.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_device = found;
|
||||
DeviceName = foundName ?? "IT7800E (未找到)";
|
||||
IsConnected = _device?.IsConnected ?? false;
|
||||
|
||||
AppendLog(found != null
|
||||
? $"已关联设备 [{DeviceName}],连接状态:{(IsConnected ? "已连接" : "未连接")}"
|
||||
: "未在 DeviceManager 中找到 IT7800E 设备,请先初始化设备配置。");
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(NavigationContext context)
|
||||
{
|
||||
var name = context.Parameters.GetValue<string?>("DeviceName");
|
||||
Initialize(name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助
|
||||
|
||||
private CancellationToken Ct() => (_cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))).Token;
|
||||
|
||||
private async Task Exec(Func<Task> action)
|
||||
{
|
||||
if (_device == null)
|
||||
{
|
||||
AppendLog("错误:未关联到设备实例,请检查设备配置。");
|
||||
return;
|
||||
}
|
||||
if (IsBusy) return;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await action();
|
||||
IsConnected = _device.IsConnected;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
AppendLog("命令超时或已取消。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppendLog($"错误:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLog(string message)
|
||||
{
|
||||
var line = $"[{DateTime.Now:HH:mm:ss}] {message}";
|
||||
ResponseLog = ResponseLog.Length > 4000
|
||||
? line + "\n" + ResponseLog[..3000]
|
||||
: line + "\n" + ResponseLog;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
using DeviceCommand.Devices;
|
||||
using Prism.Commands;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows.Input;
|
||||
using UIShare.GlobalVariable;
|
||||
using UIShare.ViewModelBase;
|
||||
|
||||
namespace DeviceEditModule.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// N36200 宽范围可编程直流电源控制面板 ViewModel。
|
||||
/// <para>
|
||||
/// 注册为 Navigation View,可通过 EventAggregator 添加为 DialogMangerView 中的 Tab:
|
||||
/// <code>
|
||||
/// var view = container.Resolve<N36200View>();
|
||||
/// (view.DataContext as N36200ViewModel)?.Initialize("N36200");
|
||||
/// _eventAggregator.GetEvent<AddDialogTabEvent>().Publish(
|
||||
/// new DialogTabInfo { Title = "N36200", Content = view });
|
||||
/// </code>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class N36200ViewModel : NavigateViewModelBase, IDisposable
|
||||
{
|
||||
#region 私有字段
|
||||
|
||||
private readonly DeviceManager _deviceManager;
|
||||
private N36200? _device;
|
||||
private CancellationTokenSource? _cts;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 设备信息属性
|
||||
|
||||
private string _deviceName = "N36200";
|
||||
public string DeviceName
|
||||
{
|
||||
get => _deviceName;
|
||||
set => SetProperty(ref _deviceName, value);
|
||||
}
|
||||
|
||||
private bool _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get => _isConnected;
|
||||
set => SetProperty(ref _isConnected, value);
|
||||
}
|
||||
|
||||
private bool _isBusy;
|
||||
public bool IsBusy
|
||||
{
|
||||
get => _isBusy;
|
||||
set => SetProperty(ref _isBusy, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 输入参数属性
|
||||
|
||||
private double _voltage = 12.0;
|
||||
/// <summary>待设置的输出电压值(V)。</summary>
|
||||
public double Voltage
|
||||
{
|
||||
get => _voltage;
|
||||
set => SetProperty(ref _voltage, value);
|
||||
}
|
||||
|
||||
private double _currentLimit = 5.0;
|
||||
/// <summary>待设置的限流值(A)。</summary>
|
||||
public double CurrentLimit
|
||||
{
|
||||
get => _currentLimit;
|
||||
set => SetProperty(ref _currentLimit, value);
|
||||
}
|
||||
|
||||
private string _selectedMode = "NORMal";
|
||||
/// <summary>待设置的运行模式:NORMal / CHARge / SEQuence / CPOWer / CARWave / APG。</summary>
|
||||
public string SelectedMode
|
||||
{
|
||||
get => _selectedMode;
|
||||
set => SetProperty(ref _selectedMode, value);
|
||||
}
|
||||
|
||||
private double _ovpValue = 15.0;
|
||||
/// <summary>过压保护值(V)。</summary>
|
||||
public double OvpValue
|
||||
{
|
||||
get => _ovpValue;
|
||||
set => SetProperty(ref _ovpValue, value);
|
||||
}
|
||||
|
||||
private double _ocpValue = 6.0;
|
||||
/// <summary>过流保护值(A)。</summary>
|
||||
public double OcpValue
|
||||
{
|
||||
get => _ocpValue;
|
||||
set => SetProperty(ref _ocpValue, value);
|
||||
}
|
||||
|
||||
private double _uvpValue = 0.0;
|
||||
/// <summary>欠压保护值(V)。</summary>
|
||||
public double UvpValue
|
||||
{
|
||||
get => _uvpValue;
|
||||
set => SetProperty(ref _uvpValue, value);
|
||||
}
|
||||
|
||||
private double _oppValue = 100.0;
|
||||
/// <summary>过功率保护值(W)。</summary>
|
||||
public double OppValue
|
||||
{
|
||||
get => _oppValue;
|
||||
set => SetProperty(ref _oppValue, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 测量结果属性
|
||||
|
||||
private string _measuredVoltage = "—";
|
||||
public string MeasuredVoltage
|
||||
{
|
||||
get => _measuredVoltage;
|
||||
set => SetProperty(ref _measuredVoltage, value);
|
||||
}
|
||||
|
||||
private string _measuredCurrent = "—";
|
||||
public string MeasuredCurrent
|
||||
{
|
||||
get => _measuredCurrent;
|
||||
set => SetProperty(ref _measuredCurrent, value);
|
||||
}
|
||||
|
||||
private string _measuredPower = "—";
|
||||
public string MeasuredPower
|
||||
{
|
||||
get => _measuredPower;
|
||||
set => SetProperty(ref _measuredPower, value);
|
||||
}
|
||||
|
||||
private string _deviceStatus = "—";
|
||||
/// <summary>设备状态字(OUTPut:STATe? 查询结果)。</summary>
|
||||
public string DeviceStatus
|
||||
{
|
||||
get => _deviceStatus;
|
||||
set => SetProperty(ref _deviceStatus, value);
|
||||
}
|
||||
|
||||
private string _responseLog = string.Empty;
|
||||
/// <summary>命令响应日志(最新消息在顶部)。</summary>
|
||||
public string ResponseLog
|
||||
{
|
||||
get => _responseLog;
|
||||
set => SetProperty(ref _responseLog, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand QueryIdentityCommand { get; }
|
||||
public ICommand ResetDeviceCommand { get; }
|
||||
public ICommand OutputOnCommand { get; }
|
||||
public ICommand OutputOffCommand { get; }
|
||||
public ICommand SetVoltageCommand { get; }
|
||||
public ICommand SetCurrentCommand { get; }
|
||||
public ICommand SetModeCommand { get; }
|
||||
public ICommand QueryAllMeasureCommand { get; }
|
||||
public ICommand QueryStatusCommand { get; }
|
||||
public ICommand SetOvpCommand { get; }
|
||||
public ICommand SetOcpCommand { get; }
|
||||
public ICommand SetUvpCommand { get; }
|
||||
public ICommand SetOppCommand { get; }
|
||||
public ICommand ClearAlarmCommand { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
public N36200ViewModel(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_deviceManager = containerProvider.Resolve<DeviceManager>();
|
||||
|
||||
QueryIdentityCommand = new DelegateCommand(async () => await Exec(async () => AppendLog("IDN: " + await _device!.查询设备标识(Ct()))));
|
||||
ResetDeviceCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.重置设备(Ct()); AppendLog("设备已重置(耗时约10s)"); }));
|
||||
OutputOnCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置DC输出(true, Ct()); AppendLog("输出已开启"); }));
|
||||
OutputOffCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置DC输出(false, Ct()); AppendLog("输出已关闭"); }));
|
||||
SetVoltageCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置电压(Voltage, Ct()); AppendLog($"电压已设为 {Voltage} V"); }));
|
||||
SetCurrentCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置电流(CurrentLimit, Ct()); AppendLog($"限流已设为 {CurrentLimit} A"); }));
|
||||
SetModeCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置运行模式(SelectedMode, Ct()); AppendLog($"模式已设为 {SelectedMode}"); }));
|
||||
SetOvpCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过压保护_OVP(OvpValue, Ct()); AppendLog($"OVP已设为 {OvpValue} V"); }));
|
||||
SetOcpCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过流保护_OCP(OcpValue, Ct()); AppendLog($"OCP已设为 {OcpValue} A"); }));
|
||||
SetUvpCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过欠压保护_UVP(UvpValue, Ct()); AppendLog($"UVP已设为 {UvpValue} V"); }));
|
||||
SetOppCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过功率保护_OPP(OppValue, Ct()); AppendLog($"OPP已设为 {OppValue} W"); }));
|
||||
ClearAlarmCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.清除告警(Ct()); AppendLog("告警已清除"); }));
|
||||
|
||||
QueryStatusCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
DeviceStatus = await _device!.查询设备状态字(Ct());
|
||||
AppendLog($"状态字: {DeviceStatus}");
|
||||
}));
|
||||
|
||||
QueryAllMeasureCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
MeasuredVoltage = await _device!.查询实际电压(Ct());
|
||||
MeasuredCurrent = await _device!.查询实际电流(Ct());
|
||||
MeasuredPower = await _device!.查询实际功率(Ct());
|
||||
AppendLog($"测量 → 电压:{MeasuredVoltage}V 电流:{MeasuredCurrent}A 功率:{MeasuredPower}W");
|
||||
}));
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#region 初始化 / Navigation
|
||||
|
||||
/// <summary>
|
||||
/// 从 DeviceManager 中查找 N36200 设备实例。
|
||||
/// 优先按 <paramref name="deviceName"/> 查找,否则取第一个匹配类型的设备。
|
||||
/// </summary>
|
||||
public void Initialize(string? deviceName = null)
|
||||
{
|
||||
N36200? found = null;
|
||||
string? foundName = null;
|
||||
|
||||
if (deviceName != null &&
|
||||
_deviceManager.DeviceMap.TryGetValue(deviceName, out var d) &&
|
||||
d is N36200 n)
|
||||
{
|
||||
found = n;
|
||||
foundName = deviceName;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var kv in _deviceManager.DeviceMap)
|
||||
{
|
||||
if (kv.Value is N36200 n36)
|
||||
{
|
||||
found = n36;
|
||||
foundName = kv.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_device = found;
|
||||
DeviceName = foundName ?? "N36200 (未找到)";
|
||||
IsConnected = _device?.IsConnected ?? false;
|
||||
|
||||
AppendLog(found != null
|
||||
? $"已关联设备 [{DeviceName}],连接状态:{(IsConnected ? "已连接" : "未连接")}"
|
||||
: "未在 DeviceManager 中找到 N36200 设备,请先初始化设备配置。");
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(NavigationContext context)
|
||||
{
|
||||
var name = context.Parameters.GetValue<string?>("DeviceName");
|
||||
Initialize(name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助
|
||||
|
||||
private CancellationToken Ct() => (_cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))).Token;
|
||||
|
||||
private async Task Exec(Func<Task> action)
|
||||
{
|
||||
if (_device == null)
|
||||
{
|
||||
AppendLog("错误:未关联到设备实例,请检查设备配置。");
|
||||
return;
|
||||
}
|
||||
if (IsBusy) return;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await action();
|
||||
IsConnected = _device.IsConnected;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
AppendLog("命令超时或已取消。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppendLog($"错误:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLog(string message)
|
||||
{
|
||||
var line = $"[{DateTime.Now:HH:mm:ss}] {message}";
|
||||
ResponseLog = ResponseLog.Length > 4000
|
||||
? line + "\n" + ResponseLog[..3000]
|
||||
: line + "\n" + ResponseLog;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
using DeviceCommand.Devices;
|
||||
using Prism.Commands;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows.Input;
|
||||
using UIShare.GlobalVariable;
|
||||
using UIShare.ViewModelBase;
|
||||
|
||||
namespace DeviceEditModule.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// N36600 便携式宽范围可编程直流电源控制面板 ViewModel。
|
||||
/// </summary>
|
||||
public class N36600ViewModel : NavigateViewModelBase, IDisposable
|
||||
{
|
||||
#region 私有字段
|
||||
|
||||
private readonly DeviceManager _deviceManager;
|
||||
private N36600? _device;
|
||||
private CancellationTokenSource? _cts;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 设备信息属性
|
||||
|
||||
private string _deviceName = "N36600";
|
||||
public string DeviceName
|
||||
{
|
||||
get => _deviceName;
|
||||
set => SetProperty(ref _deviceName, value);
|
||||
}
|
||||
|
||||
private bool _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get => _isConnected;
|
||||
set => SetProperty(ref _isConnected, value);
|
||||
}
|
||||
|
||||
private bool _isBusy;
|
||||
public bool IsBusy
|
||||
{
|
||||
get => _isBusy;
|
||||
set => SetProperty(ref _isBusy, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 输入参数属性
|
||||
|
||||
private double _voltage = 12.0;
|
||||
/// <summary>待设置的输出电压值(V)。</summary>
|
||||
public double Voltage
|
||||
{
|
||||
get => _voltage;
|
||||
set => SetProperty(ref _voltage, value);
|
||||
}
|
||||
|
||||
private double _currentLimit = 5.0;
|
||||
/// <summary>待设置的输出电流值(A)。</summary>
|
||||
public double CurrentLimit
|
||||
{
|
||||
get => _currentLimit;
|
||||
set => SetProperty(ref _currentLimit, value);
|
||||
}
|
||||
|
||||
private double _power = 60.0;
|
||||
/// <summary>待设置的输出功率值(W)。</summary>
|
||||
public double Power
|
||||
{
|
||||
get => _power;
|
||||
set => SetProperty(ref _power, value);
|
||||
}
|
||||
|
||||
private double _ovpValue = 15.0;
|
||||
/// <summary>过压保护值(V)。</summary>
|
||||
public double OvpValue
|
||||
{
|
||||
get => _ovpValue;
|
||||
set => SetProperty(ref _ovpValue, value);
|
||||
}
|
||||
|
||||
private double _ocpValue = 6.0;
|
||||
/// <summary>过流保护值(A)。</summary>
|
||||
public double OcpValue
|
||||
{
|
||||
get => _ocpValue;
|
||||
set => SetProperty(ref _ocpValue, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 测量结果属性
|
||||
|
||||
private string _measuredVoltage = "—";
|
||||
public string MeasuredVoltage
|
||||
{
|
||||
get => _measuredVoltage;
|
||||
set => SetProperty(ref _measuredVoltage, value);
|
||||
}
|
||||
|
||||
private string _measuredCurrent = "—";
|
||||
public string MeasuredCurrent
|
||||
{
|
||||
get => _measuredCurrent;
|
||||
set => SetProperty(ref _measuredCurrent, value);
|
||||
}
|
||||
|
||||
private string _measuredPower = "—";
|
||||
public string MeasuredPower
|
||||
{
|
||||
get => _measuredPower;
|
||||
set => SetProperty(ref _measuredPower, value);
|
||||
}
|
||||
|
||||
private string _outputState = "—";
|
||||
/// <summary>当前 DC 输出状态(OUTPut? 查询结果)。</summary>
|
||||
public string OutputState
|
||||
{
|
||||
get => _outputState;
|
||||
set => SetProperty(ref _outputState, value);
|
||||
}
|
||||
|
||||
private string _responseLog = string.Empty;
|
||||
/// <summary>命令响应日志(最新消息在顶部)。</summary>
|
||||
public string ResponseLog
|
||||
{
|
||||
get => _responseLog;
|
||||
set => SetProperty(ref _responseLog, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand QueryIdentityCommand { get; }
|
||||
public ICommand OutputOnCommand { get; }
|
||||
public ICommand OutputOffCommand { get; }
|
||||
public ICommand SetVoltageCommand { get; }
|
||||
public ICommand SetCurrentCommand { get; }
|
||||
public ICommand SetPowerCommand { get; }
|
||||
public ICommand SetOvpCommand { get; }
|
||||
public ICommand SetOcpCommand { get; }
|
||||
public ICommand QueryAllMeasureCommand { get; }
|
||||
public ICommand QueryOutputStateCommand { get; }
|
||||
public ICommand SetRemoteModeCommand { get; }
|
||||
public ICommand SetLocalModeCommand { get; }
|
||||
public ICommand ClearVoltageProtectionCommand { get; }
|
||||
public ICommand ClearCurrentProtectionCommand { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
public N36600ViewModel(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_deviceManager = containerProvider.Resolve<DeviceManager>();
|
||||
|
||||
QueryIdentityCommand = new DelegateCommand(async () => await Exec(async () => AppendLog("IDN: " + await _device!.查询设备标识(Ct()))));
|
||||
OutputOnCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置DC输出(true, Ct()); AppendLog("输出已开启"); }));
|
||||
OutputOffCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置DC输出(false, Ct()); AppendLog("输出已关闭"); }));
|
||||
SetVoltageCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置电压(Voltage, Ct()); AppendLog($"电压已设为 {Voltage} V"); }));
|
||||
SetCurrentCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置电流(CurrentLimit, Ct()); AppendLog($"电流已设为 {CurrentLimit} A"); }));
|
||||
SetPowerCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置功率(Power, Ct()); AppendLog($"功率已设为 {Power} W"); }));
|
||||
SetOvpCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过压保护值(OvpValue, Ct()); AppendLog($"OVP已设为 {OvpValue} V"); }));
|
||||
SetOcpCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过流保护值(OcpValue, Ct()); AppendLog($"OCP已设为 {OcpValue} A"); }));
|
||||
SetRemoteModeCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.切换远程控制模式(Ct()); AppendLog("已切换到远程控制模式"); }));
|
||||
SetLocalModeCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.切换本地控制模式(Ct()); AppendLog("已切换到本地控制模式"); }));
|
||||
ClearVoltageProtectionCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.清除电压保护状态(Ct()); AppendLog("电压保护状态已清除"); }));
|
||||
ClearCurrentProtectionCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.清除电流保护状态(Ct()); AppendLog("电流保护状态已清除"); }));
|
||||
|
||||
QueryOutputStateCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
OutputState = await _device!.查询DC输出状态(Ct());
|
||||
AppendLog($"输出状态: {OutputState}");
|
||||
}));
|
||||
|
||||
QueryAllMeasureCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
MeasuredVoltage = await _device!.查询实际电压(Ct());
|
||||
MeasuredCurrent = await _device!.查询实际电流(Ct());
|
||||
MeasuredPower = await _device!.查询实际功率(Ct());
|
||||
AppendLog($"测量 → 电压:{MeasuredVoltage}V 电流:{MeasuredCurrent}A 功率:{MeasuredPower}W");
|
||||
}));
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#region 初始化 / Navigation
|
||||
|
||||
public void Initialize(string? deviceName = null)
|
||||
{
|
||||
N36600? found = null;
|
||||
string? foundName = null;
|
||||
|
||||
if (deviceName != null &&
|
||||
_deviceManager.DeviceMap.TryGetValue(deviceName, out var d) &&
|
||||
d is N36600 n)
|
||||
{
|
||||
found = n;
|
||||
foundName = deviceName;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var kv in _deviceManager.DeviceMap)
|
||||
{
|
||||
if (kv.Value is N36600 n36)
|
||||
{
|
||||
found = n36;
|
||||
foundName = kv.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_device = found;
|
||||
DeviceName = foundName ?? "N36600 (未找到)";
|
||||
IsConnected = _device?.IsConnected ?? false;
|
||||
|
||||
AppendLog(found != null
|
||||
? $"已关联设备 [{DeviceName}],连接状态:{(IsConnected ? "已连接" : "未连接")}"
|
||||
: "未在 DeviceManager 中找到 N36600 设备,请先初始化设备配置。");
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(NavigationContext context)
|
||||
{
|
||||
var name = context.Parameters.GetValue<string?>("DeviceName");
|
||||
Initialize(name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助
|
||||
|
||||
private CancellationToken Ct() => (_cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))).Token;
|
||||
|
||||
private async Task Exec(Func<Task> action)
|
||||
{
|
||||
if (_device == null)
|
||||
{
|
||||
AppendLog("错误:未关联到设备实例,请检查设备配置。");
|
||||
return;
|
||||
}
|
||||
if (IsBusy) return;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await action();
|
||||
IsConnected = _device.IsConnected;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
AppendLog("命令超时或已取消。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppendLog($"错误:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLog(string message)
|
||||
{
|
||||
var line = $"[{DateTime.Now:HH:mm:ss}] {message}";
|
||||
ResponseLog = ResponseLog.Length > 4000
|
||||
? line + "\n" + ResponseLog[..3000]
|
||||
: line + "\n" + ResponseLog;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
using DeviceCommand.Devices;
|
||||
using Prism.Commands;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows.Input;
|
||||
using UIShare.GlobalVariable;
|
||||
using UIShare.ViewModelBase;
|
||||
using static DeviceCommand.Devices.N69200;
|
||||
|
||||
namespace DeviceEditModule.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// N69200 可编程直流电子负载控制面板 ViewModel。
|
||||
/// </summary>
|
||||
public class N69200ViewModel : NavigateViewModelBase, IDisposable
|
||||
{
|
||||
#region 私有字段
|
||||
|
||||
private readonly DeviceManager _deviceManager;
|
||||
private N69200? _device;
|
||||
private CancellationTokenSource? _cts;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 设备信息属性
|
||||
|
||||
private string _deviceName = "N69200";
|
||||
public string DeviceName
|
||||
{
|
||||
get => _deviceName;
|
||||
set => SetProperty(ref _deviceName, value);
|
||||
}
|
||||
|
||||
private bool _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get => _isConnected;
|
||||
set => SetProperty(ref _isConnected, value);
|
||||
}
|
||||
|
||||
private bool _isBusy;
|
||||
public bool IsBusy
|
||||
{
|
||||
get => _isBusy;
|
||||
set => SetProperty(ref _isBusy, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 输入参数属性
|
||||
|
||||
private DeviceWorkMode _selectedMode = DeviceWorkMode.CC;
|
||||
/// <summary>工作模式:CC / CV / CP / CR。</summary>
|
||||
public DeviceWorkMode SelectedMode
|
||||
{
|
||||
get => _selectedMode;
|
||||
set => SetProperty(ref _selectedMode, value);
|
||||
}
|
||||
|
||||
private double _loadValue = 1.0;
|
||||
/// <summary>设定值(根据 SelectedMode 代表 A / V / W / Ω)。</summary>
|
||||
public double LoadValue
|
||||
{
|
||||
get => _loadValue;
|
||||
set => SetProperty(ref _loadValue, value);
|
||||
}
|
||||
|
||||
private double _ovpValue = 60.0;
|
||||
/// <summary>过压保护值(V)。</summary>
|
||||
public double OvpValue
|
||||
{
|
||||
get => _ovpValue;
|
||||
set => SetProperty(ref _ovpValue, value);
|
||||
}
|
||||
|
||||
private double _ocpValue = 10.0;
|
||||
/// <summary>过流保护值(A)。</summary>
|
||||
public double OcpValue
|
||||
{
|
||||
get => _ocpValue;
|
||||
set => SetProperty(ref _ocpValue, value);
|
||||
}
|
||||
|
||||
private double _oppValue = 200.0;
|
||||
/// <summary>过功率保护值(W)。</summary>
|
||||
public double OppValue
|
||||
{
|
||||
get => _oppValue;
|
||||
set => SetProperty(ref _oppValue, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 测量结果属性
|
||||
|
||||
private string _measuredVoltage = "—";
|
||||
public string MeasuredVoltage
|
||||
{
|
||||
get => _measuredVoltage;
|
||||
set => SetProperty(ref _measuredVoltage, value);
|
||||
}
|
||||
|
||||
private string _measuredCurrent = "—";
|
||||
public string MeasuredCurrent
|
||||
{
|
||||
get => _measuredCurrent;
|
||||
set => SetProperty(ref _measuredCurrent, value);
|
||||
}
|
||||
|
||||
private string _measuredPower = "—";
|
||||
public string MeasuredPower
|
||||
{
|
||||
get => _measuredPower;
|
||||
set => SetProperty(ref _measuredPower, value);
|
||||
}
|
||||
|
||||
private string _currentMode = "—";
|
||||
/// <summary>当前负载模式(MODE? 查询结果)。</summary>
|
||||
public string CurrentMode
|
||||
{
|
||||
get => _currentMode;
|
||||
set => SetProperty(ref _currentMode, value);
|
||||
}
|
||||
|
||||
private string _statusByte = "—";
|
||||
/// <summary>状态字节(*STB? 查询结果)。</summary>
|
||||
public string StatusByte
|
||||
{
|
||||
get => _statusByte;
|
||||
set => SetProperty(ref _statusByte, value);
|
||||
}
|
||||
|
||||
private string _responseLog = string.Empty;
|
||||
/// <summary>命令响应日志(最新消息在顶部)。</summary>
|
||||
public string ResponseLog
|
||||
{
|
||||
get => _responseLog;
|
||||
set => SetProperty(ref _responseLog, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand QueryIdentityCommand { get; }
|
||||
public ICommand ResetDeviceCommand { get; }
|
||||
public ICommand InputOnCommand { get; }
|
||||
public ICommand InputOffCommand { get; }
|
||||
public ICommand SetModeCommand { get; }
|
||||
public ICommand QueryModeCommand { get; }
|
||||
public ICommand SetLoadValueCommand { get; }
|
||||
public ICommand QueryAllMeasureCommand { get; }
|
||||
public ICommand QueryStatusCommand { get; }
|
||||
public ICommand SetOvpCommand { get; }
|
||||
public ICommand SetOcpCommand { get; }
|
||||
public ICommand SetOppCommand { get; }
|
||||
public ICommand ClearAlarmCommand { get; }
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
public N69200ViewModel(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_deviceManager = containerProvider.Resolve<DeviceManager>();
|
||||
|
||||
QueryIdentityCommand = new DelegateCommand(async () => await Exec(async () => AppendLog("IDN: " + await _device!.查询设备标识(Ct()))));
|
||||
ResetDeviceCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.重置设备(Ct()); AppendLog("设备已重置"); }));
|
||||
InputOnCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置DC输入(true, Ct()); AppendLog("输入已开启"); }));
|
||||
InputOffCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置DC输入(false, Ct()); AppendLog("输入已关闭"); }));
|
||||
SetModeCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置负载模式(SelectedMode, Ct()); AppendLog($"模式已设为 {SelectedMode}"); }));
|
||||
QueryModeCommand = new DelegateCommand(async () => await Exec(async () => { CurrentMode = await _device!.查询负载模式(Ct()); AppendLog($"当前模式: {CurrentMode}"); }));
|
||||
SetOvpCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过压保护值_OVP(OvpValue, Ct()); AppendLog($"OVP已设为 {OvpValue} V"); }));
|
||||
SetOcpCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过流保护值_OCP(OcpValue, Ct()); AppendLog($"OCP已设为 {OcpValue} A"); }));
|
||||
SetOppCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置过功率保护值_OPP(OppValue, Ct()); AppendLog($"OPP已设为 {OppValue} W"); }));
|
||||
ClearAlarmCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.清除保护告警(Ct()); AppendLog("保护告警已清除"); }));
|
||||
|
||||
|
||||
SetLoadValueCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
switch (SelectedMode)
|
||||
{
|
||||
case DeviceWorkMode.CC:
|
||||
await _device!.设置恒电流CC(LoadValue, Ct());
|
||||
AppendLog($"恒流 CC 已设为 {LoadValue} A");
|
||||
break;
|
||||
case DeviceWorkMode.CV:
|
||||
await _device!.设置恒电压CV(LoadValue, Ct());
|
||||
AppendLog($"恒压 CV 已设为 {LoadValue} V");
|
||||
break;
|
||||
case DeviceWorkMode.CP:
|
||||
await _device!.设置恒功率CP(LoadValue, Ct());
|
||||
AppendLog($"恒功率 CP 已设为 {LoadValue} W");
|
||||
break;
|
||||
case DeviceWorkMode.CR:
|
||||
await _device!.设置恒电阻CR(LoadValue, Ct());
|
||||
AppendLog($"恒电阻 CR 已设为 {LoadValue} Ω");
|
||||
break;
|
||||
default:
|
||||
AppendLog($"模式 {SelectedMode} 不支持设置设定值");
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
||||
QueryStatusCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
StatusByte = await _device!.读取状态字节(Ct());
|
||||
AppendLog($"状态字节: {StatusByte}");
|
||||
}));
|
||||
|
||||
QueryAllMeasureCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
MeasuredVoltage = await _device!.查询实际电压(Ct());
|
||||
MeasuredCurrent = await _device!.查询实际电流(Ct());
|
||||
MeasuredPower = await _device!.查询实际功率(Ct());
|
||||
AppendLog($"测量 → 电压:{MeasuredVoltage}V 电流:{MeasuredCurrent}A 功率:{MeasuredPower}W");
|
||||
}));
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#region 初始化 / Navigation
|
||||
|
||||
public void Initialize(string? deviceName = null)
|
||||
{
|
||||
N69200? found = null;
|
||||
string? foundName = null;
|
||||
|
||||
if (deviceName != null &&
|
||||
_deviceManager.DeviceMap.TryGetValue(deviceName, out var d) &&
|
||||
d is N69200 n)
|
||||
{
|
||||
found = n;
|
||||
foundName = deviceName;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var kv in _deviceManager.DeviceMap)
|
||||
{
|
||||
if (kv.Value is N69200 n69)
|
||||
{
|
||||
found = n69;
|
||||
foundName = kv.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_device = found;
|
||||
DeviceName = foundName ?? "N69200 (未找到)";
|
||||
IsConnected = _device?.IsConnected ?? false;
|
||||
|
||||
AppendLog(found != null
|
||||
? $"已关联设备 [{DeviceName}],连接状态:{(IsConnected ? "已连接" : "未连接")}"
|
||||
: "未在 DeviceManager 中找到 N69200 设备,请先初始化设备配置。");
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(NavigationContext context)
|
||||
{
|
||||
var name = context.Parameters.GetValue<string?>("DeviceName");
|
||||
Initialize(name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助
|
||||
|
||||
private CancellationToken Ct() => (_cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))).Token;
|
||||
|
||||
private async Task Exec(Func<Task> action)
|
||||
{
|
||||
if (_device == null)
|
||||
{
|
||||
AppendLog("错误:未关联到设备实例,请检查设备配置。");
|
||||
return;
|
||||
}
|
||||
if (IsBusy) return;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await action();
|
||||
IsConnected = _device.IsConnected;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
AppendLog("命令超时或已取消。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppendLog($"错误:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLog(string message)
|
||||
{
|
||||
var line = $"[{DateTime.Now:HH:mm:ss}] {message}";
|
||||
ResponseLog = ResponseLog.Length > 4000
|
||||
? line + "\n" + ResponseLog[..3000]
|
||||
: line + "\n" + ResponseLog;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,387 +0,0 @@
|
||||
using DeviceCommand.Devices;
|
||||
using Prism.Commands;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using UIShare.GlobalVariable;
|
||||
using UIShare.ViewModelBase;
|
||||
using static DeviceCommand.Devices.SDS2000X_HD;
|
||||
|
||||
namespace DeviceEditModule.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// SDS2000X_HD 数字存储示波器控制面板 ViewModel。
|
||||
/// </summary>
|
||||
public class SDS2000X_HDViewModel : NavigateViewModelBase, IDisposable
|
||||
{
|
||||
#region 私有字段
|
||||
|
||||
private readonly DeviceManager _deviceManager;
|
||||
private SDS2000X_HD? _device;
|
||||
private CancellationTokenSource? _cts;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 设备信息属性
|
||||
|
||||
private string _deviceName = "SDS2000X_HD";
|
||||
public string DeviceName
|
||||
{
|
||||
get => _deviceName;
|
||||
set => SetProperty(ref _deviceName, value);
|
||||
}
|
||||
|
||||
private bool _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get => _isConnected;
|
||||
set => SetProperty(ref _isConnected, value);
|
||||
}
|
||||
|
||||
private bool _isBusy;
|
||||
public bool IsBusy
|
||||
{
|
||||
get => _isBusy;
|
||||
set => SetProperty(ref _isBusy, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 输入参数属性
|
||||
|
||||
private int _channel = 1;
|
||||
/// <summary>当前操作通道(1~4)。</summary>
|
||||
public int Channel
|
||||
{
|
||||
get => _channel;
|
||||
set => SetProperty(ref _channel, value);
|
||||
}
|
||||
|
||||
private double _voltsPerDiv = 1.0;
|
||||
/// <summary>垂直电压档位(V/div)。</summary>
|
||||
public double VoltsPerDiv
|
||||
{
|
||||
get => _voltsPerDiv;
|
||||
set => SetProperty(ref _voltsPerDiv, value);
|
||||
}
|
||||
|
||||
private double _offset = 0.0;
|
||||
/// <summary>垂直偏移(V)。</summary>
|
||||
public double Offset
|
||||
{
|
||||
get => _offset;
|
||||
set => SetProperty(ref _offset, value);
|
||||
}
|
||||
|
||||
private bool _is50Ohm;
|
||||
/// <summary>是否使用 50Ω 输入阻抗,false 为 1MΩ。</summary>
|
||||
public bool Is50Ohm
|
||||
{
|
||||
get => _is50Ohm;
|
||||
set => SetProperty(ref _is50Ohm, value);
|
||||
}
|
||||
|
||||
private double _timeBase = 0.001;
|
||||
/// <summary>水平时基档位(s/div)。</summary>
|
||||
public double TimeBase
|
||||
{
|
||||
get => _timeBase;
|
||||
set => SetProperty(ref _timeBase, value);
|
||||
}
|
||||
|
||||
private double _triggerLevel = 0.0;
|
||||
/// <summary>触发电平(V)。</summary>
|
||||
public double TriggerLevel
|
||||
{
|
||||
get => _triggerLevel;
|
||||
set => SetProperty(ref _triggerLevel, value);
|
||||
}
|
||||
|
||||
private string _triggerSource = "C1";
|
||||
/// <summary>触发源(C1/C2/C3/C4/EX/LINE)。</summary>
|
||||
public string TriggerSource
|
||||
{
|
||||
get => _triggerSource;
|
||||
set => SetProperty(ref _triggerSource, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 测量结果属性
|
||||
|
||||
private string _measuredVpp = "—";
|
||||
public string MeasuredVpp
|
||||
{
|
||||
get => _measuredVpp;
|
||||
set => SetProperty(ref _measuredVpp, value);
|
||||
}
|
||||
|
||||
private string _measuredFrequency = "—";
|
||||
public string MeasuredFrequency
|
||||
{
|
||||
get => _measuredFrequency;
|
||||
set => SetProperty(ref _measuredFrequency, value);
|
||||
}
|
||||
|
||||
private string _measuredRms = "—";
|
||||
public string MeasuredRms
|
||||
{
|
||||
get => _measuredRms;
|
||||
set => SetProperty(ref _measuredRms, value);
|
||||
}
|
||||
|
||||
private string _responseLog = string.Empty;
|
||||
/// <summary>命令响应日志(最新消息在顶部)。</summary>
|
||||
public string ResponseLog
|
||||
{
|
||||
get => _responseLog;
|
||||
set => SetProperty(ref _responseLog, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand QueryIdentityCommand { get; }
|
||||
public ICommand ResetDeviceCommand { get; }
|
||||
public ICommand RunCommand { get; }
|
||||
public ICommand StopCommand { get; }
|
||||
public ICommand SingleCommand { get; }
|
||||
public ICommand ForceTriggerCommand { get; }
|
||||
public ICommand SetChannelOnCommand { get; }
|
||||
public ICommand SetChannelOffCommand { get; }
|
||||
public ICommand SetVoltsDivCommand { get; }
|
||||
public ICommand SetOffsetCommand { get; }
|
||||
|
||||
// 🛠️ 补全:设置阻抗的 Command
|
||||
public ICommand SetImpedance50Command { get; }
|
||||
public ICommand SetImpedance1MCommand { get; }
|
||||
|
||||
public ICommand SetTimeBaseCommand { get; }
|
||||
public ICommand SetTriggerLevelCommand { get; }
|
||||
public ICommand SetTriggerSourceCommand { get; }
|
||||
public ICommand QueryMeasurementsCommand { get; }
|
||||
public ICommand QueryVppCommand { get; }
|
||||
public ICommand QueryFrequencyCommand { get; }
|
||||
public ICommand QueryRmsCommand { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
public SDS2000X_HDViewModel(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_deviceManager = containerProvider.Resolve<DeviceManager>();
|
||||
|
||||
QueryIdentityCommand = new DelegateCommand(async () => await Exec(async () => AppendLog("IDN: " + await _device!.查询设备标识(Ct()))));
|
||||
ResetDeviceCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.重置设备(Ct()); AppendLog("设备已重置"); }));
|
||||
RunCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.启动捕获_RUN(Ct()); AppendLog("已开始捕获"); }));
|
||||
StopCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.停止捕获_STOP(Ct()); AppendLog("已停止捕获"); }));
|
||||
SingleCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.单次触发_SINGLE(Ct()); AppendLog("已触发单次捕获"); }));
|
||||
ForceTriggerCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.强制触发(Ct()); AppendLog("已强制触发"); }));
|
||||
SetChannelOnCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置通道开关(Channel, true, Ct()); AppendLog($"通道 {Channel} 已开启"); }));
|
||||
SetChannelOffCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置通道开关(Channel, false, Ct()); AppendLog($"通道 {Channel} 已关闭"); }));
|
||||
SetVoltsDivCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置通道电压档位(Channel, VoltsPerDiv, Ct()); AppendLog($"C{Channel} 电压档位已设为 {VoltsPerDiv} V/div"); }));
|
||||
SetOffsetCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置通道垂直偏移(Channel, Offset, Ct()); AppendLog($"C{Channel} 垂直偏移已设为 {Offset} V"); }));
|
||||
|
||||
// 🛠️ 绑定:设置 50Ω 和 1MΩ 阻抗控制
|
||||
SetImpedance50Command = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
await _device!.设置通道阻抗(Channel, ImpedanceType.FIFty, Ct());
|
||||
Is50Ohm = true;
|
||||
AppendLog($"C{Channel} 输入阻抗已设为 50Ω");
|
||||
}));
|
||||
|
||||
SetImpedance1MCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
await _device!.设置通道阻抗(Channel, ImpedanceType.ONEM, Ct());
|
||||
Is50Ohm = false;
|
||||
AppendLog($"C{Channel} 输入阻抗已设为 1MΩ");
|
||||
}));
|
||||
|
||||
SetTimeBaseCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置水平时基(TimeBase, Ct()); AppendLog($"水平时基已设为 {TimeBase} s/div"); }));
|
||||
SetTriggerLevelCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置触发电平(TriggerLevel, Ct()); AppendLog($"触发电平已设为 {TriggerLevel} V"); }));
|
||||
SetTriggerSourceCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置触发源(TriggerSource, Ct()); AppendLog($"触发源已设为 {TriggerSource}"); }));
|
||||
|
||||
QueryMeasurementsCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
// 1. 保留设备原生吐出的完整原始字符串
|
||||
string rawVpp = await _device!.查询实际电压峰峰值(Channel, Ct());
|
||||
string rawFreq = await _device!.查询实际频率(Channel, Ct());
|
||||
string rawRms = await _device!.查询实际电压均方根(Channel, Ct());
|
||||
|
||||
// 2. 清洗数据并将科学计数法转为常规小数后赋值给 UI 属性
|
||||
MeasuredVpp = ParseMeasurement(rawVpp);
|
||||
MeasuredFrequency = ParseMeasurement(rawFreq);
|
||||
MeasuredRms = ParseMeasurement(rawRms);
|
||||
|
||||
// 3. 在日志中同时体现设备原始报文与解析呈现值,极方便联调
|
||||
AppendLog($"C{Channel} 测量原始数据 → Vpp:{rawVpp.Trim()} Freq:{rawFreq.Trim()} RMS:{rawRms.Trim()}");
|
||||
AppendLog($"C{Channel} 界面呈现数值 → Vpp:{MeasuredVpp}V Freq:{MeasuredFrequency}Hz RMS:{MeasuredRms}V");
|
||||
}));
|
||||
|
||||
QueryVppCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
string raw = await _device!.查询实际电压峰峰值(Channel, Ct());
|
||||
MeasuredVpp = ParseMeasurement(raw);
|
||||
AppendLog($"C{Channel} Vpp: {MeasuredVpp} (Raw: {raw.Trim()})");
|
||||
}));
|
||||
|
||||
QueryFrequencyCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
string raw = await _device!.查询实际频率(Channel, Ct());
|
||||
MeasuredFrequency = ParseMeasurement(raw);
|
||||
AppendLog($"C{Channel} Freq: {MeasuredFrequency} (Raw: {raw.Trim()})");
|
||||
}));
|
||||
|
||||
QueryRmsCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
string raw = await _device!.查询实际电压均方根(Channel, Ct());
|
||||
MeasuredRms = ParseMeasurement(raw);
|
||||
AppendLog($"C{Channel} RMS: {MeasuredRms} (Raw: {raw.Trim()})");
|
||||
}));
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#region 初始化 / Navigation
|
||||
|
||||
public void Initialize(string? deviceName = null)
|
||||
{
|
||||
SDS2000X_HD? found = null;
|
||||
string? foundName = null;
|
||||
|
||||
if (deviceName != null &&
|
||||
_deviceManager.DeviceMap.TryGetValue(deviceName, out var d) &&
|
||||
d is SDS2000X_HD s)
|
||||
{
|
||||
found = s;
|
||||
foundName = deviceName;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var kv in _deviceManager.DeviceMap)
|
||||
{
|
||||
if (kv.Value is SDS2000X_HD sds)
|
||||
{
|
||||
found = sds;
|
||||
foundName = kv.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_device = found;
|
||||
DeviceName = foundName ?? "SDS2000X_HD (未找到)";
|
||||
IsConnected = _device?.IsConnected ?? false;
|
||||
|
||||
AppendLog(found != null
|
||||
? $"已关联设备 [{DeviceName}],连接状态:{(IsConnected ? "已连接" : "未连接")}"
|
||||
: "未在 DeviceManager 中找到 SDS2000X_HD 设备,请先初始化设备配置。");
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(NavigationContext context)
|
||||
{
|
||||
var name = context.Parameters.GetValue<string?>("DeviceName");
|
||||
Initialize(name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助
|
||||
|
||||
private CancellationToken Ct() => (_cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))).Token;
|
||||
|
||||
private async Task Exec(Func<Task> action)
|
||||
{
|
||||
if (_device == null)
|
||||
{
|
||||
AppendLog("错误:未关联到设备实例,请检查设备配置。");
|
||||
return;
|
||||
}
|
||||
if (IsBusy) return;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await action();
|
||||
IsConnected = _device.IsConnected;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
AppendLog("命令超时或已取消。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppendLog($"错误:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLog(string message)
|
||||
{
|
||||
var line = $"[{DateTime.Now:HH:mm:ss}] {message}";
|
||||
ResponseLog = ResponseLog.Length > 4000
|
||||
? line + "\n" + ResponseLog[..3000]
|
||||
: line + "\n" + ResponseLog;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清洗示波器原始返回的测量字符串(例如 "C1:PAVA RMS,5.57E-03V")并安全转化为无科学计数法的小数形式。
|
||||
/// </summary>
|
||||
/// <param name="rawResponse">设备原始应答数据</param>
|
||||
/// <returns>可直接绑定到 UI 呈现的字符串数字</returns>
|
||||
private string ParseMeasurement(string rawResponse)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(rawResponse)) return "—";
|
||||
|
||||
try
|
||||
{
|
||||
string cleanData = rawResponse.Trim();
|
||||
|
||||
// 1. 斩断报头,提取逗号后面的具体内容(如 "5.57E-03V" 或 "****")
|
||||
int commaIndex = cleanData.IndexOf(',');
|
||||
if (commaIndex == -1) return "—";
|
||||
|
||||
string valStr = cleanData.Substring(commaIndex + 1);
|
||||
|
||||
var match = Regex.Match(valStr, @"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?");
|
||||
if (match.Success)
|
||||
{
|
||||
valStr = match.Value;
|
||||
}
|
||||
|
||||
// 3. 校验并拦截设备未测出时的无效星号 "****"
|
||||
if (valStr.Contains("*") || string.IsNullOrWhiteSpace(valStr))
|
||||
{
|
||||
return "0"; // 回归为零或 "—",防止触发数据异常
|
||||
}
|
||||
|
||||
// 4. 解析科学计数法,并重新以不带科学计数法的小数样式展开
|
||||
if (double.TryParse(valStr, NumberStyles.Any, CultureInfo.InvariantCulture, out double result))
|
||||
{
|
||||
// "0.######" 样式会自动消除末尾无用的冗余零,并显示为普通小数(如 0.00557)
|
||||
return result.ToString("0.######", CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 捕获可能产生的边缘转换故障,保证轮询线程绝不崩溃
|
||||
}
|
||||
|
||||
return "—";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,345 +0,0 @@
|
||||
using DeviceCommand.Devices;
|
||||
using Prism.Commands;
|
||||
using Prism.Ioc;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using UIShare.GlobalVariable;
|
||||
using UIShare.ViewModelBase;
|
||||
|
||||
namespace DeviceEditModule.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// SPAW7000 功率分析记录仪控制面板 ViewModel。
|
||||
/// </summary>
|
||||
public class SPAW7000ViewModel : NavigateViewModelBase, IDisposable
|
||||
{
|
||||
#region 私有字段
|
||||
|
||||
private readonly DeviceManager _deviceManager;
|
||||
private SPAW7000? _device;
|
||||
private CancellationTokenSource? _cts;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 设备信息属性
|
||||
|
||||
private string _deviceName = "SPAW7000";
|
||||
public string DeviceName
|
||||
{
|
||||
get => _deviceName;
|
||||
set => SetProperty(ref _deviceName, value);
|
||||
}
|
||||
|
||||
private bool _isConnected;
|
||||
public bool IsConnected
|
||||
{
|
||||
get => _isConnected;
|
||||
set => SetProperty(ref _isConnected, value);
|
||||
}
|
||||
|
||||
private bool _isBusy;
|
||||
public bool IsBusy
|
||||
{
|
||||
get => _isBusy;
|
||||
set => SetProperty(ref _isBusy, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 输入参数属性
|
||||
|
||||
private int _channel = 1;
|
||||
/// <summary>当前操作通道。</summary>
|
||||
public int Channel
|
||||
{
|
||||
get => _channel;
|
||||
set => SetProperty(ref _channel, value);
|
||||
}
|
||||
|
||||
private SPAW7000.VoltageRange _voltageRange = SPAW7000.VoltageRange.V_300;
|
||||
/// <summary>电压量程枚举。</summary>
|
||||
public SPAW7000.VoltageRange VoltageRange
|
||||
{
|
||||
get => _voltageRange;
|
||||
set => SetProperty(ref _voltageRange, value);
|
||||
}
|
||||
|
||||
private SPAW7000.CurrentRange _currentRange = SPAW7000.CurrentRange.A_5;
|
||||
/// <summary>电流量程枚举。</summary>
|
||||
public SPAW7000.CurrentRange CurrentRange
|
||||
{
|
||||
get => _currentRange;
|
||||
set => SetProperty(ref _currentRange, value);
|
||||
}
|
||||
|
||||
public SPAW7000.VoltageRange[] VoltageRangeOptions { get; } =
|
||||
(SPAW7000.VoltageRange[])Enum.GetValues(typeof(SPAW7000.VoltageRange));
|
||||
|
||||
public SPAW7000.CurrentRange[] CurrentRangeOptions { get; } =
|
||||
(SPAW7000.CurrentRange[])Enum.GetValues(typeof(SPAW7000.CurrentRange));
|
||||
|
||||
private int _resolution = 6;
|
||||
/// <summary>显示分辨率(5 或 6)。</summary>
|
||||
public int Resolution
|
||||
{
|
||||
get => _resolution;
|
||||
set => SetProperty(ref _resolution, value);
|
||||
}
|
||||
|
||||
private int _brightness = 5;
|
||||
/// <summary>屏幕亮度(1~10)。</summary>
|
||||
public int Brightness
|
||||
{
|
||||
get => _brightness;
|
||||
set => SetProperty(ref _brightness, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 测量结果属性
|
||||
|
||||
private string _measuredVoltage = "—";
|
||||
public string MeasuredVoltage
|
||||
{
|
||||
get => _measuredVoltage;
|
||||
set => SetProperty(ref _measuredVoltage, value);
|
||||
}
|
||||
|
||||
private string _measuredCurrent = "—";
|
||||
public string MeasuredCurrent
|
||||
{
|
||||
get => _measuredCurrent;
|
||||
set => SetProperty(ref _measuredCurrent, value);
|
||||
}
|
||||
|
||||
private string _measuredPower = "—";
|
||||
public string MeasuredPower
|
||||
{
|
||||
get => _measuredPower;
|
||||
set => SetProperty(ref _measuredPower, value);
|
||||
}
|
||||
|
||||
private string _measuredFrequency = "—";
|
||||
public string MeasuredFrequency
|
||||
{
|
||||
get => _measuredFrequency;
|
||||
set => SetProperty(ref _measuredFrequency, value);
|
||||
}
|
||||
|
||||
private string _measuredPowerFactor = "—";
|
||||
public string MeasuredPowerFactor
|
||||
{
|
||||
get => _measuredPowerFactor;
|
||||
set => SetProperty(ref _measuredPowerFactor, value);
|
||||
}
|
||||
|
||||
private string _deviceModel = "—";
|
||||
public string DeviceModel
|
||||
{
|
||||
get => _deviceModel;
|
||||
set => SetProperty(ref _deviceModel, value);
|
||||
}
|
||||
|
||||
private string _deviceSerial = "—";
|
||||
public string DeviceSerial
|
||||
{
|
||||
get => _deviceSerial;
|
||||
set => SetProperty(ref _deviceSerial, value);
|
||||
}
|
||||
|
||||
private string _responseLog = string.Empty;
|
||||
/// <summary>命令响应日志(最新消息在顶部)。</summary>
|
||||
public string ResponseLog
|
||||
{
|
||||
get => _responseLog;
|
||||
set => SetProperty(ref _responseLog, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public ICommand QueryIdentityCommand { get; }
|
||||
public ICommand ResetDeviceCommand { get; }
|
||||
public ICommand QueryAllMeasureCommand { get; }
|
||||
public ICommand SetVoltageRangeCommand { get; }
|
||||
public ICommand SetCurrentRangeCommand { get; }
|
||||
public ICommand SetResolutionCommand { get; }
|
||||
public ICommand SetBrightnessCommand { get; }
|
||||
public ICommand SetTouchLockOnCommand { get; }
|
||||
public ICommand SetTouchLockOffCommand { get; }
|
||||
public ICommand QueryModelCommand { get; }
|
||||
public ICommand QuerySerialCommand { get; }
|
||||
public ICommand QueryStatusByteCommand { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
public SPAW7000ViewModel(IContainerProvider containerProvider) : base(containerProvider)
|
||||
{
|
||||
_deviceManager = containerProvider.Resolve<DeviceManager>();
|
||||
|
||||
QueryIdentityCommand = new DelegateCommand(async () => await Exec(async () => AppendLog("IDN: " + await _device!.查询设备标识(Ct()))));
|
||||
ResetDeviceCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.重置设备(Ct()); AppendLog("设备已重置"); }));
|
||||
SetVoltageRangeCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置电压量程(Channel, VoltageRange, Ct()); AppendLog($"通道 {Channel} 电压量程已设为 {(int)VoltageRange} V"); }));
|
||||
SetCurrentRangeCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置电流量程(Channel, CurrentRange, Ct()); AppendLog($"通道 {Channel} 电流量程已设为 {(int)CurrentRange} A"); }));
|
||||
SetResolutionCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置显示分辨率(Resolution, Ct()); AppendLog($"显示分辨率已设为 {Resolution} 位"); }));
|
||||
SetBrightnessCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置显示亮度(Brightness, Ct()); AppendLog($"屏幕亮度已设为 {Brightness}"); }));
|
||||
SetTouchLockOnCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置屏幕触摸锁定(true, Ct()); AppendLog("屏幕触摸已锁定"); }));
|
||||
SetTouchLockOffCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置屏幕触摸锁定(false, Ct()); AppendLog("屏幕触摸已解锁"); }));
|
||||
QueryModelCommand = new DelegateCommand(async () => await Exec(async () => { DeviceModel = await _device!.查询设备型号(Ct()); AppendLog($"型号: {DeviceModel}"); }));
|
||||
QuerySerialCommand = new DelegateCommand(async () => await Exec(async () => { DeviceSerial = await _device!.查询设备序列号(Ct()); AppendLog($"序列号: {DeviceSerial}"); }));
|
||||
QueryStatusByteCommand = new DelegateCommand(async () => await Exec(async () => AppendLog("STB: " + await _device!.读取状态字节(Ct()))));
|
||||
|
||||
// 只修改这里:保持你原本的 5 次驱动查询调用不变,仅对读回来的科学计数法进行两位小数格式化
|
||||
QueryAllMeasureCommand = new DelegateCommand(async () => await Exec(async () =>
|
||||
{
|
||||
string rawU = await _device!.查询实际电压(Channel, Ct());
|
||||
string rawI = await _device!.查询实际电流(Channel, Ct());
|
||||
string rawP = await _device!.查询实际功率(Channel, Ct());
|
||||
string rawF = await _device!.查询频率(Channel, Ct());
|
||||
string rawPF = await _device!.查询功率因数(Channel, Ct());
|
||||
|
||||
// 转换科学计数法格式,如果失败会自动保持原样
|
||||
MeasuredVoltage = FormatToDecimal(rawU, "F2"); // 电压两位小数
|
||||
MeasuredCurrent = FormatToDecimal(rawI, "F3"); // 电流通常较小,建议保留3位小数
|
||||
MeasuredPower = FormatToDecimal(rawP, "F2"); // 功率两位小数
|
||||
MeasuredFrequency = FormatToDecimal(rawF, "F2"); // 频率两位小数
|
||||
MeasuredPowerFactor = FormatToDecimal(rawPF, "F3"); // 功率因数保留3位小数
|
||||
|
||||
AppendLog($"CH{Channel} 测量 → U:{MeasuredVoltage}V I:{MeasuredCurrent}A P:{MeasuredPower}W F:{MeasuredFrequency}Hz PF:{MeasuredPowerFactor}");
|
||||
}));
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
#region 初始化 / Navigation
|
||||
|
||||
public void Initialize(string? deviceName = null)
|
||||
{
|
||||
SPAW7000? found = null;
|
||||
string? foundName = null;
|
||||
|
||||
if (deviceName != null &&
|
||||
_deviceManager.DeviceMap.TryGetValue(deviceName, out var d) &&
|
||||
d is SPAW7000 s)
|
||||
{
|
||||
found = s;
|
||||
foundName = deviceName;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var kv in _deviceManager.DeviceMap)
|
||||
{
|
||||
if (kv.Value is SPAW7000 spaw)
|
||||
{
|
||||
found = spaw;
|
||||
foundName = kv.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_device = found;
|
||||
DeviceName = foundName ?? "SPAW7000 (未找到)";
|
||||
IsConnected = _device?.IsConnected ?? false;
|
||||
|
||||
AppendLog(found != null
|
||||
? $"已关联设备 [{DeviceName}],连接状态:{(IsConnected ? "已连接" : "未连接")}"
|
||||
: "未在 DeviceManager 中找到 SPAW7000 设备,请先初始化设备配置。");
|
||||
}
|
||||
|
||||
public override void OnNavigatedTo(NavigationContext context)
|
||||
{
|
||||
var name = context.Parameters.GetValue<string?>("DeviceName");
|
||||
Initialize(name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助
|
||||
|
||||
private CancellationToken Ct() => (_cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))).Token;
|
||||
|
||||
/// <summary>
|
||||
/// 将科学计数法字符串转换为标准小数格式
|
||||
/// </summary>
|
||||
private string FormatToDecimal(string rawInput, string decimalFormat = "F2")
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(rawInput))
|
||||
return "—";
|
||||
|
||||
// 去除可能夹杂的命令头,保留数据部分
|
||||
string cleanInput = CleanResponseHeader(rawInput);
|
||||
|
||||
// 解析科学计数法(NumberStyles.Any 和 InvariantCulture 是关键)
|
||||
if (double.TryParse(cleanInput, NumberStyles.Any, CultureInfo.InvariantCulture, out double value))
|
||||
{
|
||||
return value.ToString(decimalFormat, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return cleanInput;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 辅助清洗:剥离可能伴随吐回的命令头或双引号
|
||||
/// </summary>
|
||||
private string CleanResponseHeader(string response)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(response)) return string.Empty;
|
||||
string result = response.Trim();
|
||||
if (result.Contains(" "))
|
||||
{
|
||||
int lastSpaceIndex = result.LastIndexOf(' ');
|
||||
result = result.Substring(lastSpaceIndex + 1).Trim();
|
||||
}
|
||||
return result.Replace("\"", "").Replace("'", "").Trim();
|
||||
}
|
||||
|
||||
private async Task Exec(Func<Task> action)
|
||||
{
|
||||
if (_device == null)
|
||||
{
|
||||
AppendLog("错误:未关联到设备实例,请检查设备配置。");
|
||||
return;
|
||||
}
|
||||
if (IsBusy) return;
|
||||
IsBusy = true;
|
||||
try
|
||||
{
|
||||
await action();
|
||||
IsConnected = _device.IsConnected;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
AppendLog("命令超时或已取消。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppendLog($"错误:{ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendLog(string message)
|
||||
{
|
||||
var line = $"[{DateTime.Now:HH:mm:ss}] {message}";
|
||||
ResponseLog = ResponseLog.Length > 4000
|
||||
? line + "\n" + ResponseLog[..3000]
|
||||
: line + "\n" + ResponseLog;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
<UserControl x:Class="DeviceEditModule.Views.IT7800EView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:converters="clr-namespace:UIShare.Converters;assembly=UIShare"
|
||||
mc:Ignorable="d"
|
||||
prism:ViewModelLocator.AutoWireViewModel="False"
|
||||
d:DesignHeight="760" d:DesignWidth="860">
|
||||
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="12">
|
||||
|
||||
<!-- ═══ 设备信息头 ═══ -->
|
||||
<materialDesign:Card Margin="0,0,0,8" Padding="12,8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<materialDesign:PackIcon Kind="Flash" Width="22" Height="22"
|
||||
Foreground="#1565C0" Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="IT7800E 交直流可编程电源"
|
||||
FontSize="15" FontWeight="Bold"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding DeviceName, StringFormat=' [{0}]'}"
|
||||
FontSize="13" Foreground="#757575"
|
||||
VerticalAlignment="Center" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 连接状态指示 -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Border Width="10" Height="10" CornerRadius="5" Margin="0,0,6,0">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Background" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="未连接"/>
|
||||
<Setter Property="Foreground" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Text" Value="已连接"/>
|
||||
<Setter Property="Foreground" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<!-- 忙碌指示 -->
|
||||
<ProgressBar IsIndeterminate="True" Width="80" Height="4"
|
||||
Margin="12,0,0,0"
|
||||
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- ═══ 主体 2 列 ═══ -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ─── 左列 ─── -->
|
||||
<StackPanel Grid.Column="0" Margin="0,0,4,0">
|
||||
|
||||
<!-- 输出控制 -->
|
||||
<GroupBox Header="输出控制" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<!-- 开关输出 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="主输出" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="开启输出" Command="{Binding OutputOnCommand}"
|
||||
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||
Background="#388E3C" Foreground="White"
|
||||
Height="32" Padding="12,0" FontSize="12" Margin="4,0"/>
|
||||
<Button Content="关闭输出" Command="{Binding OutputOffCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 工作模式 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="工作模式" Style="{StaticResource ParamLabel}"/>
|
||||
<ComboBox Width="90" Height="32" Margin="4,0"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
SelectedItem="{Binding SelectedMode}"
|
||||
VerticalContentAlignment="Center" FontSize="12">
|
||||
<ComboBoxItem Content="AC"/>
|
||||
<ComboBoxItem Content="DC"/>
|
||||
<ComboBoxItem Content="ACDC"/>
|
||||
</ComboBox>
|
||||
<Button Content="设置模式" Command="{Binding SetModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 远程/本地 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="控制模式" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="远程控制" Command="{Binding SetRemoteModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="本地控制" Command="{Binding SetLocalModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 清除 / 重置 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="系统操作" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="清除告警" Command="{Binding ClearAlarmCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
<Button Content="清除错误" Command="{Binding ClearErrorCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
<Button Content="重置设备" Command="{Binding ResetDeviceCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 参数设置 -->
|
||||
<GroupBox Header="参数设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<!-- AC 电压 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="AC电压 (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding AcVoltage, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetAcVoltageCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- DC 偏置 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="DC偏置 (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding DcVoltage, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetDcVoltageCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 频率 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="频率 (Hz)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding Frequency, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetFrequencyCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 限流 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="限流 (A)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding CurrentLimit, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetCurrentCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 保护设置 -->
|
||||
<GroupBox Header="保护设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OVP (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OvpValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OVP" Command="{Binding SetOvpCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OCP (A)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OcpValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OCP" Command="{Binding SetOcpCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ─── 右列 ─── -->
|
||||
<StackPanel Grid.Column="1" Margin="4,0,0,0">
|
||||
|
||||
<!-- 实时测量 -->
|
||||
<GroupBox Header="实时测量" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际电压" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredVoltage, Mode=OneWay}"/>
|
||||
<TextBlock Text="V" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际电流" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredCurrent, Mode=OneWay}"/>
|
||||
<TextBlock Text="A" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际功率" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredPower, Mode=OneWay}"/>
|
||||
<TextBlock Text="W" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="输出频率" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredFrequency, Mode=OneWay}"/>
|
||||
<TextBlock Text="Hz" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<Button Content="刷新全部测量" Command="{Binding QueryAllMeasureCommand}"
|
||||
Style="{StaticResource CmdBtn}"
|
||||
HorizontalAlignment="Left" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 设备信息 -->
|
||||
<GroupBox Header="设备信息" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Orientation="Horizontal" Margin="4,8">
|
||||
<Button Content="查询 IDN" Command="{Binding QueryIdentityCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 响应日志 -->
|
||||
<GroupBox Header="响应日志" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<ScrollViewer Height="260" VerticalScrollBarVisibility="Auto">
|
||||
<TextBox Text="{Binding ResponseLog, Mode=OneWay}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
IsReadOnly="True"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="11"
|
||||
FontFamily="Consolas"
|
||||
Background="#FAFAFA"
|
||||
BorderThickness="0"
|
||||
VerticalAlignment="Top"/>
|
||||
</ScrollViewer>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace DeviceEditModule.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// IT7800EView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class IT7800EView : UserControl
|
||||
{
|
||||
public IT7800EView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,264 +0,0 @@
|
||||
<UserControl x:Class="DeviceEditModule.Views.N36200View"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:converters="clr-namespace:UIShare.Converters;assembly=UIShare"
|
||||
mc:Ignorable="d"
|
||||
prism:ViewModelLocator.AutoWireViewModel="False"
|
||||
d:DesignHeight="760" d:DesignWidth="860">
|
||||
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="12">
|
||||
|
||||
<!-- ═══ 设备信息头 ═══ -->
|
||||
<materialDesign:Card Margin="0,0,0,8" Padding="12,8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<materialDesign:PackIcon Kind="BatteryCharging" Width="22" Height="22"
|
||||
Foreground="#2E7D32" Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="N36200 宽范围可编程直流电源"
|
||||
FontSize="15" FontWeight="Bold"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding DeviceName, StringFormat=' [{0}]'}"
|
||||
FontSize="13" Foreground="#757575"
|
||||
VerticalAlignment="Center" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 连接状态指示 -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Border Width="10" Height="10" CornerRadius="5" Margin="0,0,6,0">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Background" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="未连接"/>
|
||||
<Setter Property="Foreground" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Text" Value="已连接"/>
|
||||
<Setter Property="Foreground" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<ProgressBar IsIndeterminate="True" Width="80" Height="4"
|
||||
Margin="12,0,0,0"
|
||||
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- ═══ 主体 2 列 ═══ -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ─── 左列 ─── -->
|
||||
<StackPanel Grid.Column="0" Margin="0,0,4,0">
|
||||
|
||||
<!-- 输出控制 -->
|
||||
<GroupBox Header="输出控制" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<!-- 开关输出 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="DC 输出" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="开启输出" Command="{Binding OutputOnCommand}"
|
||||
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||
Background="#388E3C" Foreground="White"
|
||||
Height="32" Padding="12,0" FontSize="12" Margin="4,0"/>
|
||||
<Button Content="关闭输出" Command="{Binding OutputOffCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 运行模式 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="运行模式" Style="{StaticResource ParamLabel}"/>
|
||||
<ComboBox Width="100" Height="32" Margin="4,0"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
SelectedItem="{Binding SelectedMode}"
|
||||
VerticalContentAlignment="Center" FontSize="12">
|
||||
<ComboBoxItem Content="NORMal"/>
|
||||
<ComboBoxItem Content="CHARge"/>
|
||||
<ComboBoxItem Content="SEQuence"/>
|
||||
<ComboBoxItem Content="CPOWer"/>
|
||||
<ComboBoxItem Content="CARWave"/>
|
||||
</ComboBox>
|
||||
<Button Content="设置" Command="{Binding SetModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 重置 / 清除 / IDN -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="系统操作" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="清除告警" Command="{Binding ClearAlarmCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
<Button Content="重置设备" Command="{Binding ResetDeviceCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 参数设置 -->
|
||||
<GroupBox Header="参数设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<!-- 电压 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="电压 (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding Voltage, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetVoltageCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 限流 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="限流 (A)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding CurrentLimit, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetCurrentCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 保护设置 -->
|
||||
<GroupBox Header="保护设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OVP (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OvpValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OVP" Command="{Binding SetOvpCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OCP (A)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OcpValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OCP" Command="{Binding SetOcpCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="UVP (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding UvpValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 UVP" Command="{Binding SetUvpCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OPP (W)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OppValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OPP" Command="{Binding SetOppCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ─── 右列 ─── -->
|
||||
<StackPanel Grid.Column="1" Margin="4,0,0,0">
|
||||
|
||||
<!-- 实时测量 -->
|
||||
<GroupBox Header="实时测量" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际电压" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredVoltage, Mode=OneWay}"/>
|
||||
<TextBlock Text="V" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际电流" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredCurrent, Mode=OneWay}"/>
|
||||
<TextBlock Text="A" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际功率" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredPower, Mode=OneWay}"/>
|
||||
<TextBlock Text="W" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<Button Content="刷新全部测量" Command="{Binding QueryAllMeasureCommand}"
|
||||
Style="{StaticResource CmdBtn}"
|
||||
HorizontalAlignment="Left" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 设备信息与状态 -->
|
||||
<GroupBox Header="设备信息与状态" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="查询 IDN" Command="{Binding QueryIdentityCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="查询状态字" Command="{Binding QueryStatusCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="状态字" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}" Width="200"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding DeviceStatus, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 响应日志 -->
|
||||
<GroupBox Header="响应日志" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<ScrollViewer Height="300" VerticalScrollBarVisibility="Auto">
|
||||
<TextBox Text="{Binding ResponseLog, Mode=OneWay}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
IsReadOnly="True"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="11"
|
||||
FontFamily="Consolas"
|
||||
Background="#FAFAFA"
|
||||
BorderThickness="0"
|
||||
VerticalAlignment="Top"/>
|
||||
</ScrollViewer>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace DeviceEditModule.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// N36200View.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class N36200View : UserControl
|
||||
{
|
||||
public N36200View()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
<UserControl x:Class="DeviceEditModule.Views.N36600View"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:converters="clr-namespace:UIShare.Converters;assembly=UIShare"
|
||||
mc:Ignorable="d"
|
||||
prism:ViewModelLocator.AutoWireViewModel="False"
|
||||
d:DesignHeight="760" d:DesignWidth="860">
|
||||
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="12">
|
||||
|
||||
<!-- ═══ 设备信息头 ═══ -->
|
||||
<materialDesign:Card Margin="0,0,0,8" Padding="12,8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<materialDesign:PackIcon Kind="BatteryCharging" Width="22" Height="22"
|
||||
Foreground="#2E7D32" Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="N36600 便携式宽范围可编程直流电源"
|
||||
FontSize="15" FontWeight="Bold"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding DeviceName, StringFormat=' [{0}]'}"
|
||||
FontSize="13" Foreground="#757575"
|
||||
VerticalAlignment="Center" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 连接状态指示 -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Border Width="10" Height="10" CornerRadius="5" Margin="0,0,6,0">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Background" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="未连接"/>
|
||||
<Setter Property="Foreground" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Text" Value="已连接"/>
|
||||
<Setter Property="Foreground" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<ProgressBar IsIndeterminate="True" Width="80" Height="4"
|
||||
Margin="12,0,0,0"
|
||||
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- ═══ 主体 2 列 ═══ -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ─── 左列 ─── -->
|
||||
<StackPanel Grid.Column="0" Margin="0,0,4,0">
|
||||
|
||||
<!-- 输出控制 -->
|
||||
<GroupBox Header="输出控制" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<!-- 开关输出 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="DC 输出" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="开启输出" Command="{Binding OutputOnCommand}"
|
||||
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||
Background="#388E3C" Foreground="White"
|
||||
Height="32" Padding="12,0" FontSize="12" Margin="4,0"/>
|
||||
<Button Content="关闭输出" Command="{Binding OutputOffCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 远程/本地 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="控制模式" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="远程控制" Command="{Binding SetRemoteModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="本地控制" Command="{Binding SetLocalModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 清除保护 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="清除保护" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="清除OVP" Command="{Binding ClearVoltageProtectionCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
<Button Content="清除OCP" Command="{Binding ClearCurrentProtectionCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 参数设置 -->
|
||||
<GroupBox Header="参数设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<!-- 电压 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="电压 (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding Voltage, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetVoltageCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 电流 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="电流 (A)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding CurrentLimit, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetCurrentCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 功率 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="功率 (W)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding Power, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetPowerCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 保护设置 -->
|
||||
<GroupBox Header="保护设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OVP (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OvpValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OVP" Command="{Binding SetOvpCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OCP (A)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OcpValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OCP" Command="{Binding SetOcpCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ─── 右列 ─── -->
|
||||
<StackPanel Grid.Column="1" Margin="4,0,0,0">
|
||||
|
||||
<!-- 实时测量 -->
|
||||
<GroupBox Header="实时测量" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际电压" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredVoltage, Mode=OneWay}"/>
|
||||
<TextBlock Text="V" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际电流" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredCurrent, Mode=OneWay}"/>
|
||||
<TextBlock Text="A" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际功率" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredPower, Mode=OneWay}"/>
|
||||
<TextBlock Text="W" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<Button Content="刷新全部测量" Command="{Binding QueryAllMeasureCommand}"
|
||||
Style="{StaticResource CmdBtn}"
|
||||
HorizontalAlignment="Left" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 设备信息与状态 -->
|
||||
<GroupBox Header="设备信息与状态" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="查询 IDN" Command="{Binding QueryIdentityCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="查询输出状态" Command="{Binding QueryOutputStateCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="输出状态" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}" Width="160"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OutputState, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 响应日志 -->
|
||||
<GroupBox Header="响应日志" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<ScrollViewer Height="300" VerticalScrollBarVisibility="Auto">
|
||||
<TextBox Text="{Binding ResponseLog, Mode=OneWay}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
IsReadOnly="True"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="11"
|
||||
FontFamily="Consolas"
|
||||
Background="#FAFAFA"
|
||||
BorderThickness="0"
|
||||
VerticalAlignment="Top"/>
|
||||
</ScrollViewer>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace DeviceEditModule.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// N36600View.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class N36600View : UserControl
|
||||
{
|
||||
public N36600View()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,263 +0,0 @@
|
||||
<UserControl x:Class="DeviceEditModule.Views.N69200View"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:converters="clr-namespace:UIShare.Converters;assembly=UIShare"
|
||||
mc:Ignorable="d"
|
||||
prism:ViewModelLocator.AutoWireViewModel="False"
|
||||
d:DesignHeight="760" d:DesignWidth="860">
|
||||
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="12">
|
||||
|
||||
<!-- ═══ 设备信息头 ═══ -->
|
||||
<materialDesign:Card Margin="0,0,0,8" Padding="12,8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<materialDesign:PackIcon Kind="CurrentDc" Width="22" Height="22"
|
||||
Foreground="#1565C0" Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="N69200 可编程直流电子负载"
|
||||
FontSize="15" FontWeight="Bold"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding DeviceName, StringFormat=' [{0}]'}"
|
||||
FontSize="13" Foreground="#757575"
|
||||
VerticalAlignment="Center" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 连接状态指示 -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Border Width="10" Height="10" CornerRadius="5" Margin="0,0,6,0">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Background" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="未连接"/>
|
||||
<Setter Property="Foreground" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Text" Value="已连接"/>
|
||||
<Setter Property="Foreground" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<ProgressBar IsIndeterminate="True" Width="80" Height="4"
|
||||
Margin="12,0,0,0"
|
||||
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- ═══ 主体 2 列 ═══ -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ─── 左列 ─── -->
|
||||
<StackPanel Grid.Column="0" Margin="0,0,4,0">
|
||||
|
||||
<!-- 输入控制 -->
|
||||
<GroupBox Header="输入控制" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<!-- 开关输入 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="DC 输入" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="开启输入" Command="{Binding InputOnCommand}"
|
||||
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||
Background="#388E3C" Foreground="White"
|
||||
Height="32" Padding="12,0" FontSize="12" Margin="4,0"/>
|
||||
<Button Content="关闭输入" Command="{Binding InputOffCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 工作模式 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="工作模式" Style="{StaticResource ParamLabel}"/>
|
||||
<ComboBox xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
Width="90" Height="32" Margin="4,0"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
SelectedItem="{Binding SelectedMode}"
|
||||
VerticalContentAlignment="Center" FontSize="12">
|
||||
<sys:String>CC</sys:String>
|
||||
<sys:String>CV</sys:String>
|
||||
<sys:String>CP</sys:String>
|
||||
<sys:String>CR</sys:String>
|
||||
</ComboBox>
|
||||
<Button Content="设置" Command="{Binding SetModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="查询" Command="{Binding QueryModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!-- 远程/本地 -->
|
||||
<!--<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="控制模式" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="远程控制" Command="{Binding SetRemoteModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="本地控制" Command="{Binding SetLocalModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>-->
|
||||
<!-- 系统操作 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="系统操作" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="清除告警" Command="{Binding ClearAlarmCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
<Button Content="重置设备" Command="{Binding ResetDeviceCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 参数设置 -->
|
||||
<GroupBox Header="参数设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<!-- 设定值 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="设定值" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding LoadValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetLoadValueCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 保护设置 -->
|
||||
<GroupBox Header="保护设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OVP (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OvpValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OVP" Command="{Binding SetOvpCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OCP (A)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OcpValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OCP" Command="{Binding SetOcpCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="OPP (W)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding OppValue, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置 OPP" Command="{Binding SetOppCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ─── 右列 ─── -->
|
||||
<StackPanel Grid.Column="1" Margin="4,0,0,0">
|
||||
|
||||
<!-- 实时测量 -->
|
||||
<GroupBox Header="实时测量" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际电压" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredVoltage, Mode=OneWay}"/>
|
||||
<TextBlock Text="V" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际电流" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredCurrent, Mode=OneWay}"/>
|
||||
<TextBlock Text="A" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="实际功率" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding MeasuredPower, Mode=OneWay}"/>
|
||||
<TextBlock Text="W" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<Button Content="刷新全部测量" Command="{Binding QueryAllMeasureCommand}"
|
||||
Style="{StaticResource CmdBtn}"
|
||||
HorizontalAlignment="Left" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 设备信息与状态 -->
|
||||
<GroupBox Header="设备信息与状态" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="查询 IDN" Command="{Binding QueryIdentityCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="查询状态字节" Command="{Binding QueryStatusCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="当前模式" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}" Width="120"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding CurrentMode, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="状态字节" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}" Width="120"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
Text="{Binding StatusByte, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 响应日志 -->
|
||||
<GroupBox Header="响应日志" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<ScrollViewer Height="260" VerticalScrollBarVisibility="Auto">
|
||||
<TextBox Text="{Binding ResponseLog, Mode=OneWay}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
IsReadOnly="True"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="11"
|
||||
FontFamily="Consolas"
|
||||
Background="#FAFAFA"
|
||||
BorderThickness="0"
|
||||
VerticalAlignment="Top"/>
|
||||
</ScrollViewer>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace DeviceEditModule.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// N69200View.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class N69200View : UserControl
|
||||
{
|
||||
public N69200View()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
<UserControl x:Class="DeviceEditModule.Views.SDS2000X_HDView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:converters="clr-namespace:UIShare.Converters;assembly=UIShare"
|
||||
mc:Ignorable="d"
|
||||
prism:ViewModelLocator.AutoWireViewModel="False"
|
||||
d:DesignHeight="760" d:DesignWidth="860">
|
||||
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="12">
|
||||
|
||||
<!-- ═══ 设备信息头 ═══ -->
|
||||
<materialDesign:Card Margin="0,0,0,8" Padding="12,8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<materialDesign:PackIcon Kind="Waveform" Width="22" Height="22"
|
||||
Foreground="#1565C0" Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="SDS2000X_HD 数字存储示波器"
|
||||
FontSize="15" FontWeight="Bold"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding DeviceName, StringFormat=' [{0}]'}"
|
||||
FontSize="13" Foreground="#757575"
|
||||
VerticalAlignment="Center" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 连接状态指示 -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Border Width="10" Height="10" CornerRadius="5" Margin="0,0,6,0">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Background" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="未连接"/>
|
||||
<Setter Property="Foreground" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Text" Value="已连接"/>
|
||||
<Setter Property="Foreground" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<ProgressBar IsIndeterminate="True" Width="80" Height="4"
|
||||
Margin="12,0,0,0"
|
||||
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- ═══ 主体 2 列 ═══ -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ─── 左列 ─── -->
|
||||
<StackPanel Grid.Column="0" Margin="0,0,4,0">
|
||||
|
||||
<!-- 通道选择 -->
|
||||
<GroupBox Header="通道选择" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="通道号" Style="{StaticResource ParamLabel}"/>
|
||||
<ComboBox Width="80" Height="32" Margin="4,0"
|
||||
SelectedItem="{Binding Channel}"
|
||||
VerticalContentAlignment="Center" FontSize="12">
|
||||
<sys:Int32>1</sys:Int32>
|
||||
<sys:Int32>2</sys:Int32>
|
||||
<sys:Int32>3</sys:Int32>
|
||||
<sys:Int32>4</sys:Int32>
|
||||
</ComboBox>
|
||||
<Button Content="开启" Command="{Binding SetChannelOnCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="关闭" Command="{Binding SetChannelOffCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 运行控制 -->
|
||||
<GroupBox Header="运行控制" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="Run" Command="{Binding RunCommand}"
|
||||
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||
Background="#388E3C" Foreground="White"
|
||||
Height="32" Padding="16,0" FontSize="12" Margin="4,0"/>
|
||||
<Button Content="Stop" Command="{Binding StopCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
<Button Content="Single" Command="{Binding SingleCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="Force Trig" Command="{Binding ForceTriggerCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="查询 IDN" Command="{Binding QueryIdentityCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="重置设备" Command="{Binding ResetDeviceCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 垂直设置 -->
|
||||
<GroupBox Header="垂直设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="V/div (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
Text="{Binding VoltsPerDiv}"/>
|
||||
<Button Content="设置" Command="{Binding SetVoltsDivCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="Offset (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
Text="{Binding Offset, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetOffsetCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="输入阻抗" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="50Ω" Command="{Binding SetImpedance50Command}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="1MΩ" Command="{Binding SetImpedance1MCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 水平/触发设置 -->
|
||||
<GroupBox Header="水平与触发" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="时基 (s/div)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
Text="{Binding TimeBase}"/>
|
||||
<Button Content="设置" Command="{Binding SetTimeBaseCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="触发电平 (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}"
|
||||
Text="{Binding TriggerLevel, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetTriggerLevelCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="触发源" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}" Width="80"
|
||||
Text="{Binding TriggerSource, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetTriggerSourceCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ─── 右列 ─── -->
|
||||
<StackPanel Grid.Column="1" Margin="4,0,0,0">
|
||||
|
||||
<!-- 自动测量 -->
|
||||
<GroupBox Header="自动测量" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="Vpp" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
Text="{Binding MeasuredVpp, Mode=OneWay}"/>
|
||||
<TextBlock Text="V" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
<Button Content="刷新" Command="{Binding QueryVppCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="频率" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
Text="{Binding MeasuredFrequency, Mode=OneWay}"/>
|
||||
<TextBlock Text="Hz" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
<Button Content="刷新" Command="{Binding QueryFrequencyCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="RMS" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
Text="{Binding MeasuredRms, Mode=OneWay}"/>
|
||||
<TextBlock Text="V" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
<Button Content="刷新" Command="{Binding QueryRmsCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<Button Content="刷新全部测量" Command="{Binding QueryMeasurementsCommand}"
|
||||
Style="{StaticResource CmdBtn}"
|
||||
HorizontalAlignment="Left" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 响应日志 -->
|
||||
<GroupBox Header="响应日志" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<ScrollViewer Height="460" VerticalScrollBarVisibility="Auto">
|
||||
<TextBox Text="{Binding ResponseLog, Mode=OneWay}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
IsReadOnly="True"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="11"
|
||||
FontFamily="Consolas"
|
||||
Background="#FAFAFA"
|
||||
BorderThickness="0"
|
||||
VerticalAlignment="Top"/>
|
||||
</ScrollViewer>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace DeviceEditModule.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// SDS2000X_HDView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class SDS2000X_HDView : UserControl
|
||||
{
|
||||
public SDS2000X_HDView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
<UserControl x:Class="DeviceEditModule.Views.SPAW7000View"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:converters="clr-namespace:UIShare.Converters;assembly=UIShare"
|
||||
mc:Ignorable="d"
|
||||
prism:ViewModelLocator.AutoWireViewModel="False"
|
||||
d:DesignHeight="760" d:DesignWidth="860">
|
||||
|
||||
<UserControl.Resources>
|
||||
<converters:BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="12">
|
||||
|
||||
<!-- ═══ 设备信息头 ═══ -->
|
||||
<materialDesign:Card Margin="0,0,0,8" Padding="12,8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<materialDesign:PackIcon Kind="ChartLine" Width="22" Height="22"
|
||||
Foreground="#1565C0" Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="SPAW7000 功率分析记录仪"
|
||||
FontSize="15" FontWeight="Bold"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding DeviceName, StringFormat=' [{0}]'}"
|
||||
FontSize="13" Foreground="#757575"
|
||||
VerticalAlignment="Center" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 连接状态指示 -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Border Width="10" Height="10" CornerRadius="5" Margin="0,0,6,0">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Background" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
<TextBlock VerticalAlignment="Center" FontSize="12">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="未连接"/>
|
||||
<Setter Property="Foreground" Value="#F44336"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Text" Value="已连接"/>
|
||||
<Setter Property="Foreground" Value="#4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<ProgressBar IsIndeterminate="True" Width="80" Height="4"
|
||||
Margin="12,0,0,0"
|
||||
Visibility="{Binding IsBusy, Converter={StaticResource BoolToVis}}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
|
||||
<!-- ═══ 主体 2 列 ═══ -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ─── 左列 ─── -->
|
||||
<StackPanel Grid.Column="0" Margin="0,0,4,0">
|
||||
|
||||
<!-- 通道与量程 -->
|
||||
<GroupBox Header="通道与量程" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="通道号" Style="{StaticResource ParamLabel}"/>
|
||||
<ComboBox Width="80" Height="32" Margin="4,0"
|
||||
SelectedItem="{Binding Channel}"
|
||||
VerticalContentAlignment="Center" FontSize="12">
|
||||
<sys:Int32>1</sys:Int32>
|
||||
<sys:Int32>2</sys:Int32>
|
||||
<sys:Int32>3</sys:Int32>
|
||||
<sys:Int32>4</sys:Int32>
|
||||
<sys:Int32>5</sys:Int32>
|
||||
<sys:Int32>6</sys:Int32>
|
||||
<sys:Int32>7</sys:Int32>
|
||||
<sys:Int32>8</sys:Int32>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="电压量程 (V)" Style="{StaticResource ParamLabel}"/>
|
||||
<ComboBox Width="100" Height="32" Margin="4,0"
|
||||
ItemsSource="{Binding VoltageRangeOptions}"
|
||||
SelectedItem="{Binding VoltageRange}"
|
||||
VerticalContentAlignment="Center" FontSize="12"/>
|
||||
<Button Content="设置" Command="{Binding SetVoltageRangeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="电流量程 (A)" Style="{StaticResource ParamLabel}"/>
|
||||
<ComboBox Width="100" Height="32" Margin="4,0"
|
||||
ItemsSource="{Binding CurrentRangeOptions}"
|
||||
SelectedItem="{Binding CurrentRange}"
|
||||
VerticalContentAlignment="Center" FontSize="12"/>
|
||||
<Button Content="设置" Command="{Binding SetCurrentRangeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<!--<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="耦合模式" Style="{StaticResource ParamLabel}"/>
|
||||
<ComboBox Width="90" Height="32" Margin="4,0"
|
||||
SelectedItem="{Binding CouplingMode}"
|
||||
ItemsSource="{Binding InputMeasureModeOptions}"
|
||||
VerticalContentAlignment="Center" FontSize="12">
|
||||
</ComboBox>
|
||||
<Button Content="设置" Command="{Binding SetCouplingModeCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>-->
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 系统设置 -->
|
||||
<GroupBox Header="系统设置" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="分辨率" Style="{StaticResource ParamLabel}"/>
|
||||
<ComboBox Width="80" Height="32" Margin="4,0"
|
||||
SelectedItem="{Binding Resolution}"
|
||||
VerticalContentAlignment="Center" FontSize="12">
|
||||
<sys:Int32>5</sys:Int32>
|
||||
<sys:Int32>6</sys:Int32>
|
||||
</ComboBox>
|
||||
<Button Content="设置" Command="{Binding SetResolutionCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="亮度 (1~10)" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource NumInput}" Width="60"
|
||||
Text="{Binding Brightness, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Content="设置" Command="{Binding SetBrightnessCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="触摸锁" Style="{StaticResource ParamLabel}"/>
|
||||
<Button Content="锁定" Command="{Binding SetTouchLockOnCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="解锁" Command="{Binding SetTouchLockOffCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 设备信息 -->
|
||||
<GroupBox Header="设备信息" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="查询 IDN" Command="{Binding QueryIdentityCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="重置设备" Command="{Binding ResetDeviceCommand}"
|
||||
Style="{StaticResource WarnBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="查询型号" Command="{Binding QueryModelCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="查询序列号" Command="{Binding QuerySerialCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
<Button Content="查询 STB" Command="{Binding QueryStatusByteCommand}"
|
||||
Style="{StaticResource CmdBtn}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="型号" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}" Width="281"
|
||||
Text="{Binding DeviceModel, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="序列号" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}" Width="281"
|
||||
Text="{Binding DeviceSerial, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
|
||||
<!-- ─── 右列 ─── -->
|
||||
<StackPanel Grid.Column="1" Margin="4,0,0,0">
|
||||
|
||||
<!-- 实时测量 -->
|
||||
<GroupBox Header="实时测量" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<StackPanel Margin="4,4,4,4">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="电压" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
Text="{Binding MeasuredVoltage, Mode=OneWay}"/>
|
||||
<TextBlock Text="V" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="电流" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
Text="{Binding MeasuredCurrent, Mode=OneWay}"/>
|
||||
<TextBlock Text="A" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="功率" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
Text="{Binding MeasuredPower, Mode=OneWay}"/>
|
||||
<TextBlock Text="W" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="频率" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
Text="{Binding MeasuredFrequency, Mode=OneWay}"/>
|
||||
<TextBlock Text="Hz" VerticalAlignment="Center" Margin="2,0,8,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<TextBlock Text="功率因数" Style="{StaticResource ParamLabel}"/>
|
||||
<TextBox Style="{StaticResource MeasureBox}"
|
||||
Text="{Binding MeasuredPowerFactor, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
<Button Content="刷新全部测量" Command="{Binding QueryAllMeasureCommand}"
|
||||
Style="{StaticResource CmdBtn}"
|
||||
HorizontalAlignment="Left" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 响应日志 -->
|
||||
<GroupBox Header="响应日志" Margin="0,0,0,8"
|
||||
materialDesign:ColorZoneAssist.Mode="PrimaryLight">
|
||||
<ScrollViewer Height="360" VerticalScrollBarVisibility="Auto">
|
||||
<TextBox Text="{Binding ResponseLog, Mode=OneWay}"
|
||||
materialDesign:HintAssist.Hint=""
|
||||
IsReadOnly="True"
|
||||
TextWrapping="Wrap"
|
||||
FontSize="11"
|
||||
FontFamily="Consolas"
|
||||
Background="#FAFAFA"
|
||||
BorderThickness="0"
|
||||
VerticalAlignment="Top"/>
|
||||
</ScrollViewer>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace DeviceEditModule.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// SPAW7000View.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class SPAW7000View : UserControl
|
||||
{
|
||||
public SPAW7000View()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user