Files
ACP/DeviceEditModule/ViewModels/SPAW7000ViewModel.cs
2026-07-29 13:12:27 +08:00

345 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
}
}
}