Files
XplorePlane/XP.Hardware.PLC.Sentry/ViewModels/SignalDataDemoViewModel.cs
T

273 lines
9.0 KiB
C#

using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Prism.Commands;
using Prism.Mvvm;
using XP.Common.Logging.Interfaces;
using XP.Hardware.Plc.Abstractions;
using XP.Hardware.Plc.Exceptions;
using XP.Hardware.Plc.Services;
using XP.Hardware.PLC.Configs;
namespace XP.App.ViewModels
{
/// <summary>
/// 信号数据服务 DEMO 窗口 ViewModel
/// </summary>
public class SignalDataDemoViewModel : BindableBase
{
private readonly PlcService _plcService;
private readonly ISignalDataService _signalService;
private readonly ConfigLoader _configLoader;
private readonly ILoggerService _logger;
// 日志
public ObservableCollection<string> LogEntries { get; } = new();
// 连接状态
public bool IsConnected => _plcService.IsConnected;
public string StatusText => _plcService.StatusText;
private bool _isInitialized;
public bool IsInitialized
{
get => _isInitialized;
set => SetProperty(ref _isInitialized, value);
}
// 缓存读取
private string _readSignalName = "";
public string ReadSignalName
{
get => _readSignalName;
set => SetProperty(ref _readSignalName, value);
}
private string _readResult = "";
public string ReadResult
{
get => _readResult;
set => SetProperty(ref _readResult, value);
}
// 队列写入
private string _queueSignalName = "";
public string QueueSignalName
{
get => _queueSignalName;
set => SetProperty(ref _queueSignalName, value);
}
private string _queueWriteValue = "";
public string QueueWriteValue
{
get => _queueWriteValue;
set => SetProperty(ref _queueWriteValue, value);
}
// 直接写入+回读校验
private string _directSignalName = "";
public string DirectSignalName
{
get => _directSignalName;
set => SetProperty(ref _directSignalName, value);
}
private string _directWriteValue = "";
public string DirectWriteValue
{
get => _directWriteValue;
set => SetProperty(ref _directWriteValue, value);
}
// 信号定义文件路径
private string _xmlFilePath = "PlcAddrDfn.xml";
public string XmlFilePath
{
get => _xmlFilePath;
set => SetProperty(ref _xmlFilePath, value);
}
// 命令
public DelegateCommand ConnectAndLoadCommand { get; }
public DelegateCommand CacheReadCommand { get; }
public DelegateCommand QueueWriteCommand { get; }
public DelegateCommand DirectWriteCommand { get; }
public DelegateCommand ClearLogCommand { get; }
public SignalDataDemoViewModel(
PlcService plcService,
ISignalDataService signalService,
ConfigLoader configLoader,
ILoggerService logger)
{
_plcService = plcService ?? throw new ArgumentNullException(nameof(plcService));
_signalService = signalService ?? throw new ArgumentNullException(nameof(signalService));
_configLoader = configLoader ?? throw new ArgumentNullException(nameof(configLoader));
_logger = logger?.ForModule<SignalDataDemoViewModel>() ?? throw new ArgumentNullException(nameof(logger));
_plcService.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(PlcService.IsConnected))
RaisePropertyChanged(nameof(IsConnected));
else if (e.PropertyName == nameof(PlcService.StatusText))
RaisePropertyChanged(nameof(StatusText));
};
ConnectAndLoadCommand = new DelegateCommand(async () => await ConnectAndLoadAsync());
CacheReadCommand = new DelegateCommand(CacheRead);
QueueWriteCommand = new DelegateCommand(QueueWrite);
DirectWriteCommand = new DelegateCommand(async () => await DirectWriteAsync());
ClearLogCommand = new DelegateCommand(() => LogEntries.Clear());
}
private void Log(string msg)
{
var text = $"[{DateTime.Now:HH:mm:ss.fff}] {msg}";
LogEntries.Add(text);
}
/// <summary>
/// 连接 PLC 并加载信号定义
/// </summary>
private async Task ConnectAndLoadAsync()
{
try
{
Log("正在加载配置...");
var config = _configLoader.LoadPlcConfig();
Log($"配置加载成功: {config.IpAddress}:{config.Port}, DB读={config.ReadDbBlock}");
Log("正在连接 PLC...");
var result = await _plcService.InitializeAsync(config);
if (!result)
{
Log("ERROR: PLC 连接失败");
return;
}
Log("PLC 连接成功");
Log($"正在加载信号定义: {XmlFilePath}");
_plcService.LoadSignalDefinitions(XmlFilePath);
Log("信号定义加载成功");
IsInitialized = true;
}
catch (Exception ex)
{
Log($"ERROR: {ex.Message}");
}
}
/// <summary>
/// 缓存读取
/// </summary>
private void CacheRead()
{
if (string.IsNullOrWhiteSpace(ReadSignalName))
{
Log("ERROR: 请输入信号名称");
return;
}
try
{
var value = _signalService.GetValueByName(ReadSignalName);
ReadResult = value?.ToString() ?? "null";
Log($"缓存读取成功: {ReadSignalName} = {ReadResult} (类型: {value?.GetType().Name ?? "null"})");
}
catch (PlcException ex)
{
ReadResult = "ERROR";
Log($"ERROR: 缓存读取失败 - {ex.Message}");
}
catch (Exception ex)
{
ReadResult = "ERROR";
Log($"ERROR: {ex.Message}");
}
}
/// <summary>
/// 队列写入
/// </summary>
private void QueueWrite()
{
if (string.IsNullOrWhiteSpace(QueueSignalName))
{
Log("ERROR: 请输入信号名称");
return;
}
if (string.IsNullOrWhiteSpace(QueueWriteValue))
{
Log("ERROR: 请输入写入值");
return;
}
try
{
// 尝试解析为数值,否则作为字符串
object value = ParseInputValue(QueueWriteValue);
bool enqueued = _signalService.EnqueueWrite(QueueSignalName, value);
Log(enqueued
? $"队列写入成功: {QueueSignalName} = {QueueWriteValue}"
: $"WARN: 队列写入返回 false(队列未运行或已满): {QueueSignalName}");
}
catch (PlcException ex)
{
Log($"ERROR: 队列写入失败 - {ex.Message}");
}
catch (Exception ex)
{
Log($"ERROR: {ex.Message}");
}
}
/// <summary>
/// 直接写入+回读校验
/// </summary>
private async Task DirectWriteAsync()
{
if (string.IsNullOrWhiteSpace(DirectSignalName))
{
Log("ERROR: 请输入信号名称");
return;
}
if (string.IsNullOrWhiteSpace(DirectWriteValue))
{
Log("ERROR: 请输入写入值");
return;
}
try
{
object value = ParseInputValue(DirectWriteValue);
Log($"正在直接写入: {DirectSignalName} = {DirectWriteValue}...");
bool verified = await _signalService.WriteDirectWithVerify(DirectSignalName, value);
Log(verified
? $"直接写入校验通过: {DirectSignalName} = {DirectWriteValue}"
: $"WARN: 直接写入校验失败: {DirectSignalName} = {DirectWriteValue}");
}
catch (PlcException ex)
{
Log($"ERROR: 直接写入失败 - {ex.Message}");
}
catch (Exception ex)
{
Log($"ERROR: {ex.Message}");
}
}
/// <summary>
/// 解析用户输入值:尝试 bool → int → double → string
/// </summary>
private object ParseInputValue(string input)
{
if (bool.TryParse(input, out bool bVal)) return bVal;
if (int.TryParse(input, out int iVal)) return iVal;
if (double.TryParse(input, out double dVal)) return dVal;
return input;
}
}
}