报文设置扩展
This commit is contained in:
7
ADP.sln
7
ADP.sln
@@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZLGUSBCANFD", "ZLGUSBCANFD\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchMovementModule", "BenchMovementModule\BenchMovementModule.csproj", "{31F84D0E-3634-4C70-A830-21AF412E3BBF}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchMovementModule", "BenchMovementModule\BenchMovementModule.csproj", "{31F84D0E-3634-4C70-A830-21AF412E3BBF}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CANModule", "CANModule\CANModule.csproj", "{AF2533DD-599D-49D7-942B-B0C26534D15F}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -119,6 +121,10 @@ Global
|
|||||||
{31F84D0E-3634-4C70-A830-21AF412E3BBF}.Debug|Any CPU.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{31F84D0E-3634-4C70-A830-21AF412E3BBF}.Release|Any CPU.Build.0 = 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
|
||||||
|
{AF2533DD-599D-49D7-942B-B0C26534D15F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -132,5 +138,6 @@ Global
|
|||||||
{850A5BE8-0BC1-4D6A-8351-DD812C9C4427} = {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}
|
{170AD4C1-189D-4FBE-B10D-2A4304527834} = {1E92D601-68FC-45F6-8251-BD0F39226E5B}
|
||||||
{31F84D0E-3634-4C70-A830-21AF412E3BBF} = {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}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\BenchMovementModule\BenchMovementModule.csproj" />
|
<ProjectReference Include="..\BenchMovementModule\BenchMovementModule.csproj" />
|
||||||
|
<ProjectReference Include="..\CANModule\CANModule.csproj" />
|
||||||
<ProjectReference Include="..\Command\Command.csproj" />
|
<ProjectReference Include="..\Command\Command.csproj" />
|
||||||
<ProjectReference Include="..\DeviceCommand\DeviceCommand.csproj" />
|
<ProjectReference Include="..\DeviceCommand\DeviceCommand.csproj" />
|
||||||
<ProjectReference Include="..\DeviceEditModule\DeviceEditModule.csproj" />
|
<ProjectReference Include="..\DeviceEditModule\DeviceEditModule.csproj" />
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace ADP.ViewModels
|
|||||||
|
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
private readonly IRegionManager _regionManager;
|
private readonly IRegionManager _regionManager;
|
||||||
|
private readonly IDialogService _dialogService;
|
||||||
private readonly IContainerProvider _containerProvider;
|
private readonly IContainerProvider _containerProvider;
|
||||||
private readonly INotificationManager _notificationManager;
|
private readonly INotificationManager _notificationManager;
|
||||||
private readonly IModuleManager _moduleManager;
|
private readonly IModuleManager _moduleManager;
|
||||||
@@ -145,11 +146,13 @@ namespace ADP.ViewModels
|
|||||||
public ICommand NewCommand { get; set; }
|
public ICommand NewCommand { get; set; }
|
||||||
public ICommand SetDefaultCommand { get; set; }
|
public ICommand SetDefaultCommand { get; set; }
|
||||||
public ICommand ShowDialogManagerViewCommand { get; set; }
|
public ICommand ShowDialogManagerViewCommand { get; set; }
|
||||||
|
public ICommand SelectCANMessageCommand { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public ShellViewModel(IContainerProvider containerProvider)
|
public ShellViewModel(IContainerProvider containerProvider)
|
||||||
{
|
{
|
||||||
_containerProvider = containerProvider;
|
_containerProvider = containerProvider;
|
||||||
|
_dialogService= containerProvider.Resolve<IDialogService>();
|
||||||
_globalInfo = containerProvider.Resolve<GlobalInfo>();
|
_globalInfo = containerProvider.Resolve<GlobalInfo>();
|
||||||
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
|
||||||
_regionManager = containerProvider.Resolve<IRegionManager>();
|
_regionManager = containerProvider.Resolve<IRegionManager>();
|
||||||
@@ -173,6 +176,7 @@ namespace ADP.ViewModels
|
|||||||
SaveAsCommand = new DelegateCommand(SaveAs);
|
SaveAsCommand = new DelegateCommand(SaveAs);
|
||||||
SaveCommand = new DelegateCommand(Save);
|
SaveCommand = new DelegateCommand(Save);
|
||||||
SetDefaultCommand = new DelegateCommand(SetDefault);
|
SetDefaultCommand = new DelegateCommand(SetDefault);
|
||||||
|
SelectCANMessageCommand = new DelegateCommand(SelectCANMessage);
|
||||||
|
|
||||||
_globalInfo.ContextDic.Add("default", new ScopedContext());
|
_globalInfo.ContextDic.Add("default", new ScopedContext());
|
||||||
|
|
||||||
@@ -196,7 +200,6 @@ namespace ADP.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void RefreshAllContextProperties()
|
private void RefreshAllContextProperties()
|
||||||
{
|
{
|
||||||
RaisePropertyChanged(nameof(RunState));
|
RaisePropertyChanged(nameof(RunState));
|
||||||
@@ -207,6 +210,11 @@ namespace ADP.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region 命令处理与事件
|
#region 命令处理与事件
|
||||||
|
private void SelectCANMessage()
|
||||||
|
{
|
||||||
|
_dialogService.ShowDialog("SelectCanMessageView");
|
||||||
|
}
|
||||||
|
|
||||||
private void ShowDialogManagerView()
|
private void ShowDialogManagerView()
|
||||||
{
|
{
|
||||||
_eventAggregator.GetEvent<CancelMinimizeEvent>().Publish();
|
_eventAggregator.GetEvent<CancelMinimizeEvent>().Publish();
|
||||||
|
|||||||
@@ -159,6 +159,16 @@
|
|||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
||||||
|
<!-- CAN报文选择 -->
|
||||||
|
<MenuItem Header="CAN报文选择"
|
||||||
|
Foreground="Black"
|
||||||
|
Command="{Binding SelectCANMessageCommand}">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<materialDesign:PackIcon Kind="Message"
|
||||||
|
Foreground="Black" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
<!-- 蜂鸣器消音 -->
|
<!-- 蜂鸣器消音 -->
|
||||||
<MenuItem Header="弹窗管理器"
|
<MenuItem Header="弹窗管理器"
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
|
|||||||
14
CANModule/CANModule.csproj
Normal file
14
CANModule/CANModule.csproj
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<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>
|
||||||
17
CANModule/UpdateInfoModule.cs
Normal file
17
CANModule/UpdateInfoModule.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using CANModule.Views;
|
||||||
|
|
||||||
|
namespace CANModule
|
||||||
|
{
|
||||||
|
public class CANModule : IModule
|
||||||
|
{
|
||||||
|
public void OnInitialized(IContainerProvider containerProvider)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterTypes(IContainerRegistry containerRegistry)
|
||||||
|
{
|
||||||
|
containerRegistry.RegisterDialog<SelectCanMessageView>("SelectCanMessageView");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
171
CANModule/ViewModels/SelectCanMessageViewModel.cs
Normal file
171
CANModule/ViewModels/SelectCanMessageViewModel.cs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using UIShare.ViewModelBase;
|
||||||
|
using ZLGUSBCANFD;
|
||||||
|
|
||||||
|
namespace CANModule.ViewModels
|
||||||
|
{
|
||||||
|
public class SelectCanMessageViewModel : DialogViewModelBase
|
||||||
|
{
|
||||||
|
#region 属性
|
||||||
|
public DialogCloseListener RequestClose { get; set; }
|
||||||
|
|
||||||
|
private ObservableCollection<int> _ChannelList;
|
||||||
|
public ObservableCollection<int> ChannelList
|
||||||
|
{
|
||||||
|
get => _ChannelList;
|
||||||
|
set => SetProperty(ref _ChannelList, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObservableCollection<string> _messageList;
|
||||||
|
public ObservableCollection<string> MessageList
|
||||||
|
{
|
||||||
|
get => _messageList;
|
||||||
|
set => SetProperty(ref _messageList, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObservableCollection<string> _signalList;
|
||||||
|
public ObservableCollection<string> SignalList
|
||||||
|
{
|
||||||
|
get => _signalList;
|
||||||
|
set => SetProperty(ref _signalList, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _title = "CollectCANSignalSetting";
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get => _title;
|
||||||
|
set => SetProperty(ref _title, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _selectedMessage;
|
||||||
|
public string SelectedMessage
|
||||||
|
{
|
||||||
|
get => _selectedMessage;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _selectedMessage, value))
|
||||||
|
{
|
||||||
|
// 健壮性检查:防范切换通道时清空选择引发的连锁 Bug
|
||||||
|
if (!string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
// 使用 FirstOrDefault 代替 First,防止找不到匹配项时导致上位机崩溃
|
||||||
|
var targetMsg = ZLGDBCParser.MsgDatabase[MessageChannel]
|
||||||
|
.FirstOrDefault(x => $"[0x{x.msg_id:X}]{x.msg_name}" == value);
|
||||||
|
|
||||||
|
if (targetMsg != null && targetMsg.signal_Name != null)
|
||||||
|
{
|
||||||
|
SignalList = new ObservableCollection<string>(targetMsg.signal_Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SignalList = new ObservableCollection<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SignalList = new ObservableCollection<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _selectedSignal;
|
||||||
|
public string SelectedSignal
|
||||||
|
{
|
||||||
|
get => _selectedSignal;
|
||||||
|
set => SetProperty(ref _selectedSignal, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _MessageChannel=-1;
|
||||||
|
public int MessageChannel
|
||||||
|
{
|
||||||
|
get => _MessageChannel;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_MessageChannel != value)
|
||||||
|
{
|
||||||
|
_MessageChannel = value;
|
||||||
|
|
||||||
|
// 1. 先安全清空旧的选择项和信号列表,断开引用链
|
||||||
|
SelectedMessage = null;
|
||||||
|
SelectedSignal = null;
|
||||||
|
SignalList = new ObservableCollection<string>();
|
||||||
|
|
||||||
|
// 2. 刷新当前通道的报文列表
|
||||||
|
if (ZLGDBCParser.MsgDatabase != null && ZLGDBCParser.MsgDatabase.Count > value)
|
||||||
|
{
|
||||||
|
MessageList = new ObservableCollection<string>(
|
||||||
|
ZLGDBCParser.MsgDatabase[value].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageList = new ObservableCollection<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
RaisePropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 命令
|
||||||
|
public ICommand CloseCommand { get; set; }
|
||||||
|
public ICommand GetSelectedMessageCommand { get; set; }
|
||||||
|
public ICommand GetSelectedSignalCommand { get; set; }
|
||||||
|
public ICommand LoadCommand { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public SelectCanMessageViewModel(IContainerProvider containerProvider) : base(containerProvider)
|
||||||
|
{
|
||||||
|
CloseCommand = new DelegateCommand(Close);
|
||||||
|
GetSelectedMessageCommand = new DelegateCommand(GetSelectedMessage);
|
||||||
|
GetSelectedSignalCommand = new DelegateCommand(GetSelectedSignal);
|
||||||
|
LoadCommand = new DelegateCommand(Load);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 命令处理
|
||||||
|
private void Close()
|
||||||
|
{
|
||||||
|
RequestClose.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Load()
|
||||||
|
{
|
||||||
|
ChannelList = new ObservableCollection<int>(Enumerable.Range(0, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetSelectedSignal()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(SelectedSignal))
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
Clipboard.SetDataObject(SelectedSignal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetSelectedMessage()
|
||||||
|
{
|
||||||
|
// 修复原本误写为 SelectedSignal != null 的 Bug,并增加了边界防错
|
||||||
|
if (!string.IsNullOrEmpty(SelectedMessage) && SelectedMessage.Contains(']'))
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
Clipboard.SetDataObject(SelectedMessage);
|
||||||
|
//var parts = SelectedMessage.Split(']');
|
||||||
|
//if (parts.Length > 1)
|
||||||
|
//{
|
||||||
|
// Clipboard.SetDataObject(parts[1]); // 复制纯报文名称(如:"EngineStatus")
|
||||||
|
//}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
69
CANModule/Views/SelectCanMessageView.xaml
Normal file
69
CANModule/Views/SelectCanMessageView.xaml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<UserControl x:Class="CANModule.Views.SelectCanMessageView"
|
||||||
|
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:local="clr-namespace:CANModule.Views"
|
||||||
|
xmlns:oxy="http://oxyplot.org/wpf"
|
||||||
|
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
xmlns:prism="http://prismlibrary.com/"
|
||||||
|
xmlns:cons="clr-namespace:UIShare.Converters;assembly=UIShare"
|
||||||
|
Background="White"
|
||||||
|
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||||
|
Height="350"
|
||||||
|
Width="350">
|
||||||
|
<prism:Dialog.WindowStyle>
|
||||||
|
<Style BasedOn="{StaticResource DialogUserManageStyle}"
|
||||||
|
TargetType="Window" />
|
||||||
|
</prism:Dialog.WindowStyle>
|
||||||
|
<i:Interaction.Triggers>
|
||||||
|
<i:EventTrigger EventName="Loaded">
|
||||||
|
<i:InvokeCommandAction Command="{Binding LoadCommand}" />
|
||||||
|
</i:EventTrigger>
|
||||||
|
</i:Interaction.Triggers>
|
||||||
|
<GroupBox Padding="0,0,0,0"
|
||||||
|
MouseLeftButtonDown="MouseLeftButtonDown">
|
||||||
|
<GroupBox.Header>
|
||||||
|
<Grid Margin="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Text="CAN报文选择"
|
||||||
|
Foreground="White"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="5,0,10,0" />
|
||||||
|
<Button Content="关闭"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="0 0 0 0"
|
||||||
|
Width="60"
|
||||||
|
Command="{Binding CloseCommand}"
|
||||||
|
Height="25" />
|
||||||
|
</Grid>
|
||||||
|
</GroupBox.Header>
|
||||||
|
<Grid>
|
||||||
|
<StackPanel Grid.Row="1" Margin="10">
|
||||||
|
<Label Content="通道" VerticalAlignment="Center"/>
|
||||||
|
<ComboBox ItemsSource="{Binding ChannelList}"
|
||||||
|
SelectedItem="{Binding MessageChannel,Mode=TwoWay}"
|
||||||
|
MinWidth="100"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
materialDesign:HintAssist.Hint="" />
|
||||||
|
<Label Content="报文" VerticalAlignment="Center"/>
|
||||||
|
<ComboBox materialDesign:HintAssist.Hint=""
|
||||||
|
MinWidth="100"
|
||||||
|
SelectedItem="{Binding SelectedMessage,Mode=TwoWay}"
|
||||||
|
ItemsSource="{Binding MessageList}" />
|
||||||
|
<Label Content="信号" VerticalAlignment="Center"/>
|
||||||
|
<ComboBox materialDesign:HintAssist.Hint=""
|
||||||
|
SelectedItem="{Binding SelectedSignal,Mode=TwoWay}"
|
||||||
|
ItemsSource="{Binding SignalList}" MinWidth="100" />
|
||||||
|
<Button Content="选择报文名" Margin="10" Command="{Binding GetSelectedMessageCommand}"/>
|
||||||
|
<Button Content="选择信号名" Margin="10" Command="{Binding GetSelectedSignalCommand}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
|
</UserControl>
|
||||||
36
CANModule/Views/SelectCanMessageView.xaml.cs
Normal file
36
CANModule/Views/SelectCanMessageView.xaml.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
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 CANModule.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// SelectCanMessageView.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class SelectCanMessageView : UserControl
|
||||||
|
{
|
||||||
|
public SelectCanMessageView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.LeftButton == MouseButtonState.Pressed)
|
||||||
|
{
|
||||||
|
Window.GetWindow(this)?.DragMove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -153,7 +153,6 @@ namespace MonitorModule.ViewModels
|
|||||||
try { _dbFlushTask.Wait(TimeSpan.FromSeconds(1.5)); } catch { }
|
try { _dbFlushTask.Wait(TimeSpan.FromSeconds(1.5)); } catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
_sampleTimer.Tick -= OnSampleTick;
|
|
||||||
|
|
||||||
// 3. 释放容器作用域
|
// 3. 释放容器作用域
|
||||||
_scope?.Dispose();
|
_scope?.Dispose();
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ namespace ZLGUSBCANFD
|
|||||||
{
|
{
|
||||||
_dbcHandles[通道号] = chDbcHandle;
|
_dbcHandles[通道号] = chDbcHandle;
|
||||||
_isDbcLoadedArray[通道号] = true;
|
_isDbcLoadedArray[通道号] = true;
|
||||||
|
ZLGDBCParser.ParseAndLoadToDatabase(chDbcHandle, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -507,20 +508,25 @@ namespace ZLGUSBCANFD
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 4.1 仿同星高性能智能报文/信号控制流 (新增扩展)
|
#region 4.1 报文设置与发送 (支持智能进制转换)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置并发送指定信号值。
|
/// 设置并发送指定信号值(帧 ID 支持 string 兼容模式)。
|
||||||
/// 其余未指定信号使用 DBC 中定义的初始值填充,避免总线数据被意外清零。
|
/// 其余未指定信号使用 DBC 中定义的初始值填充,避免总线数据被意外清零。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="通道号">CAN/CANFD 通道索引</param>
|
/// <param name="通道号">CAN/CANFD 通道索引</param>
|
||||||
/// <param name="帧ID">对应报文的帧 ID</param>
|
/// <param name="帧IDStr">对应报文的帧 ID(可以是 "26"、"0x1A"、"1A")</param>
|
||||||
/// <param name="信号名称">DBC 中定义的英文信号名称(不区分大小写)</param>
|
/// <param name="信号名称">DBC 中定义的英文信号名称(不区分大小写)</param>
|
||||||
/// <param name="物理值">要写入的实际物理数值</param>
|
/// <param name="物理值">要写入的实际物理数值</param>
|
||||||
/// <param name="循环发送间隔毫秒">0 = 单次发送;>0 = 周期循环发送(单位毫秒)</param>
|
/// <param name="循环发送间隔毫秒">0 = 单次发送;>0 = 周期循环发送(单位毫秒)</param>
|
||||||
/// <returns>操作是否成功</returns>
|
/// <returns>操作是否成功</returns>
|
||||||
public virtual bool 设置报文(uint 通道号, uint 帧ID, string 信号名称, double 物理值, int 循环发送间隔毫秒 = 0)
|
public virtual bool 设置报文(uint 通道号, string 帧IDStr, string 信号名称, double 物理值, int 循环发送间隔毫秒 = 0)
|
||||||
{
|
{
|
||||||
|
if (!TryParseFrameId(帧IDStr, out uint 帧ID))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[ZLGCANFD] 设置报文失败: 无法解析的帧 ID '{帧IDStr}'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
|
if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
|
||||||
if (!_isDbcLoadedArray[通道号]) return false;
|
if (!_isDbcLoadedArray[通道号]) return false;
|
||||||
if (string.IsNullOrWhiteSpace(信号名称)) return false;
|
if (string.IsNullOrWhiteSpace(信号名称)) return false;
|
||||||
@@ -534,15 +540,21 @@ namespace ZLGUSBCANFD
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送报文:以 DBC 中所有信号的初始值作为默认值发送。
|
/// 发送报文:以 DBC 中所有信号的初始值作为默认值发送(帧 ID 支持 string 兼容模式)。
|
||||||
/// 如果之前调用 设置报文 保存过覆盖值,则会优先使用覆盖值。
|
/// 如果之前调用 设置报文 保存过覆盖值,则会优先使用覆盖值。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="通道号">CAN/CANFD 通道索引</param>
|
/// <param name="通道号">CAN/CANFD 通道索引</param>
|
||||||
/// <param name="帧ID">DBC 中定义的帧 ID</param>
|
/// <param name="帧IDStr">DBC 中定义的帧 ID(可以是 "26"、"0x1A"、"1A")</param>
|
||||||
/// <param name="循环发送间隔毫秒">0 = 单次发送;>0 = 周期循环发送(毫秒)</param>
|
/// <param name="循环发送间隔毫秒">0 = 单次发送;>0 = 周期循环发送(毫秒)</param>
|
||||||
/// <param name="是否使用CANFD">1 = 以 CANFD 格式发送;0 = 经典 CAN 格式</param>
|
/// <param name="是否使用CANFD">1 = 以 CANFD 格式发送;0 = 经典 CAN 格式</param>
|
||||||
public virtual bool 发送报文(uint 通道号, uint 帧ID, int 循环发送间隔毫秒 = 0, int 是否使用CANFD = 1)
|
public virtual bool 发送报文(uint 通道号, string 帧IDStr, int 循环发送间隔毫秒 = 0, int 是否使用CANFD = 1)
|
||||||
{
|
{
|
||||||
|
if (!TryParseFrameId(帧IDStr, out uint 帧ID))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[ZLGCANFD] 发送报文失败: 无法解析的帧 ID '{帧IDStr}'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
|
if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
|
||||||
if (!_isDbcLoadedArray[通道号]) return false;
|
if (!_isDbcLoadedArray[通道号]) return false;
|
||||||
if (循环发送间隔毫秒 < 0) throw new ArgumentOutOfRangeException(nameof(循环发送间隔毫秒));
|
if (循环发送间隔毫秒 < 0) throw new ArgumentOutOfRangeException(nameof(循环发送间隔毫秒));
|
||||||
@@ -552,10 +564,10 @@ namespace ZLGUSBCANFD
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送自定义报文(原始字节)。
|
/// 发送自定义报文(原始字节,帧 ID 支持 string 兼容模式)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="通道号">CAN/CANFD 通道索引</param>
|
/// <param name="通道号">CAN/CANFD 通道索引</param>
|
||||||
/// <param name="帧ID">帧 ID;扩展帧会自动置位 0x80000000</param>
|
/// <param name="帧IDStr">帧 ID(可以是 "26"、"0x1A"、"1A");扩展帧会自动置位 0x80000000</param>
|
||||||
/// <param name="原始数据">原始帧数据</param>
|
/// <param name="原始数据">原始帧数据</param>
|
||||||
/// <param name="dlcLength">数据长度;CANFD 仅允许 0-8,12,16,20,24,32,48,64</param>
|
/// <param name="dlcLength">数据长度;CANFD 仅允许 0-8,12,16,20,24,32,48,64</param>
|
||||||
/// <param name="是否是扩展帧">是否为 29 位扩展帧</param>
|
/// <param name="是否是扩展帧">是否为 29 位扩展帧</param>
|
||||||
@@ -563,13 +575,19 @@ namespace ZLGUSBCANFD
|
|||||||
/// <param name="开启波特率加速BRS">CANFD 是否开启波特率加速</param>
|
/// <param name="开启波特率加速BRS">CANFD 是否开启波特率加速</param>
|
||||||
public virtual bool 发送自定义报文(
|
public virtual bool 发送自定义报文(
|
||||||
uint 通道号,
|
uint 通道号,
|
||||||
uint 帧ID,
|
string 帧IDStr,
|
||||||
byte[] 原始数据,
|
byte[] 原始数据,
|
||||||
byte dlcLength,
|
byte dlcLength,
|
||||||
bool 是否是扩展帧 = false,
|
bool 是否是扩展帧 = false,
|
||||||
bool 是否是CANFD = true,
|
bool 是否是CANFD = true,
|
||||||
bool 开启波特率加速BRS = true)
|
bool 开启波特率加速BRS = true)
|
||||||
{
|
{
|
||||||
|
if (!TryParseFrameId(帧IDStr, out uint 帧ID))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[ZLGCANFD] 发送自定义报文失败: 无法解析的帧 ID '{帧IDStr}'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
|
if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
|
||||||
if (原始数据 == null) return false;
|
if (原始数据 == null) return false;
|
||||||
|
|
||||||
@@ -649,7 +667,6 @@ namespace ZLGUSBCANFD
|
|||||||
string signalName = Encoding.Default.GetString(signal.strName).TrimEnd('\0');
|
string signalName = Encoding.Default.GetString(signal.strName).TrimEnd('\0');
|
||||||
if (!string.IsNullOrEmpty(signalName) && signal.initialValueValid != 0)
|
if (!string.IsNullOrEmpty(signalName) && signal.initialValueValid != 0)
|
||||||
{
|
{
|
||||||
// ZDBC 文档标注 initialValue 为“原始值”,但实际按 DBC 规范这里存放的是物理值
|
|
||||||
dict[signalName] = signal.initialValue;
|
dict[signalName] = signal.initialValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -693,6 +710,49 @@ namespace ZLGUSBCANFD
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计算物理值也需要传入对应通道,使用通道专属的DBC句柄进行计算
|
/// 计算物理值也需要传入对应通道,使用通道专属的DBC句柄进行计算
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <summary>
|
||||||
|
/// 智能解析帧 ID 字符串,兼容 10 进制、16 进制(如 "0x1A", "1A", "26")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idStr">输入的帧 ID 字符串</param>
|
||||||
|
/// <param name="frameId">解析成功后的 uint 帧 ID</param>
|
||||||
|
/// <returns>是否解析成功</returns>
|
||||||
|
[Browsable(false)]
|
||||||
|
public static bool TryParseFrameId(string idStr, out uint frameId)
|
||||||
|
{
|
||||||
|
frameId = 0;
|
||||||
|
if (string.IsNullOrWhiteSpace(idStr)) return false;
|
||||||
|
|
||||||
|
idStr = idStr.Trim();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1. 处理带 0x 或 0X 的标准 16 进制
|
||||||
|
if (idStr.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
frameId = Convert.ToUInt32(idStr.Substring(2), 16);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 尝试当做纯 10 进制解析(如 "26")
|
||||||
|
if (uint.TryParse(idStr, out frameId))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 如果不是纯数字,但符合 16 进制特征(如 "1A"、"ABC"),尝试按 16 进制解析
|
||||||
|
// 使用 System.Globalization.NumberStyles.HexNumber
|
||||||
|
if (uint.TryParse(idStr, System.Globalization.NumberStyles.HexNumber, null, out frameId))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
[Browsable(false)]
|
[Browsable(false)]
|
||||||
public ulong 物理值转原始寄存器值(uint 通道号, ZDBC.DBCSignal 信号定义, double 实际物理值)
|
public ulong 物理值转原始寄存器值(uint 通道号, ZDBC.DBCSignal 信号定义, double 实际物理值)
|
||||||
|
|||||||
120
ZLGUSBCANFD/ZLGDBCParser.cs
Normal file
120
ZLGUSBCANFD/ZLGDBCParser.cs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ZLGUSBCANFD
|
||||||
|
{
|
||||||
|
public class _Msg_
|
||||||
|
{
|
||||||
|
public int msg_type { get; set; }
|
||||||
|
public int msg_id { get; set; }
|
||||||
|
public int msg_cyclic { get; set; }
|
||||||
|
public byte msg_dlc { get; set; }
|
||||||
|
public string msg_name { get; set; }
|
||||||
|
public string[] signal_Name { get; set; }
|
||||||
|
public int msg_brs { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Msg_Type
|
||||||
|
{
|
||||||
|
CAN = 0,
|
||||||
|
CANFD = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ZLGDBCParser
|
||||||
|
{
|
||||||
|
// 补齐这个属性!4个通道的静态报文数据库缓存,供 ViewModel 直接读取
|
||||||
|
public static List<List<_Msg_>> MsgDatabase { get; set; } =
|
||||||
|
[.. Enumerable.Range(0, 4).Select(_ => new List<_Msg_>())];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 外部调用:解析特定通道的 DBC 并自动存入对应的 MsgDatabase 缓存中
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chDbcHandle">ZDBC句柄</param>
|
||||||
|
/// <param name="channel">通道号索引 (0-11)</param>
|
||||||
|
public static void ParseAndLoadToDatabase(uint chDbcHandle, int channel)
|
||||||
|
{
|
||||||
|
if (channel < 0 || channel >= MsgDatabase.Count) return;
|
||||||
|
|
||||||
|
// 清空当前通道旧缓存
|
||||||
|
MsgDatabase[channel].Clear();
|
||||||
|
|
||||||
|
// 解析并填充
|
||||||
|
var parsedList = ParseZlgDbc(chDbcHandle);
|
||||||
|
MsgDatabase[channel].AddRange(parsedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 全手工解析周立功 DBC 句柄下的所有消息和信号
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chDbcHandle">对应通道的 ZDBC 句柄</param>
|
||||||
|
/// <returns>返回对齐同星业务层的自定义报文列表</returns>
|
||||||
|
public static List<_Msg_> ParseZlgDbc(uint chDbcHandle)
|
||||||
|
{
|
||||||
|
List<_Msg_> msgList = new List<_Msg_>();
|
||||||
|
|
||||||
|
// 显式指定周立功命名空间下的 INVALID_DBC_HANDLE 校验
|
||||||
|
if (chDbcHandle == 0 || chDbcHandle == ZLGUSBCANFD.ZDBC.INVALID_DBC_HANDLE)
|
||||||
|
return msgList;
|
||||||
|
|
||||||
|
// 显式指定周立功命名空间下的结构体大小
|
||||||
|
int msgSize = Marshal.SizeOf(typeof(ZLGUSBCANFD.ZDBC.DBCMessage));
|
||||||
|
IntPtr pMsg = Marshal.AllocHGlobal(msgSize);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1. 获取周立功 DBC 的第一条报文
|
||||||
|
bool hasMessage = ZLGUSBCANFD.ZDBC.ZDBC_GetFirstMessage(chDbcHandle, pMsg);
|
||||||
|
|
||||||
|
while (hasMessage)
|
||||||
|
{
|
||||||
|
// 强制指定周立功底层 DBCMessage 结构映射
|
||||||
|
var zlgMsg = (ZLGUSBCANFD.ZDBC.DBCMessage)Marshal.PtrToStructure(pMsg, typeof(ZLGUSBCANFD.ZDBC.DBCMessage));
|
||||||
|
|
||||||
|
// 1. 优先在字节数组中找到第一个 \0 的位置
|
||||||
|
int nullIndex = Array.IndexOf(zlgMsg.strName, (byte)0);
|
||||||
|
|
||||||
|
_Msg_ myMsg = new _Msg_
|
||||||
|
{
|
||||||
|
msg_id = (int)zlgMsg.nID,
|
||||||
|
|
||||||
|
// 2. 只翻译 \0 之前的有效字节,彻底解决乱码与规避不必要的内存开销
|
||||||
|
msg_name = nullIndex >= 0
|
||||||
|
? Encoding.Default.GetString(zlgMsg.strName, 0, nullIndex)
|
||||||
|
: Encoding.Default.GetString(zlgMsg.strName).TrimEnd('\0'),
|
||||||
|
|
||||||
|
msg_dlc = (byte)zlgMsg.nSize,
|
||||||
|
msg_cyclic = (int)zlgMsg.nCycleTime,
|
||||||
|
// 如果底层识别出是扩展帧(nExtend==1),这里对齐映射为你的业务类型
|
||||||
|
msg_type = zlgMsg.nExtend == 1 ? (int)Msg_Type.CANFD : (int)Msg_Type.CAN,
|
||||||
|
signal_Name = new string[zlgMsg.nSignalCount]
|
||||||
|
};
|
||||||
|
// 2. 提取该报文下的所有信号名称
|
||||||
|
for (int i = 0; i < zlgMsg.nSignalCount; i++)
|
||||||
|
{
|
||||||
|
var signal = zlgMsg.vSignals[i];
|
||||||
|
string sigName = Encoding.Default.GetString(signal.strName).TrimEnd('\0');
|
||||||
|
myMsg.signal_Name[i] = sigName;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgList.Add(myMsg);
|
||||||
|
|
||||||
|
// 3. 移向下一条报文
|
||||||
|
hasMessage = ZLGUSBCANFD.ZDBC.ZDBC_GetNextMessage(chDbcHandle, pMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// 彻底释放非托管内存,避免上位机高频切换加载 DBC 时导致内存泄漏
|
||||||
|
Marshal.FreeHGlobal(pMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按 ID 排序,对齐你的树状展现或者二分查找业务逻辑
|
||||||
|
msgList.Sort((a, b) => a.msg_id.CompareTo(b.msg_id));
|
||||||
|
return msgList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user