273 lines
9.0 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|