A:PLC 调试页面增加串口设置

This commit is contained in:
jimmy committed 2026-01-21 14:42:45 +08:00
1 parent 4973979169
commit 479eae64a1
5 files changed
+281 -29

No files matched your search

+16 -1
View File
@@ -5,6 +5,7 @@ using Serilog;
using Serilog.Events;
using Serilog.Formatting.Json;
using Sharp.Log.Options;
using System.Text;
namespace Sharp.Log.Internal;
@@ -47,6 +48,7 @@ internal static class SerilogConfigurator
// Sinks
if (options.UseConsole)
{
TrySetConsoleEncoding();
if (options.ConsoleJson)
{
cfg = cfg.WriteTo.Async(a => a.Console(new JsonFormatter(renderMessage: true)));
@@ -94,6 +96,19 @@ internal static class SerilogConfigurator
return cfg.CreateLogger();
}
private static void TrySetConsoleEncoding()
{
try
{
Console.OutputEncoding = Encoding.UTF8;
Console.InputEncoding = Encoding.UTF8;
}
catch
{
// Ignore environments without a console.
}
}
private static LogEventLevel MapLevel(LogLevel level)
{
return level switch
@@ -133,4 +148,4 @@ internal static class SerilogConfigurator
return null;
}
}
}
}
@@ -9,6 +9,7 @@ using Sharp.Wpf.Navigation;
using Sharp.Wpf.Abstractions;
using Plc.Abstractions;
using Plc.Models;
using Plc.Siemens.Options;
namespace Sharp.Demo.ViewModels.Pages;
@@ -20,8 +21,13 @@ public class PlcDebugViewModel : ViewModelBase, INavigationAware
private readonly IPlcService _plcService;
private readonly ILogger<PlcDebugViewModel> _logger;
private readonly IDispatcher _dispatcher;
private readonly SiemensPlcOptions _siemensOptions;
private string _ipAddress = "192.168.1.100";
private PlcBrand _selectedBrand = PlcBrand.Siemens;
private string _siemensIpAddress;
private string _siemensPort;
private string _omronIpAddress = "192.168.1.100";
private string _omronPort = "9600";
private string _status = "未连接";
private string _readAddress = "DB1.DBW0";
private string _readValue = "-";
@@ -36,11 +42,16 @@ public class PlcDebugViewModel : ViewModelBase, INavigationAware
public PlcDebugViewModel(
IPlcService plcService,
ILogger<PlcDebugViewModel> logger,
IDispatcher dispatcher)
IDispatcher dispatcher,
SiemensPlcOptions siemensOptions)
{
_plcService = plcService ?? throw new ArgumentNullException(nameof(plcService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_siemensOptions = siemensOptions ?? throw new ArgumentNullException(nameof(siemensOptions));
_siemensIpAddress = _siemensOptions.IpAddress;
_siemensPort = _siemensOptions.Port.ToString();
// 初始化命令
ConnectCommand = new AsyncCommand(ConnectAsync);
@@ -63,10 +74,62 @@ public class PlcDebugViewModel : ViewModelBase, INavigationAware
#region 属性
public PlcBrand SelectedBrand
{
get => _selectedBrand;
set
{
if (SetProperty(ref _selectedBrand, value))
{
OnPropertyChanged(nameof(IpAddress));
OnPropertyChanged(nameof(Port));
OnPropertyChanged(nameof(IsBrandSupported));
OnPropertyChanged(nameof(SelectedBrandName));
OnPropertyChanged(nameof(SelectedBrandDescription));
}
}
}
public string SelectedBrandName => SelectedBrand switch
{
PlcBrand.Siemens => "西门子",
PlcBrand.Omron => "欧姆龙",
PlcBrand.Mitsubishi => "三菱",
PlcBrand.ModbusTcp => "Modbus TCP",
_ => "未知"
};
public string SelectedBrandDescription => SelectedBrand switch
{
PlcBrand.Siemens => "Sharp.Plc.Siemens - 西门子 PLC 通信驱动 (S7-1200/1500/300/400)",
PlcBrand.Omron => "Sharp.Plc.Omron - 欧姆龙 PLC 通信驱动(规划中)",
_ => "Sharp.Plc - PLC 通信驱动"
};
public bool IsBrandSupported => SelectedBrand == PlcBrand.Siemens;
public string IpAddress
{
get => _ipAddress;
set => SetProperty(ref _ipAddress, value);
get => SelectedBrand == PlcBrand.Siemens ? _siemensIpAddress : _omronIpAddress;
set
{
if (SelectedBrand == PlcBrand.Siemens)
SetProperty(ref _siemensIpAddress, value, nameof(IpAddress));
else
SetProperty(ref _omronIpAddress, value, nameof(IpAddress));
}
}
public string Port
{
get => SelectedBrand == PlcBrand.Siemens ? _siemensPort : _omronPort;
set
{
if (SelectedBrand == PlcBrand.Siemens)
SetProperty(ref _siemensPort, value, nameof(Port));
else
SetProperty(ref _omronPort, value, nameof(Port));
}
}
public string Status
@@ -198,8 +261,21 @@ public class PlcDebugViewModel : ViewModelBase, INavigationAware
{
try
{
if (!IsBrandSupported)
{
Status = "当前品牌暂未支持";
AppendLog($"⚠️ {SelectedBrandName} 驱动尚未实现");
return;
}
if (!TryApplySiemensOptions())
{
Status = "配置错误";
return;
}
Status = "正在连接...";
AppendLog($"正在连接 PLC: {IpAddress}");
AppendLog($"正在连接 PLC ({SelectedBrandName}): {IpAddress}:{Port}");
await _plcService.StartAsync();
@@ -318,6 +394,25 @@ public class PlcDebugViewModel : ViewModelBase, INavigationAware
}
}
private bool TryApplySiemensOptions()
{
if (string.IsNullOrWhiteSpace(IpAddress))
{
AppendLog("❌ IP 地址不能为空");
return false;
}
if (!int.TryParse(Port, out var port) || port < 1 || port > 65535)
{
AppendLog("❌ 端口格式不正确(1-65535)");
return false;
}
_siemensOptions.IpAddress = IpAddress;
_siemensOptions.Port = port;
return true;
}
private void ClearLog()
{
LogText = string.Empty;
@@ -637,4 +732,4 @@ public class WriteQueueItem : ViewModelBase
get => _dataTypeName;
set => SetProperty(ref _dataTypeName, value);
}
}
}
@@ -11,6 +11,7 @@ using Sharp.Wpf.Commands;
using Sharp.Wpf.Abstractions;
using Plc.Abstractions;
using Plc.Models;
using Plc.Siemens.Options;
namespace Sharp.Demo.ViewModels.Windows;
@@ -22,8 +23,13 @@ public class PlcDebugViewModel : ViewModelBase
private readonly IPlcService _plcService;
private readonly ILogger<PlcDebugViewModel> _logger;
private readonly IDispatcher _dispatcher;
private readonly SiemensPlcOptions _siemensOptions;
private string _ipAddress = "192.168.1.100";
private PlcBrand _selectedBrand = PlcBrand.Siemens;
private string _siemensIpAddress;
private string _siemensPort;
private string _omronIpAddress = "192.168.1.100";
private string _omronPort = "9600";
private string _status = "未连接";
private string _readAddress = "DB1.DBW0";
private string _readValue = "-";
@@ -38,11 +44,16 @@ public class PlcDebugViewModel : ViewModelBase
public PlcDebugViewModel(
IPlcService plcService,
ILogger<PlcDebugViewModel> logger,
IDispatcher dispatcher)
IDispatcher dispatcher,
SiemensPlcOptions siemensOptions)
{
_plcService = plcService ?? throw new ArgumentNullException(nameof(plcService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_siemensOptions = siemensOptions ?? throw new ArgumentNullException(nameof(siemensOptions));
_siemensIpAddress = _siemensOptions.IpAddress;
_siemensPort = _siemensOptions.Port.ToString();
// 初始化命令
ConnectCommand = new AsyncCommand(ConnectAsync);
@@ -66,10 +77,54 @@ public class PlcDebugViewModel : ViewModelBase
#region 属性
public PlcBrand SelectedBrand
{
get => _selectedBrand;
set
{
if (SetProperty(ref _selectedBrand, value))
{
OnPropertyChanged(nameof(IpAddress));
OnPropertyChanged(nameof(Port));
OnPropertyChanged(nameof(IsBrandSupported));
OnPropertyChanged(nameof(SelectedBrandName));
}
}
}
public string SelectedBrandName => SelectedBrand switch
{
PlcBrand.Siemens => "西门子",
PlcBrand.Omron => "欧姆龙",
PlcBrand.Mitsubishi => "三菱",
PlcBrand.ModbusTcp => "Modbus TCP",
_ => "未知"
};
public bool IsBrandSupported => SelectedBrand == PlcBrand.Siemens;
public string IpAddress
{
get => _ipAddress;
set => SetProperty(ref _ipAddress, value);
get => SelectedBrand == PlcBrand.Siemens ? _siemensIpAddress : _omronIpAddress;
set
{
if (SelectedBrand == PlcBrand.Siemens)
SetProperty(ref _siemensIpAddress, value, nameof(IpAddress));
else
SetProperty(ref _omronIpAddress, value, nameof(IpAddress));
}
}
public string Port
{
get => SelectedBrand == PlcBrand.Siemens ? _siemensPort : _omronPort;
set
{
if (SelectedBrand == PlcBrand.Siemens)
SetProperty(ref _siemensPort, value, nameof(Port));
else
SetProperty(ref _omronPort, value, nameof(Port));
}
}
public string Status
@@ -187,8 +242,21 @@ public class PlcDebugViewModel : ViewModelBase
{
try
{
if (!IsBrandSupported)
{
Status = "当前品牌暂未支持";
AppendLog($"⚠️ {SelectedBrandName} 驱动尚未实现");
return;
}
if (!TryApplySiemensOptions())
{
Status = "配置错误";
return;
}
Status = "正在连接...";
AppendLog($"正在连接 PLC: {IpAddress}");
AppendLog($"正在连接 PLC ({SelectedBrandName}): {IpAddress}:{Port}");
await _plcService.StartAsync();
@@ -307,6 +375,25 @@ public class PlcDebugViewModel : ViewModelBase
}
}
private bool TryApplySiemensOptions()
{
if (string.IsNullOrWhiteSpace(IpAddress))
{
AppendLog("❌ IP 地址不能为空");
return false;
}
if (!int.TryParse(Port, out var port) || port < 1 || port > 65535)
{
AppendLog("❌ 端口格式不正确(1-65535)");
return false;
}
_siemensOptions.IpAddress = IpAddress;
_siemensOptions.Port = port;
return true;
}
private void AppendLog(string message)
{
var timestamp = DateTime.Now.ToString("HH:mm:ss");
@@ -864,4 +951,4 @@ public class WriteQueueItem : ViewModelBase
get => _verify;
set => SetProperty(ref _verify, value);
}
}
}
@@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:plc="clr-namespace:Plc.Models;assembly=Plc"
mc:Ignorable="d"
d:DesignHeight="1000"
d:DesignWidth="1200">
@@ -18,7 +19,7 @@
Margin="0,10,0,30"
FontSize="14"
Foreground="{DynamicResource SecondaryTextBrush}"
Text="Sharp.Plc.Siemens - 西门子 PLC 通信驱动 (S7-1200/1500/300/400)" />
Text="{Binding SelectedBrandDescription}" />
<!-- 连接控制 -->
<Border
@@ -31,11 +32,40 @@
<StackPanel>
<TextBlock Text="PLC 连接" FontSize="16" FontWeight="Bold" Margin="0,0,0,10" />
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="IP 地址:" VerticalAlignment="Center" Margin="0,0,10,0" Width="80" />
<TextBox Text="{Binding IpAddress}" Width="200" Height="32" Padding="8,0"
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1" />
</StackPanel>
<TabControl SelectedValue="{Binding SelectedBrand}" SelectedValuePath="Tag" Margin="0,0,0,10">
<TabItem Header="西门子" Tag="{x:Static plc:PlcBrand.Siemens}">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="IP 地址:" VerticalAlignment="Center" Margin="0,0,10,0"
Width="80" />
<TextBox Text="{Binding IpAddress}" Width="200" Height="32" Padding="8,0"
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1" />
<TextBlock Text="端口:" VerticalAlignment="Center" Margin="15,0,10,0" Width="50" />
<TextBox Text="{Binding Port}" Width="100" Height="32" Padding="8,0"
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1" />
</StackPanel>
<TextBlock Text="S7-1200/1500/300/400,默认端口 102"
Foreground="{DynamicResource SecondaryTextBrush}"
FontSize="12" />
</StackPanel>
</TabItem>
<TabItem Header="欧姆龙" Tag="{x:Static plc:PlcBrand.Omron}">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="IP 地址:" VerticalAlignment="Center" Margin="0,0,10,0"
Width="80" />
<TextBox Text="{Binding IpAddress}" Width="200" Height="32" Padding="8,0"
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1" />
<TextBlock Text="端口:" VerticalAlignment="Center" Margin="15,0,10,0" Width="50" />
<TextBox Text="{Binding Port}" Width="100" Height="32" Padding="8,0"
BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1" />
</StackPanel>
<TextBlock Text="欧姆龙驱动尚未实现,后续可按品牌扩展配置项"
Foreground="{DynamicResource SecondaryTextBrush}"
FontSize="12" />
</StackPanel>
</TabItem>
</TabControl>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="状态:" VerticalAlignment="Center" Margin="0,0,10,0" Width="80" />
@@ -45,10 +75,12 @@
<StackPanel Orientation="Horizontal">
<Button Content="连接" Width="100" Height="35" Margin="0,0,10,0"
Command="{Binding ConnectCommand}"
Style="{StaticResource ButtonSuccess}" />
Style="{StaticResource ButtonSuccess}"
IsEnabled="{Binding IsBrandSupported}" />
<Button Content="断开" Width="100" Height="35"
Command="{Binding DisconnectCommand}"
Style="{StaticResource ButtonDanger}" />
Style="{StaticResource ButtonDanger}"
IsEnabled="{Binding IsBrandSupported}" />
</StackPanel>
</StackPanel>
</Border>
@@ -296,4 +328,4 @@
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>
</UserControl>
@@ -4,6 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:plc="clr-namespace:Plc.Models;assembly=Plc"
mc:Ignorable="d"
Title="PLC 调试工具"
Height="800"
@@ -23,16 +24,38 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="IP 地址:" VerticalAlignment="Center" Margin="0,0,10,0" />
<TextBox Text="{Binding IpAddress}" Width="150" Height="28" Margin="0,0,10,0" />
<TabControl Grid.Row="0" SelectedValue="{Binding SelectedBrand}" SelectedValuePath="Tag"
Margin="0,0,0,10">
<TabItem Header="西门子" Tag="{x:Static plc:PlcBrand.Siemens}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="IP 地址:" VerticalAlignment="Center" Margin="0,0,10,0" />
<TextBox Text="{Binding IpAddress}" Width="150" Height="28" Margin="0,0,10,0" />
<TextBlock Text="端口:" VerticalAlignment="Center" Margin="10,0,10,0" />
<TextBox Text="{Binding Port}" Width="80" Height="28" Margin="0,0,10,0" />
</StackPanel>
</TabItem>
<TabItem Header="欧姆龙" Tag="{x:Static plc:PlcBrand.Omron}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="IP 地址:" VerticalAlignment="Center" Margin="0,0,10,0" />
<TextBox Text="{Binding IpAddress}" Width="150" Height="28" Margin="0,0,10,0" />
<TextBlock Text="端口:" VerticalAlignment="Center" Margin="10,0,10,0" />
<TextBox Text="{Binding Port}" Width="80" Height="28" Margin="0,0,10,0" />
<TextBlock Text="驱动未实现" VerticalAlignment="Center"
Foreground="{DynamicResource SecondaryTextBrush}" />
</StackPanel>
</TabItem>
</TabControl>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Content="🔗 连接" Width="90" Height="32" Margin="0,0,10,0"
Command="{Binding ConnectCommand}" Style="{StaticResource ButtonSuccess}" />
Command="{Binding ConnectCommand}" Style="{StaticResource ButtonSuccess}"
IsEnabled="{Binding IsBrandSupported}" />
<Button Content="🔌 断开" Width="90" Height="32" Margin="0,0,10,0"
Command="{Binding DisconnectCommand}" Style="{StaticResource ButtonDanger}" />
Command="{Binding DisconnectCommand}" Style="{StaticResource ButtonDanger}"
IsEnabled="{Binding IsBrandSupported}" />
<Separator Margin="10,0" />
@@ -42,7 +65,7 @@
</StackPanel>
<!-- 最新日志 -->
<TextBlock Grid.Row="1" Text="{Binding LastLogMessage}"
<TextBlock Grid.Row="2" Text="{Binding LastLogMessage}"
Foreground="{DynamicResource SecondaryTextBrush}"
FontSize="11" Margin="0,5,0,0" TextTrimming="CharacterEllipsis" />
</Grid>
@@ -318,4 +341,4 @@
</TabItem>
</TabControl>
</Grid>
</Window>
</Window>