diff --git a/ACP.sln b/ACP.sln
index 160b3d3..1808d71 100644
--- a/ACP.sln
+++ b/ACP.sln
@@ -35,8 +35,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonitorModule", "MonitorMod
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceEditModule", "DeviceEditModule\DeviceEditModule.csproj", "{170AD4C1-189D-4FBE-B10D-2A4304527834}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZLGUSBCANFD", "ZLGUSBCANFD\ZLGUSBCANFD.csproj", "{542FE380-2344-4343-9AC6-F0C587C13B88}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CANModule", "CANModule\CANModule.csproj", "{AF2533DD-599D-49D7-942B-B0C26534D15F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "加密狗", "加密狗\加密狗.csproj", "{A35CA316-7B5B-4183-8636-4ECA532B1489}"
@@ -47,6 +45,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExportModule", "ExportModul
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ACP", "ACP\ACP.csproj", "{CC810066-06A3-4635-96C7-1D30D78C2130}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TSMasterCAN", "TSMasterCAN\TSMasterCAN.csproj", "{B45DC94C-2CBB-4119-8787-B52A9E7EC58B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -113,10 +113,6 @@ Global
{170AD4C1-189D-4FBE-B10D-2A4304527834}.Debug|Any CPU.Build.0 = Debug|Any CPU
{170AD4C1-189D-4FBE-B10D-2A4304527834}.Release|Any CPU.ActiveCfg = Release|Any CPU
{170AD4C1-189D-4FBE-B10D-2A4304527834}.Release|Any CPU.Build.0 = Release|Any CPU
- {542FE380-2344-4343-9AC6-F0C587C13B88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {542FE380-2344-4343-9AC6-F0C587C13B88}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {542FE380-2344-4343-9AC6-F0C587C13B88}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {542FE380-2344-4343-9AC6-F0C587C13B88}.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
@@ -137,6 +133,10 @@ Global
{CC810066-06A3-4635-96C7-1D30D78C2130}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC810066-06A3-4635-96C7-1D30D78C2130}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC810066-06A3-4635-96C7-1D30D78C2130}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B45DC94C-2CBB-4119-8787-B52A9E7EC58B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B45DC94C-2CBB-4119-8787-B52A9E7EC58B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B45DC94C-2CBB-4119-8787-B52A9E7EC58B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B45DC94C-2CBB-4119-8787-B52A9E7EC58B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/ACP/ACP.csproj b/ACP/ACP.csproj
index 77a4fd2..37b3348 100644
--- a/ACP/ACP.csproj
+++ b/ACP/ACP.csproj
@@ -31,9 +31,9 @@
+
-
diff --git a/CANModule/CANModule.cs b/CANModule/CANModule.cs
index 9944f14..0aeed6e 100644
--- a/CANModule/CANModule.cs
+++ b/CANModule/CANModule.cs
@@ -12,7 +12,7 @@ namespace CANModule
{
containerRegistry.RegisterDialog("SelectCanMessageView");
containerRegistry.RegisterDialog("CollectCANSignalSettingView");
- containerRegistry.RegisterForNavigation("ZLGCANFDView");
+ containerRegistry.RegisterForNavigation("CANView");
}
}
}
diff --git a/CANModule/CANModule.csproj b/CANModule/CANModule.csproj
index 3df7504..fea4280 100644
--- a/CANModule/CANModule.csproj
+++ b/CANModule/CANModule.csproj
@@ -1,14 +1,21 @@
-
- net8.0-windows
- enable
- true
- enable
-
+
+ net8.0-windows
+ enable
+ true
+ enable
+
-
-
-
+
+
+
+
+
+
+
+ ..\TSMasterCAN\Interop.TSMasterAPI.dll
+
+
diff --git a/CANModule/ViewModels/CANViewModel.cs b/CANModule/ViewModels/CANViewModel.cs
new file mode 100644
index 0000000..0f486aa
--- /dev/null
+++ b/CANModule/ViewModels/CANViewModel.cs
@@ -0,0 +1,581 @@
+
+using Microsoft.Win32;
+using Model;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+using System.Windows.Input;
+using System.Windows.Threading;
+using TSMasterCAN;
+using UIShare.GlobalVariable;
+using UIShare.UIViewModel;
+
+namespace CANModule.ViewModels
+{
+ public class CANViewModel : BindableBase, IDialogAware
+ {
+
+ #region 属性
+ private string _Title = "同星CAN";
+
+ public string Title
+ {
+ get { return _Title; }
+ set { SetProperty(ref _Title, value); }
+ }
+ private ObservableCollection _CanMessageList = new();
+
+ public ObservableCollection CanMessageList
+ {
+ get { return _CanMessageList; }
+ set { SetProperty(ref _CanMessageList, value); }
+ }
+ private string _DBCChannel = "0";
+
+ public string DBCChannel
+ {
+ get { return _DBCChannel; }
+ set { SetProperty(ref _DBCChannel, value); }
+ }
+ private bool _IsDirectlySend = false;
+
+ public bool IsDirectlySend
+ {
+ get { return _IsDirectlySend; }
+ set { SetProperty(ref _IsDirectlySend, value); }
+ }
+ private ObservableCollection _Message;
+ public ObservableCollection Message
+ {
+ get { return _Message; }
+ set { SetProperty(ref _Message, value); }
+ }
+ private ObservableCollection _Signal;
+ public ObservableCollection Signal
+ {
+ get { return _Signal; }
+ set { SetProperty(ref _Signal, value); }
+ }
+ byte channel;
+ private string _selectedMessage;
+ public string SelectedMessage
+ {
+ get { return _selectedMessage; }
+ set
+ {
+ if (_selectedMessage != value)
+ {
+ Signal = new(DBCParse.MsgDatabase[channel].Where(x => $"[0x{x.msg_id:X}]{x.msg_name}" == value).First().signal_Name);
+ _selectedMessage = value;
+ RaisePropertyChanged();
+ }
+ }
+ }
+
+ private string _selectedSignal;
+ public string SelectedSignal
+ {
+ get { return _selectedSignal; }
+ set { SetProperty(ref _selectedSignal, value); }
+ }
+
+ private string _signalValue;
+ public string SignalValue
+ {
+ get { return _signalValue; }
+ set { SetProperty(ref _signalValue, value); }
+ }
+
+ private string _cycleSendInterval;
+ public string CycleSendInterval
+ {
+ get { return _cycleSendInterval; }
+ set { SetProperty(ref _cycleSendInterval, value); }
+ }
+
+ private string _messageSendChannel = "0";
+ public string MessageSendChannel
+ {
+ get { return _messageSendChannel; }
+ set { SetProperty(ref _messageSendChannel, value); }
+ }
+ public string BLFPath
+ {
+ get => _systemConfig?.DefaultBLFFilePath ?? "";
+ set
+ {
+ if (_systemConfig != null && _systemConfig.DefaultBLFFilePath != value)
+ {
+ _systemConfig.DefaultBLFFilePath = value;
+ RaisePropertyChanged();
+ }
+ }
+ }
+
+ public string DBCPath
+ {
+ get => _systemConfig?.DefaultDBCFilePath ?? "";
+ set
+ {
+ if (_systemConfig != null && _systemConfig.DefaultDBCFilePath != value)
+ {
+ _systemConfig.DefaultDBCFilePath = value;
+ RaisePropertyChanged();
+ }
+ }
+ }
+ private bool _IsSaved;
+ public bool IsSaved
+ {
+ get { return _IsSaved; }
+ set { SetProperty(ref _IsSaved, value); }
+ }
+ public ObservableCollection DBCAutoLoadList
+ {
+ get => _systemConfig?.DBCAutoLoadList ?? new ObservableCollection();
+ }
+
+ private AutoDBCLoadItem _SelectedDcAutoLoad;
+ public AutoDBCLoadItem SelectedDcAutoLoad
+ {
+ get { return _SelectedDcAutoLoad; }
+ set { SetProperty(ref _SelectedDcAutoLoad, value); }
+ }
+ private TSMaster.APP_CHANNEL[] _appChannelNames = new[] { TSMaster.APP_CHANNEL.CHN1, TSMaster.APP_CHANNEL.CHN2, TSMaster.APP_CHANNEL.CHN3, TSMaster.APP_CHANNEL.CHN4 };
+ public TSMaster.APP_CHANNEL[] APP_CHANNEL
+ {
+ get { return _appChannelNames; }
+ set { SetProperty(ref _appChannelNames, value); }
+ }
+
+ private TSMaster.APP_CHANNEL _aIdxChn;
+ public TSMaster.APP_CHANNEL AIdxChn
+ {
+ get { return _aIdxChn; }
+ set { SetProperty(ref _aIdxChn, value); }
+ }
+
+ private int _aID;
+ public int AID
+ {
+ get { return _aID; }
+ set { SetProperty(ref _aID, value); }
+ }
+
+ private bool _aIsTx;
+ public bool AIsTx
+ {
+ get { return _aIsTx; }
+ set { SetProperty(ref _aIsTx, value); }
+ }
+
+ private bool _aIsExt;
+ public bool AIsExt
+ {
+ get { return _aIsExt; }
+ set { SetProperty(ref _aIsExt, value); }
+ }
+
+ private bool _aIsRemote;
+ public bool AIsRemote
+ {
+ get { return _aIsRemote; }
+ set { SetProperty(ref _aIsRemote, value); }
+ }
+
+ private byte _aDlc;
+ public byte ADLC
+ {
+ get { return _aDlc; }
+ set { SetProperty(ref _aDlc, value); }
+ }
+
+ private byte[] _aDataArray;
+ public byte[] ADataArray
+ {
+ get { return _aDataArray; }
+ set { SetProperty(ref _aDataArray, value); }
+ }
+
+ private bool _aIsFD = true;
+ public bool AIsFD
+ {
+ get { return _aIsFD; }
+ set { SetProperty(ref _aIsFD, value); }
+ }
+
+ private bool _aIsBRS = false;
+ public bool AIsBRS
+ {
+ get { return _aIsBRS; }
+ set { SetProperty(ref _aIsBRS, value); }
+ }
+
+ private bool _AutoSetting = true;
+ public bool AutoSetting
+ {
+ get { return _AutoSetting; }
+ set { SetProperty(ref _AutoSetting, value); }
+ }
+
+ private string _CustomMessage = "[00,11,22,33,AA,BB,CC,DD]";
+ public string CustomMessage
+ {
+ get { return _CustomMessage; }
+ set { SetProperty(ref _CustomMessage, value); }
+ }
+
+ private float _CustomSendCycleInterval = 0.0f;
+ public float CustomSendCycleInterval
+ {
+ get { return _CustomSendCycleInterval; }
+ set { SetProperty(ref _CustomSendCycleInterval, value); }
+ }
+ private bool _UpdateToDB;
+ public bool UpdateToDB
+ {
+ get { return _UpdateToDB; }
+ set { SetProperty(ref _UpdateToDB, value); }
+ }
+ #endregion
+ #region 命令
+ public ICommand SelectBLFPathCommand { get; set; }
+ public ICommand SaveBLFPathCommand { get; set; }
+ public ICommand StartTranscirbeCommand { get; set; }
+ public ICommand EndTranscirbeCommand { get; set; }
+ public ICommand CloseCommand { get; set; }
+ public ICommand ConnectCanCommand { get; set; }
+ public ICommand CloseCanCommand { get; set; }
+ public ICommand ClearCycleCommand { get; set; }
+ public ICommand UpLoadDBCCommand { get; set; }
+ public ICommand ChangeDBCCommand { get; set; }
+ public ICommand LoadDBCCommand { get; set; }
+ public ICommand CheckDBCCommand { get; set; }
+ public ICommand InitTSMasterCommand { get; set; }
+ public ICommand ReleaseTSMasterCommand { get; set; }
+ public ICommand LoadMessageCommand { get; set; }
+ public ICommand SetAndSendMessageCommand { get; set; }
+ public ICommand DeleteDcAutoLoadCommand { get; set; }
+ public ICommand SendCustomMessageCommand { get; set; }
+
+ #endregion
+ private IEventAggregator _eventAggregator { get; set; }
+ private CAN? _canfd;
+ private SystemConfig? _systemConfig;
+ private readonly DeviceManager _deviceManager;
+ private IDialogService _dialogService { get; set; }
+ CancellationTokenSource cts = new CancellationTokenSource();
+ public CANViewModel(IContainerProvider containerProvider)
+ {
+ _eventAggregator = containerProvider.Resolve();
+ _systemConfig = containerProvider.Resolve();
+ _deviceManager = containerProvider.Resolve();
+ _canfd = _deviceManager.CANFD;
+ _dialogService = containerProvider.Resolve();
+ SelectBLFPathCommand = new DelegateCommand(SelectBLFPath);
+ SaveBLFPathCommand = new DelegateCommand(SaveBLFPath);
+ StartTranscirbeCommand = new DelegateCommand(StartTranscirbe);
+ EndTranscirbeCommand = new DelegateCommand(EndTranscirbe);
+ CloseCommand = new DelegateCommand(Close);
+ ConnectCanCommand = new DelegateCommand(ConnectCan);
+ CloseCanCommand = new DelegateCommand(CloseCan);
+ ClearCycleCommand = new DelegateCommand(ClearCycle);
+ UpLoadDBCCommand = new DelegateCommand(UpLoadDBC);
+ ChangeDBCCommand = new DelegateCommand(ChangeDBC);
+ LoadDBCCommand = new DelegateCommand(LoadDBC);
+ CheckDBCCommand = new DelegateCommand(CheckDBC);
+ InitTSMasterCommand = new DelegateCommand(InitTSMaster);
+ ReleaseTSMasterCommand = new DelegateCommand(ReleaseTSMaster);
+ SetAndSendMessageCommand = new DelegateCommand(SetAndSendMessage);
+ LoadMessageCommand = new DelegateCommand(LoadMessage);
+ DeleteDcAutoLoadCommand = new DelegateCommand(DeleteDcAutoLoad);
+ SendCustomMessageCommand = new DelegateCommand(SendCustomMessage);
+ }
+
+ #region 命令
+ private void SendCustomMessage()
+ {
+ try
+ {
+ ADataArray = 报文转换(CustomMessage);
+ if (ADataArray.Length > byte.MaxValue) throw new Exception("报文数量超过上限!");
+ if (AutoSetting)
+ {
+ ADLC = (byte)ADataArray.Length;
+ }
+ }
+ catch (Exception ex)
+ {
+ _dialogService.ShowDialog("MessageDialog", new DialogParameters
+ {
+ { "message", $"报文转换失败:{ex.Message}" }
+ });
+ return;
+ }
+ var re = CAN.SendMsg(AIdxChn, AID, AIsTx, AIsExt,
+ AIsRemote, ADLC, ADataArray, AIsFD, AIsBRS, UpdateToDB, CustomSendCycleInterval);
+ }
+ private void DeleteDcAutoLoad()
+ {
+ DBCAutoLoadList.Remove(SelectedDcAutoLoad);
+ ConfigService.Save(_systemConfig);
+ }
+ private void LoadMessage()
+ {
+ if (int.TryParse(MessageSendChannel, out int channel))
+ {
+ Message = new(DBCParse.MsgDatabase[channel].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}"));
+ }
+ else
+ {
+
+ }
+ }
+
+ private void SetAndSendMessage()
+ {
+ if (int.TryParse(CycleSendInterval, out int sendPeriod) && double.TryParse(SignalValue, out double SValue) && byte.TryParse(MessageSendChannel, out byte c))
+ {
+ channel = c;
+ var message = SelectedMessage.Split(']')[1];
+ var re = CAN.SetSignalValue(channel, message, SelectedSignal, SValue, IsDirectlySend, sendPeriod);
+ }
+ else
+ {
+
+ }
+ }
+
+ private void ReleaseTSMaster()
+ {
+ CAN.Release();
+ }
+
+ private void InitTSMaster()
+ {
+ var re = CAN.Init("ACP");
+ }
+ private void UpLoadDBC()
+ {
+ var re = CAN.UnLoadDBC();
+ }
+
+ private void ChangeDBC()
+ {
+ var dialog = new OpenFileDialog
+ {
+ Title = "更换DBC文件",
+ Filter = "DBC 文件 (*.dbc)|*.dbc|所有文件 (*.*)|*.*",
+ DefaultExt = ".dbc",
+ };
+ if (dialog.ShowDialog() == true)
+ {
+ DBCPath = Path.GetFullPath(dialog.FileName);
+ ConfigService.Save(_systemConfig);
+ }
+ }
+
+ private void LoadDBC()
+ {
+ if (int.TryParse(DBCChannel, out var channel))
+ {
+ var re = CAN.LoadDBC(DBCPath, [channel], out _);
+ if (re == 0 && IsSaved)
+ {
+ var item = DBCAutoLoadList.Where(s => s.DBCChannel == channel).FirstOrDefault();
+ if (item == null)
+ {
+ DBCAutoLoadList.Add(new AutoDBCLoadItem
+ {
+ DBCFilePath = DBCPath,
+ DBCChannel = channel
+ });
+ }
+ else
+ {
+ DBCAutoLoadList.Remove(item);
+ DBCAutoLoadList.Add(new AutoDBCLoadItem
+ {
+ DBCFilePath = DBCPath,
+ DBCChannel = channel
+ });
+ }
+ ConfigService.Save(_systemConfig);
+ }
+ }
+ else
+ {
+
+ }
+ }
+
+ private void CheckDBC()
+ {
+ if (int.TryParse(DBCChannel, out var channel))
+ {
+ _dialogService.ShowDialog("DBCInfo", new DialogParameters
+ {
+ { "can_Network", DBCParse.can_Network },
+ { "MsgDatabase", DBCParse.MsgDatabase[channel] }
+ });
+ }
+
+ }
+ private void ClearCycle()
+ {
+ var re = CAN.DeleteCyclicMsgs();
+ }
+
+ private void CloseCan()
+ {
+ var re = CAN.DisConnect();
+ }
+
+ private void ConnectCan()
+ {
+ var re = CAN.Connect();
+ }
+ private void EndTranscirbe()
+ {
+ var re = CAN.StopLogging();
+ }
+
+ private void StartTranscirbe()
+ {
+ var re = CAN.StartLogging(BLFPath);
+ }
+
+ private void SaveBLFPath()
+ {
+ _systemConfig.DefaultBLFFilePath = BLFPath;
+ ConfigService.Save(_systemConfig);
+ }
+
+ private void SelectBLFPath()
+ {
+ var dialog = new SaveFileDialog
+ {
+ Title = "保存 CAN报文回放 BLF 文件",
+ Filter = "BLF 文件 (*.blf)|*.blf|所有文件 (*.*)|*.*",
+ DefaultExt = ".blf",
+ FileName = "log.blf",
+ OverwritePrompt = true
+ };
+ if (dialog.ShowDialog() == true)
+ {
+ BLFPath = Path.GetFullPath(dialog.FileName);
+ }
+ }
+ private void Close()
+ {
+ RequestClose.Invoke();
+ }
+ #endregion
+ public byte[] 报文转换(string s)
+ {
+ s = s.Replace("[", string.Empty).Replace("]", string.Empty);
+ var strs = s.Split(',', StringSplitOptions.RemoveEmptyEntries);
+ byte[] bytes = new byte[strs.Length];
+ for (int i = 0; i < strs.Length; i++)
+ {
+ bytes[i] = Convert.ToByte(strs[i], 16);
+ }
+ return bytes;
+ }
+
+ private async Task Refresh(CancellationToken ct = default)
+ {
+ while (ct.IsCancellationRequested == false)
+ {
+ var temp = CAN.RealTimeMessages.Select(s => s.Value).ToArray();
+ foreach (var item in temp)
+ {
+ var find = CanMessageList.FirstOrDefault(s => s.报文ID == item.FIdentifier);
+ if (find != null)
+ {
+ if (find.通道 != item.FIdxChn) find.通道 = item.FIdxChn;
+ if (find.报文ID != item.FIdentifier) find.报文ID = item.FIdentifier;
+ if (find.时间戳 != item.FTimeUS) find.时间戳 = item.FTimeUS;
+ if (find.FD != item.FIsFD) find.FD = item.FIsFD;
+ if (find.IsTx != item.FIsTx) find.IsTx = item.FIsTx;
+
+ var 长度改变 = find.长度 == item.FDLC;
+ var 数据改变 = find.Bytes.SequenceEqual(item.FData);
+ if (长度改变 || 数据改变)
+ {
+ find.长度 = item.FDLC;
+ Array.Copy(item.FData, 0, find.Bytes, 0, 64);
+ find.报文 = 十六进制字符串转换(item.FData.AsSpan(0, find.长度));
+ }
+ }
+ else
+ {
+ var 报文temp = new CanMessageShowVM()
+ {
+ 通道 = item.FIdxChn,
+ 报文ID = item.FIdentifier,
+ 时间戳 = item.FTimeUS,
+ FD = item.FIsFD,
+ IsTx = item.FIsTx,
+ 长度 = item.FDLC,
+ 报文 = 十六进制字符串转换(item.FData.AsSpan(0, item.FDLC)),
+ };
+ Array.Copy(item.FData, 0, 报文temp.Bytes, 0, 64);
+ Application.Current.Dispatcher.Invoke(() =>
+ {
+ CanMessageList.Add(报文temp);
+ });
+ }
+
+ }
+ await Task.Delay(50, ct);
+ }
+ }
+ string 十六进制字符串转换(Span s)
+ {
+ if (s == null || s.Length == 0)
+ return "[]";
+
+ var sb = new StringBuilder();
+ sb.Append('[');
+ for (int i = 0; i < s.Length; i++)
+ {
+ sb.Append("0x");
+ sb.Append(s[i].ToString("X2"));
+ if (i < s.Length - 1)
+ sb.Append(", ");
+ }
+ sb.Append(']');
+ return sb.ToString();
+ }
+ #region dialog规范
+ public DialogCloseListener RequestClose { get; set; }
+
+ public bool CanCloseDialog()
+ {
+ return true;
+ }
+
+ public void OnDialogClosed()
+ {
+ cts.Cancel();
+ }
+
+ public void OnDialogOpened(IDialogParameters parameters)
+ {
+ Task.Run(() => Refresh(cts.Token), cts.Token);
+ }
+
+
+ #endregion
+ }
+}
diff --git a/CANModule/ViewModels/CollectCANSingalSettingViewModel.cs b/CANModule/ViewModels/CollectCANSingalSettingViewModel.cs
index 80cf9f7..f2c15d0 100644
--- a/CANModule/ViewModels/CollectCANSingalSettingViewModel.cs
+++ b/CANModule/ViewModels/CollectCANSingalSettingViewModel.cs
@@ -1,30 +1,41 @@
using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Configuration;
using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
using System.Windows.Input;
+using Model;
+using TSMasterCAN;
using UIShare.GlobalVariable;
using UIShare.PubEvent;
using UIShare.UIViewModel;
-using UIShare.ViewModelBase;
-using ZLGUSBCANFD;
namespace CANModule.ViewModels
{
- public class CollectCANSignalSettingViewModel : DialogViewModelBase
+ public class CollectCANSignalSettingViewModel : BindableBase, IDialogAware
{
- #region 字段
- private ZLGCANFD? _canfd;
- private SystemConfig? _systemConfig;
- #endregion
-
#region 属性
public ObservableCollection ConfigurationList
{
- get => _systemConfig?.ConfigurationList ?? new ObservableCollection();
+ get => _systemConfig.ConfigurationList;
+ set
+ {
+ if(_systemConfig.ConfigurationList != value)
+ {
+ _systemConfig.ConfigurationList = value;
+ RaisePropertyChanged();
+ }
+ }
}
-
-
+ private ObservableCollection _ChannelList;
+ public ObservableCollection ChannelList
+ {
+ get => _ChannelList;
+ set => SetProperty(ref _ChannelList, value);
+ }
private ObservableCollection _messageList;
public ObservableCollection MessageList
{
@@ -39,42 +50,23 @@ namespace CANModule.ViewModels
set => SetProperty(ref _signalList, value);
}
- private string _title = "信号采集设置";
+ private string _title= "信号采集设置";
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
-
private string _selectedMessage;
public string SelectedMessage
{
get => _selectedMessage;
set
{
- if (SetProperty(ref _selectedMessage, value))
+ if (SetProperty(ref _selectedMessage,value))
{
- if (!string.IsNullOrEmpty(value) && _canfd != null)
+ if (value != null && value != "")
{
- var db = _canfd.DBCParser.MsgDatabase;
- if (MessageChannel >= 0 && MessageChannel < db.Count)
- {
- var targetMsg = db[MessageChannel]
- .FirstOrDefault(x => $"[0x{x.msg_id:X}]{x.msg_name}" == value);
-
- if (targetMsg != null && targetMsg.signal_Name != null)
- {
- SignalList = new ObservableCollection(targetMsg.signal_Name);
- }
- else
- {
- SignalList = new ObservableCollection();
- }
- }
- }
- else
- {
- SignalList = new ObservableCollection();
+ SignalList = new(DBCParse.MsgDatabase[MessageChannel].Where(x => $"[0x{x.msg_id:X}]{x.msg_name}" == value).First().signal_Name);
}
}
}
@@ -86,7 +78,6 @@ namespace CANModule.ViewModels
get => _SelectedItem;
set => SetProperty(ref _SelectedItem, value);
}
-
private string _selectedSignal;
public string SelectedSignal
{
@@ -94,7 +85,7 @@ namespace CANModule.ViewModels
set => SetProperty(ref _selectedSignal, value);
}
- private int _MessageChannel=-1;
+ private int _MessageChannel;
public int MessageChannel
{
get => _MessageChannel;
@@ -103,127 +94,91 @@ namespace CANModule.ViewModels
if (_MessageChannel != value)
{
_MessageChannel = value;
-
+ MessageList = new(DBCParse.MsgDatabase[value].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}"));
+ SignalList = new();
SelectedMessage = null;
SelectedSignal = null;
- SignalList = new ObservableCollection();
-
- if (_canfd != null)
- {
- var db = _canfd.DBCParser.MsgDatabase;
- if (db != null && value >= 0 && value < db.Count)
- {
- MessageList = new ObservableCollection(
- db[value].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}")
- );
- }
- else
- {
- MessageList = new ObservableCollection();
- }
- }
- else
- {
- MessageList = new ObservableCollection();
- }
-
RaisePropertyChanged();
}
}
}
- private int _collectionInterval = 1000;
+ private int _collectionInterval=1000;
public int CollectionInterval
{
get => _collectionInterval;
set => SetProperty(ref _collectionInterval, value);
}
- #endregion
-
- #region 命令
+ #endregion Properties
public ICommand AddCommand { get; set; }
- public ICommand CloseCommand { get; set; }
- public ICommand SaveCommand { get; set; }
- public ICommand DeleteCommand { get; set; }
- #endregion
-
- public CollectCANSignalSettingViewModel(IContainerProvider containerProvider) : base(containerProvider)
+ public ICommand CloseCommand { get; set; }
+ public ICommand LoadCommand { get; set; }
+ public ICommand SaveCommand { get; set; }
+ public ICommand DeleteCommand { get; set; }
+ public DialogCloseListener RequestClose { get; set; }
+ public IEventAggregator _eventAggregator { get; set; }
+ private SystemConfig _systemConfig;
+ public CollectCANSignalSettingViewModel(IContainerProvider containerProvider)
{
+ _eventAggregator=containerProvider.Resolve();
+ _systemConfig= containerProvider.Resolve();
CloseCommand = new DelegateCommand(Close);
AddCommand = new DelegateCommand(Add);
+ LoadCommand = new DelegateCommand(Load);
SaveCommand = new DelegateCommand(Save);
DeleteCommand = new DelegateCommand(Delete);
}
- #region Dialog 生命周期
- public override void OnDialogOpened(IDialogParameters parameters)
- {
- _systemConfig = parameters.GetValue("SystemConfig");
- _canfd = _systemConfig?.CANFD;
- string title = _systemConfig.Title;
- char lastChar = title[title.Length - 1];
- // 3. "TestCellX"转int
- MessageChannel = int.Parse(lastChar.ToString())-1;
- if (MessageChannel >= 4) MessageChannel -= 4;
- RaisePropertyChanged(nameof(ConfigurationList));
- }
- #endregion
-
- #region 命令处理
private void Delete()
{
- if (SelectedItem != null)
- {
- _systemConfig?.ConfigurationList.Remove(SelectedItem);
- }
+ ConfigurationList.Remove(SelectedItem);
}
private void Save()
{
+ _eventAggregator.GetEvent().Publish();
ConfigService.Save(_systemConfig);
}
+ private void Load()
+ {
+ ChannelList = new ObservableCollection(Enumerable.Range(0, 12));
+ }
+
private void Add()
{
- if (string.IsNullOrEmpty(SelectedSignal) || string.IsNullOrEmpty(SelectedMessage) || CollectionInterval < 100)
+ if (string.IsNullOrEmpty(SelectedSignal) || string.IsNullOrEmpty(SelectedMessage)||CollectionInterval<100)
{
return;
}
- if (_systemConfig == null) return;
-
string hexString = ExtractHex(SelectedMessage);
- if (string.IsNullOrEmpty(hexString)) return;
-
- int decimalValue = ConvertHexToDecimal(hexString);
- if (_systemConfig.ConfigurationList.Any(x => x.SignalName == SelectedSignal && x.Channel == MessageChannel))
+ if (string.IsNullOrEmpty(hexString))
{
return;
}
-
- _systemConfig.ConfigurationList.Add(new CANSignalConfig
+ int decimalValue = ConvertHexToDecimal(hexString);
+ if (ConfigurationList.Where(x => x.SignalName == SelectedSignal&&x.Channel==MessageChannel).FirstOrDefault() != null) return;
+ ConfigurationList.Add(new CANSignalConfig
{
CollectionID = Guid.NewGuid(),
- Channel = MessageChannel,
- MethodName = CANSignalBroadcaster.BuildMethodName((uint)decimalValue, SelectedSignal),
+ Channel = MessageChannel,
MessageName = ExtractMessageName(SelectedMessage),
SignalName = SelectedSignal,
MessageID = decimalValue,
CollectionInterval = CollectionInterval
});
}
-
private string ExtractHex(string input)
{
int startIndex = input.IndexOf("0x") + 2;
- int endIndex = input.IndexOf("]", startIndex);
+ int endIndex = input.IndexOf("]", startIndex);
if (startIndex >= 2 && endIndex > startIndex)
{
return input.Substring(startIndex, endIndex - startIndex);
}
return string.Empty;
}
-
private int ConvertHexToDecimal(string hex)
{
try
@@ -232,20 +187,37 @@ namespace CANModule.ViewModels
}
catch (FormatException)
{
- return -1;
+ return -1;
}
}
-
private string ExtractMessageName(string input)
{
var parts = input.Split(']');
- return parts.Length > 1 ? parts[1] : string.Empty;
+ return parts.Length > 1 ? parts[1] : string.Empty;
}
private void Close()
{
RequestClose.Invoke();
}
- #endregion
+
+ public bool CanCloseDialog()
+ {
+ return true;
+ }
+
+ public void OnDialogClosed()
+ {
+
+ }
+
+ public void OnDialogOpened(IDialogParameters parameters)
+ {
+ if (DBCParse.MsgDatabase.Count == 0 || DBCParse.MsgDatabase[0].Count==0)
+ {
+
+ }
+ MessageList = new(DBCParse.MsgDatabase[0].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}"));
+ }
}
}
diff --git a/CANModule/ViewModels/SelectCanMessageViewModel.cs b/CANModule/ViewModels/SelectCanMessageViewModel.cs
index 3b06b12..baa3808 100644
--- a/CANModule/ViewModels/SelectCanMessageViewModel.cs
+++ b/CANModule/ViewModels/SelectCanMessageViewModel.cs
@@ -1,29 +1,26 @@
using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Text;
+using System.Threading.Channels;
+using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
-using UIShare.ViewModelBase;
-using ZLGUSBCANFD;
+using TSMasterCAN;
+using UIShare.UIViewModel;
namespace CANModule.ViewModels
{
- public class SelectCanMessageViewModel : DialogViewModelBase
+ public class SelectCanMessageViewModel : BindableBase, IDialogAware
{
- #region 字段
- private ZLGCANFD? _canfd;
- #endregion
-
#region 属性
- public DialogCloseListener RequestClose { get; set; }
-
private ObservableCollection _ChannelList;
public ObservableCollection ChannelList
{
get => _ChannelList;
set => SetProperty(ref _ChannelList, value);
}
-
private ObservableCollection _messageList;
public ObservableCollection MessageList
{
@@ -44,7 +41,6 @@ namespace CANModule.ViewModels
get => _title;
set => SetProperty(ref _title, value);
}
-
private string _selectedMessage;
public string SelectedMessage
{
@@ -53,27 +49,9 @@ namespace CANModule.ViewModels
{
if (SetProperty(ref _selectedMessage, value))
{
- if (!string.IsNullOrEmpty(value) && _canfd != null)
+ if (value != null && value != "")
{
- var db = _canfd.DBCParser.MsgDatabase;
- if (MessageChannel >= 0 && MessageChannel < db.Count)
- {
- var targetMsg = db[MessageChannel]
- .FirstOrDefault(x => $"[0x{x.msg_id:X}]{x.msg_name}" == value);
-
- if (targetMsg != null && targetMsg.signal_Name != null)
- {
- SignalList = new ObservableCollection(targetMsg.signal_Name);
- }
- else
- {
- SignalList = new ObservableCollection();
- }
- }
- }
- else
- {
- SignalList = new ObservableCollection();
+ SignalList = new(DBCParse.MsgDatabase[MessageChannel].Where(x => $"[0x{x.msg_id:X}]{x.msg_name}" == value).First().signal_Name);
}
}
}
@@ -85,8 +63,7 @@ namespace CANModule.ViewModels
get => _selectedSignal;
set => SetProperty(ref _selectedSignal, value);
}
-
- private int _MessageChannel = -1;
+ private int _MessageChannel;
public int MessageChannel
{
get => _MessageChannel;
@@ -94,94 +71,84 @@ namespace CANModule.ViewModels
{
if (_MessageChannel != value)
{
- _MessageChannel = value;
-
- // 1. 先安全清空旧的选择项和信号列表
+ _MessageChannel=value;
+ MessageList = new(DBCParse.MsgDatabase[value].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}"));
+ SignalList = new();
SelectedMessage = null;
SelectedSignal = null;
- SignalList = new ObservableCollection();
-
- // 2. 刷新当前通道的报文列表
- if (_canfd != null)
- {
- var db = _canfd.DBCParser.MsgDatabase;
- if (db != null && value >= 0 && value < db.Count)
- {
- MessageList = new ObservableCollection(
- db[value].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}")
- );
- }
- else
- {
- MessageList = new ObservableCollection();
- }
- }
- else
- {
- MessageList = new ObservableCollection();
- }
-
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)
+ public DialogCloseListener RequestClose { get; set; }
+ public SelectCanMessageViewModel()
{
CloseCommand = new DelegateCommand(Close);
GetSelectedMessageCommand = new DelegateCommand(GetSelectedMessage);
GetSelectedSignalCommand = new DelegateCommand(GetSelectedSignal);
LoadCommand = new DelegateCommand(Load);
- }
- #region Dialog 生命周期
- public override void OnDialogOpened(IDialogParameters parameters)
- {
- _canfd = parameters.GetValue("CANFD");
- }
- #endregion
-
- #region 命令处理
- private void Close()
- {
- RequestClose.Invoke();
}
private void Load()
{
- int maxCh = _canfd?.DBCParser.MaxChannels ?? 4;
- ChannelList = new ObservableCollection(Enumerable.Range(0, maxCh));
+ ChannelList = new ObservableCollection(Enumerable.Range(0, 12));
}
private void GetSelectedSignal()
{
- if (!string.IsNullOrEmpty(SelectedSignal))
+ if (SelectedSignal!=null)
{
Application.Current.Dispatcher.Invoke(() =>
{
Clipboard.SetDataObject(SelectedSignal);
});
}
+ else
+ {
+
+ }
+
}
private void GetSelectedMessage()
{
- if (!string.IsNullOrEmpty(SelectedMessage) && SelectedMessage.Contains(']'))
+ if (SelectedSignal != null)
{
Application.Current.Dispatcher.Invoke(() =>
{
- Clipboard.SetDataObject(SelectedMessage);
+ Clipboard.SetDataObject(SelectedMessage.Split("]")[1]);
});
}
+ else
+ {
+
+ }
+ }
+
+ private void Close()
+ {
+ RequestClose.Invoke();
+ }
+
+ public bool CanCloseDialog()
+ {
+ return true;
+ }
+
+ public void OnDialogClosed()
+ {
+
+ }
+
+ public void OnDialogOpened(IDialogParameters parameters)
+ {
+ MessageList = new(DBCParse.MsgDatabase[0].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}"));
}
- #endregion
}
}
diff --git a/CANModule/ViewModels/ZLGCANFDViewModel.cs b/CANModule/ViewModels/ZLGCANFDViewModel.cs
deleted file mode 100644
index 1ebc85e..0000000
--- a/CANModule/ViewModels/ZLGCANFDViewModel.cs
+++ /dev/null
@@ -1,649 +0,0 @@
-using Microsoft.Win32;
-using System;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Input;
-using UIShare.GlobalVariable;
-using UIShare.UIViewModel;
-using UIShare.ViewModelBase;
-using ZLGUSBCANFD;
-
-namespace CANModule.ViewModels
-{
- public class ZLGCANFDViewModel : NavigateViewModelBase
- {
- #region 字段
- private ZLGCANFD? _canfd;
- private SystemConfig? _systemConfig;
- private CancellationTokenSource? _refreshCts;
- private readonly DeviceManager _deviceManager;
- #endregion
-
- #region 属性
- private string _Title = "周立功CAN";
- public string Title
- {
- get => _Title;
- set => SetProperty(ref _Title, value);
- }
-
- private ObservableCollection _CanMessageList = new();
- public ObservableCollection CanMessageList
- {
- get => _CanMessageList;
- set => SetProperty(ref _CanMessageList, value);
- }
-
- private int _DBCChannel = 0;
- public int DBCChannel
- {
- get => _DBCChannel;
- set => SetProperty(ref _DBCChannel, value);
- }
-
- private bool _IsDirectlySend = false;
- public bool IsDirectlySend
- {
- get => _IsDirectlySend;
- set => SetProperty(ref _IsDirectlySend, value);
- }
-
- private ObservableCollection _Message;
- public ObservableCollection Message
- {
- get => _Message;
- set => SetProperty(ref _Message, value);
- }
-
- private ObservableCollection _Signal;
- public ObservableCollection Signal
- {
- get => _Signal;
- set => SetProperty(ref _Signal, value);
- }
-
- private byte _channel;
- private string _selectedMessage;
- public string SelectedMessage
- {
- get => _selectedMessage;
- set
- {
- if (_selectedMessage != value)
- {
- if (!string.IsNullOrEmpty(value) && _canfd != null)
- {
- var db = _canfd.DBCParser.MsgDatabase;
- if (_channel >= 0 && _channel < db.Count)
- {
- var targetMsg = db[(int)_channel]
- .FirstOrDefault(x => $"[0x{x.msg_id:X}]{x.msg_name}" == value);
-
- if (targetMsg != null && targetMsg.signal_Name != null)
- {
- Signal = new ObservableCollection(targetMsg.signal_Name);
- }
- else
- {
- Signal = new ObservableCollection();
- }
- }
- }
- else
- {
- Signal = new ObservableCollection();
- }
- _selectedMessage = value;
- RaisePropertyChanged();
- }
- }
- }
-
- private string _selectedSignal;
- public string SelectedSignal
- {
- get => _selectedSignal;
- set => SetProperty(ref _selectedSignal, value);
- }
-
- private string _signalValue;
- public string SignalValue
- {
- get => _signalValue;
- set => SetProperty(ref _signalValue, value);
- }
-
- private string _cycleSendInterval;
- public string CycleSendInterval
- {
- get => _cycleSendInterval;
- set => SetProperty(ref _cycleSendInterval, value);
- }
-
- private int _messageSendChannel = 0;
- public int MessageSendChannel
- {
- get => _messageSendChannel;
- set => SetProperty(ref _messageSendChannel, value);
- }
-
- public string BLFPath
- {
- get => _systemConfig?.DefaultBLFFilePath ?? "";
- set
- {
- if (_systemConfig != null && _systemConfig.DefaultBLFFilePath != value)
- {
- _systemConfig.DefaultBLFFilePath = value;
- RaisePropertyChanged();
- }
- }
- }
-
- public string DBCPath
- {
- get => _systemConfig?.DefaultDBCFilePath ?? "";
- set
- {
- if (_systemConfig != null && _systemConfig.DefaultDBCFilePath != value)
- {
- _systemConfig.DefaultDBCFilePath = value;
- RaisePropertyChanged();
- }
- }
- }
-
- private bool _IsSaved;
- public bool IsSaved
- {
- get => _IsSaved;
- set => SetProperty(ref _IsSaved, value);
- }
-
- public ObservableCollection DBCAutoLoadList
- {
- get => _systemConfig?.DBCAutoLoadList ?? new ObservableCollection();
- }
-
- private AutoDBCLoadItem _SelectedDcAutoLoad;
- public AutoDBCLoadItem SelectedDcAutoLoad
- {
- get => _SelectedDcAutoLoad;
- set => SetProperty(ref _SelectedDcAutoLoad, value);
- }
-
- // ===== 自定义报文发送属性 =====
- private APP_CHANNEL[] _appChannelNames = Enum.GetValues();
- public APP_CHANNEL[] APP_CHANNEL
- {
- get => _appChannelNames;
- set => SetProperty(ref _appChannelNames, value);
- }
-
- private APP_CHANNEL _aIdxChn;
- public APP_CHANNEL AIdxChn
- {
- get => _aIdxChn;
- set => SetProperty(ref _aIdxChn, value);
- }
-
- private int _aID;
- public int AID
- {
- get => _aID;
- set => SetProperty(ref _aID, value);
- }
-
- private bool _aIsTx;
- public bool AIsTx
- {
- get => _aIsTx;
- set => SetProperty(ref _aIsTx, value);
- }
-
- private bool _aIsExt;
- public bool AIsExt
- {
- get => _aIsExt;
- set => SetProperty(ref _aIsExt, value);
- }
-
- private bool _aIsRemote;
- public bool AIsRemote
- {
- get => _aIsRemote;
- set => SetProperty(ref _aIsRemote, value);
- }
-
- private byte _aDlc;
- public byte ADLC
- {
- get => _aDlc;
- set => SetProperty(ref _aDlc, value);
- }
-
- private byte[] _aDataArray;
- public byte[] ADataArray
- {
- get => _aDataArray;
- set => SetProperty(ref _aDataArray, value);
- }
-
- private bool _aIsFD = true;
- public bool AIsFD
- {
- get => _aIsFD;
- set => SetProperty(ref _aIsFD, value);
- }
-
- private bool _aIsBRS = false;
- public bool AIsBRS
- {
- get => _aIsBRS;
- set => SetProperty(ref _aIsBRS, value);
- }
-
- private bool _AutoSetting = true;
- public bool AutoSetting
- {
- get => _AutoSetting;
- set => SetProperty(ref _AutoSetting, value);
- }
-
- private string _CustomMessage = "[00,11,22,33,AA,BB,CC,DD]";
- public string CustomMessage
- {
- get => _CustomMessage;
- set => SetProperty(ref _CustomMessage, value);
- }
-
- private float _CustomSendCycleInterval = 0.0f;
- public float CustomSendCycleInterval
- {
- get => _CustomSendCycleInterval;
- set => SetProperty(ref _CustomSendCycleInterval, value);
- }
-
- //private bool _UpdateToDB;
- //public bool UpdateToDB
- //{
- // get => _UpdateToDB;
- // set => SetProperty(ref _UpdateToDB, value);
- //}
-
- // ===== 连接状态 =====
- private bool _IsDeviceOpened;
- public bool IsDeviceOpened
- {
- get => _IsDeviceOpened;
- set => SetProperty(ref _IsDeviceOpened, value);
- }
-
- private ObservableCollection _ChannelList;
- public ObservableCollection ChannelList
- {
- get => _ChannelList;
- set => SetProperty(ref _ChannelList, value);
- }
-
- private int _SelectedChannel = -1;
- public int SelectedChannel
- {
- get => _SelectedChannel;
- set
- {
- if (_SelectedChannel != value)
- {
- _SelectedChannel = value;
- if (value >= 0 && _canfd != null)
- {
- _canfd.初始化并启动通道((uint)value);
- }
- RaisePropertyChanged();
- }
- }
- }
- #endregion
-
- #region 命令
- public ICommand SelectBLFPathCommand { get; set; }
- public ICommand SaveBLFPathCommand { get; set; }
- public ICommand StartTranscribeCommand { get; set; }
- public ICommand EndTranscribeCommand { get; set; }
- public ICommand ConnectCanCommand { get; set; }
- public ICommand CloseCanCommand { get; set; }
- public ICommand ClearCycleCommand { get; set; }
- public ICommand UpLoadDBCCommand { get; set; }
- public ICommand ChangeDBCCommand { get; set; }
- public ICommand LoadDBCCommand { get; set; }
- public ICommand LoadMessageCommand { get; set; }
- public ICommand SetAndSendMessageCommand { get; set; }
- public ICommand DeleteDcAutoLoadCommand { get; set; }
- public ICommand SendCustomMessageCommand { get; set; }
- public ICommand LoadCommand { get; set; }
- #endregion
-
- public ZLGCANFDViewModel(IContainerProvider containerProvider) : base(containerProvider)
- {
- _systemConfig = containerProvider.Resolve();
- _deviceManager = containerProvider.Resolve();
- _canfd = _deviceManager.CANFD;
- SelectBLFPathCommand = new DelegateCommand(SelectBLFPath);
- SaveBLFPathCommand = new DelegateCommand(SaveBLFPath);
- StartTranscribeCommand = new DelegateCommand(StartTranscribe);
- EndTranscribeCommand = new DelegateCommand(EndTranscribe);
- ConnectCanCommand = new DelegateCommand(ConnectCan);
- CloseCanCommand = new DelegateCommand(CloseCan);
- ClearCycleCommand = new DelegateCommand(ClearCycle);
- UpLoadDBCCommand = new DelegateCommand(UpLoadDBC);
- ChangeDBCCommand = new DelegateCommand(ChangeDBC);
- LoadDBCCommand = new DelegateCommand(LoadDBC);
- SetAndSendMessageCommand = new DelegateCommand(SetAndSendMessage);
- LoadMessageCommand = new DelegateCommand(LoadMessage);
- DeleteDcAutoLoadCommand = new DelegateCommand(DeleteDcAutoLoad);
- SendCustomMessageCommand = new DelegateCommand(SendCustomMessage);
- _canfd.OnDbcMessageDecoded += OnDbcMessageDecoded;
- LoadCommand = new DelegateCommand(Load);
- }
-
- #region Dialog 生命周期
- public override void OnNavigatedTo(NavigationContext navigationContext)
- {
- if (_canfd != null)
- {
-
- }
-
- RaisePropertyChanged(nameof(BLFPath));
- RaisePropertyChanged(nameof(DBCPath));
- RaisePropertyChanged(nameof(DBCAutoLoadList));
- }
-
- public override void OnNavigatedFrom(NavigationContext navigationContext)
- {
- if (_canfd != null)
- {
- _canfd.OnDbcMessageDecoded -= OnDbcMessageDecoded;
- }
- _refreshCts?.Cancel();
- }
- #endregion
-
- #region 命令处理
- private void Load()
- {
- int maxCh = _canfd?.DBCParser.MaxChannels ?? 4;
- ChannelList = new ObservableCollection(Enumerable.Range(0, maxCh));
- }
-
- private void SendCustomMessage()
- {
- if (_canfd == null) return;
-
- try
- {
- ADataArray = 报文转换(CustomMessage);
- if (ADataArray.Length > byte.MaxValue) throw new Exception("报文数量超过上限!");
- if (AutoSetting)
- {
- ADLC = (byte)ADataArray.Length;
- }
- }
- catch (Exception ex)
- {
- ShowErrorMessageBox($"报文转换失败:{ex.Message}", () => { });
- return;
- }
-
- _canfd.发送自定义报文(
- (uint)AIdxChn,
- AID.ToString(),
- ADataArray,
- ADLC,
- AIsExt,
- AIsFD,
- AIsBRS);
- }
-
- private void DeleteDcAutoLoad()
- {
- if (SelectedDcAutoLoad != null)
- {
- DBCAutoLoadList.Remove(SelectedDcAutoLoad);
- }
- }
-
- private void LoadMessage()
- {
- if (_canfd == null) return;
-
- if (MessageSendChannel >= 0)
- {
- var db = _canfd.DBCParser.MsgDatabase;
- if (MessageSendChannel < db.Count)
- {
- Message = new ObservableCollection(
- db[MessageSendChannel].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}"));
- }
- }
- }
-
- private void SetAndSendMessage()
- {
- if (_canfd == null) return;
-
- if (int.TryParse(CycleSendInterval, out int sendPeriod) &&
- double.TryParse(SignalValue, out double SValue) &&
- MessageSendChannel >= 0)
- {
- _channel = (byte)MessageSendChannel;
- var message = SelectedMessage.Split(']')[1];
-
- // 通过 DBC 查找帧 ID
- var db = _canfd.DBCParser.MsgDatabase;
- if (MessageSendChannel < db.Count)
- {
- var targetMsg = db[MessageSendChannel]
- .FirstOrDefault(x => $"[0x{x.msg_id:X}]{x.msg_name}" == SelectedMessage);
-
- if (targetMsg != null)
- {
- _canfd.设置报文((uint)MessageSendChannel, targetMsg.msg_id.ToString(), SelectedSignal, SValue, sendPeriod, IsDirectlySend);
- }
- }
- }
- }
-
- private void UpLoadDBC()
- {
- if (_canfd == null) return;
-
- // 释放当前通道的 DBC
- if (DBCChannel >= 0)
- {
- _canfd.释放通道DBC((uint)DBCChannel);
- }
- }
-
- private void ChangeDBC()
- {
- var dialog = new OpenFileDialog
- {
- Title = "更换DBC文件",
- Filter = "DBC 文件 (*.dbc)|*.dbc|所有文件 (*.*)|*.*",
- DefaultExt = ".dbc",
- };
- if (dialog.ShowDialog() == true)
- {
- DBCPath = System.IO.Path.GetFullPath(dialog.FileName);
- }
- }
-
- private void LoadDBC()
- {
- if (_canfd == null || DBCChannel < 0) return;
-
- bool re = _canfd.加载通道DBC文件((uint)DBCChannel, DBCPath);
-
- if (re && IsSaved)
- {
- var item = DBCAutoLoadList.FirstOrDefault(s => s.DBCChannel == DBCChannel);
- if (item == null)
- {
- DBCAutoLoadList.Add(new AutoDBCLoadItem
- {
- DBCFilePath = DBCPath,
- DBCChannel = DBCChannel
- });
- }
- else
- {
- DBCAutoLoadList.Remove(item);
- DBCAutoLoadList.Add(new AutoDBCLoadItem
- {
- DBCFilePath = DBCPath,
- DBCChannel = DBCChannel
- });
- }
- ConfigService.Save(_systemConfig);
- }
- }
- private void ClearCycle()
- {
- _canfd?.停止所有循环发送();
- }
-
- private void CloseCan()
- {
- if (_canfd == null) return;
-
- _canfd.关闭CAN卡设备();
- IsDeviceOpened = false;
- _refreshCts?.Cancel();
- }
-
- private void ConnectCan()
- {
- if (_canfd == null) return;
-
- bool re = _canfd.打开设备();
- IsDeviceOpened = re;
-
- if (re)
- {
- // 启动实时报文刷新
- _refreshCts?.Cancel();
- _refreshCts = new CancellationTokenSource();
- _ = Refresh(_refreshCts.Token);
- }
- }
-
- private void EndTranscribe()
- {
- // TODO: BLF 录制功能在 ZLGCANFD 中未实现,暂不支持
- ShowInfoMessageBox("BLF 录制功能尚未在此硬件驱动中实现。", () => { });
- }
-
- private void StartTranscribe()
- {
- // TODO: BLF 录制功能在 ZLGCANFD 中未实现,暂不支持
- ShowInfoMessageBox("BLF 录制功能尚未在此硬件驱动中实现。", () => { });
- }
-
- private void SaveBLFPath()
- {
- // 路径已直接绑定到 SystemConfig,无需额外操作
- }
-
- private void SelectBLFPath()
- {
- var dialog = new SaveFileDialog
- {
- Title = "保存 CAN报文回放 BLF 文件",
- Filter = "BLF 文件 (*.blf)|*.blf|所有文件 (*.*)|*.*",
- DefaultExt = ".blf",
- FileName = "log.blf",
- OverwritePrompt = true
- };
- if (dialog.ShowDialog() == true)
- {
- BLFPath = System.IO.Path.GetFullPath(dialog.FileName);
- }
- }
-
- #endregion
-
- #region 辅助方法
- public byte[] 报文转换(string s)
- {
- s = s.Replace("[", string.Empty).Replace("]", string.Empty);
- var strs = s.Split(',', StringSplitOptions.RemoveEmptyEntries);
- byte[] bytes = new byte[strs.Length];
- for (int i = 0; i < strs.Length; i++)
- {
- bytes[i] = Convert.ToByte(strs[i], 16);
- }
- return bytes;
- }
-
- private async Task Refresh(CancellationToken ct = default)
- {
- while (!ct.IsCancellationRequested)
- {
- // 通过 OnDbcMessageDecoded 事件已实时更新 CanMessageList
- // 此处仅做周期性 UI 刷新触发
- await Task.Delay(50, ct);
- }
- }
-
- private void OnDbcMessageDecoded(uint channel, ZDBC.DBCMessage msg)
- {
- // DBC 解码后的报文回调
- Application.Current.Dispatcher.BeginInvoke(() =>
- {
- var msgName = System.Text.Encoding.Default.GetString(msg.strName).TrimEnd('\0');
- var find = CanMessageList.FirstOrDefault(s => s.报文ID == (int)msg.nID&& s.通道==channel);
- if (find != null)
- {
- find.通道 = (byte)channel;
- find.报文ID = (int)msg.nID;
- find.时间戳 = (ulong)DateTimeOffset.Now.ToUnixTimeMilliseconds(); ;
- find.长度 = (byte)msg.nSize;
- }
- else
- {
- CanMessageList.Add(new CanMessageShowVM
- {
- 通道 = (byte)channel,
- 报文ID = (int)msg.nID,
- 时间戳 = (ulong)DateTimeOffset.Now.ToUnixTimeMilliseconds(),
- 长度 = (byte)msg.nSize
- });
- }
- });
- }
-
- private string 十六进制字符串转换(System.Span s)
- {
- if (s == null || s.Length == 0)
- return "[]";
-
- var sb = new StringBuilder();
- sb.Append('[');
- for (int i = 0; i < s.Length; i++)
- {
- sb.Append("0x");
- sb.Append(s[i].ToString("X2"));
- if (i < s.Length - 1)
- sb.Append(", ");
- }
- sb.Append(']');
- return sb.ToString();
- }
- #endregion
- }
-}
diff --git a/CANModule/Views/ZLGCANFDView.xaml b/CANModule/Views/CANView.xaml
similarity index 75%
rename from CANModule/Views/ZLGCANFDView.xaml
rename to CANModule/Views/CANView.xaml
index b063f7c..61022fa 100644
--- a/CANModule/Views/ZLGCANFDView.xaml
+++ b/CANModule/Views/CANView.xaml
@@ -1,10 +1,11 @@
-
-
-
-
-
-
+ MouseLeftButtonDown="MouseLeftButtonDown">
@@ -38,59 +34,46 @@
Foreground="White"
VerticalAlignment="Center"
Margin="5,0,10,0" />
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
@@ -98,11 +81,13 @@
-
+
+ Command="{Binding ChangeDBCCommand}"
+ CommandParameter="更换DBC" />
+ Command="{Binding LoadDBCCommand}"
+ CommandParameter="加载DBC" />
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Command="{Binding SetAndSendMessageCommand}"
+ CommandParameter="设置" />
-
+ ItemsSource="{Binding APP_CHANNEL}"
+ />
@@ -250,10 +247,11 @@
-
+ IsChecked="{Binding UpdateToDB}" />
@@ -268,16 +266,20 @@
VerticalContentAlignment="Center" />
+ Command="{Binding SelectBLFPathCommand}"
+ CommandParameter="选择路径" />
+ Command="{Binding SaveBLFPathCommand}"
+ CommandParameter="保存路径" />
+ Command="{Binding StartTranscirbeCommand}"
+ CommandParameter="开始录制" />
+ Command="{Binding EndTranscirbeCommand}"
+ CommandParameter="结束录制" />
diff --git a/CANModule/Views/ZLGCANFDView.xaml.cs b/CANModule/Views/CANView.xaml.cs
similarity index 85%
rename from CANModule/Views/ZLGCANFDView.xaml.cs
rename to CANModule/Views/CANView.xaml.cs
index 2e4e7f6..4d9cf01 100644
--- a/CANModule/Views/ZLGCANFDView.xaml.cs
+++ b/CANModule/Views/CANView.xaml.cs
@@ -16,14 +16,15 @@ using System.Windows.Shapes;
namespace CANModule.Views
{
///
- /// ZLGCANFDView.xaml 的交互逻辑
+ /// CANView.xaml 的交互逻辑
///
- public partial class ZLGCANFDView : UserControl
+ public partial class CANView : UserControl
{
- public ZLGCANFDView()
+ public CANView()
{
InitializeComponent();
}
+
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
@@ -31,5 +32,7 @@ namespace CANModule.Views
Window.GetWindow(this)?.DragMove();
}
}
+
+
}
}
diff --git a/CANModule/Views/CollectCANSignalSettingView.xaml b/CANModule/Views/CollectCANSingalSettingView.xaml
similarity index 83%
rename from CANModule/Views/CollectCANSignalSettingView.xaml
rename to CANModule/Views/CollectCANSingalSettingView.xaml
index dfb3fa9..ea65d6d 100644
--- a/CANModule/Views/CollectCANSignalSettingView.xaml
+++ b/CANModule/Views/CollectCANSingalSettingView.xaml
@@ -1,23 +1,27 @@
+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: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="400"
+Width="1000">
+
+
+
+
+
@@ -79,11 +83,12 @@
Margin="10">
-
-
-
-
+
+
+
-
+
-
+
-
+
-
-
+
+
-
\ No newline at end of file
+
diff --git a/MonitorModule/ViewModels/Dialogs/ValueLimitViewModel.cs b/MonitorModule/ViewModels/Dialogs/ValueLimitViewModel.cs
index 6c6b01a..29d5fcc 100644
--- a/MonitorModule/ViewModels/Dialogs/ValueLimitViewModel.cs
+++ b/MonitorModule/ViewModels/Dialogs/ValueLimitViewModel.cs
@@ -7,11 +7,11 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Windows.Input;
+using TSMasterCAN;
using UIShare.GlobalVariable;
using UIShare.PubEvent;
using UIShare.UIViewModel;
using UIShare.ViewModelBase;
-using ZLGUSBCANFD;
namespace MonitorModule.ViewModels.Dialogs
{
@@ -197,10 +197,10 @@ namespace MonitorModule.ViewModels.Dialogs
///
private IEnumerable<(string DisplayName, string Fingerprint, string MethodName)> DiscoverCanSignals()
{
- if (_deviceManager?.CANFD?.DBCParser?.MsgDatabase == null) yield break;
+ if (_deviceManager?.CANFD == null) yield break;
if (_systemConfig?.ConfigurationList == null) yield break;
- var msgDb = _deviceManager.CANFD.DBCParser.MsgDatabase;
+ var msgDb = DBCParse.MsgDatabase;
string canDeviceFingerprint = _deviceManager.GetCanDeviceFingerprint();
foreach (var cfg in _systemConfig.ConfigurationList)
{
@@ -331,10 +331,10 @@ namespace MonitorModule.ViewModels.Dialogs
private void OnDbcLoaded(DBCLoadedArgs args)
{
if (args.Scope != _systemConfig?.Title) return;
- if (_deviceManager?.CANFD?.DBCParser?.MsgDatabase == null) return;
+ if (_deviceManager?.CANFD == null) return;
int channel = (int)args.Channel;
- var msgDb = _deviceManager.CANFD.DBCParser.MsgDatabase;
+ var msgDb = DBCParse.MsgDatabase;
if (channel < 0 || channel >= msgDb.Count) return;
string canDeviceFingerprint = _deviceManager.GetCanDeviceFingerprint();
diff --git a/MonitorModule/ViewModels/MonitorViewModel.cs b/MonitorModule/ViewModels/MonitorViewModel.cs
index 4843448..f796a02 100644
--- a/MonitorModule/ViewModels/MonitorViewModel.cs
+++ b/MonitorModule/ViewModels/MonitorViewModel.cs
@@ -18,11 +18,11 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Threading;
+using TSMasterCAN;
using UIShare.GlobalVariable;
using UIShare.PubEvent;
using UIShare.UIViewModel;
using UIShare.ViewModelBase;
-using ZLGUSBCANFD;
namespace MonitorModule.ViewModels
@@ -535,9 +535,9 @@ namespace MonitorModule.ViewModels
private void RefreshConfiguredCanSignals()
{
if (_systemConfig?.ConfigurationList == null || _systemConfig.ConfigurationList.Count == 0) return;
- if (_deviceManager?.CANFD?.DBCParser?.MsgDatabase == null) return;
+ if (_deviceManager?.CANFD == null) return;
- var msgDb = _deviceManager.CANFD.DBCParser.MsgDatabase;
+ var msgDb = DBCParse.MsgDatabase;
foreach (var channel in _systemConfig.ConfigurationList.Select(c => c.Channel).Distinct())
{
if (channel < 0 || channel >= msgDb.Count) continue;
@@ -633,10 +633,9 @@ namespace MonitorModule.ViewModels
private void OnDbcLoaded(DBCLoadedArgs args)
{
if (args.Scope != TestStatus) return;
- if (_deviceManager?.CANFD?.DBCParser?.MsgDatabase == null) return;
-
+ if (_deviceManager?.CANFD == null) return;
int channel = (int)args.Channel;
- var msgDb = _deviceManager.CANFD.DBCParser.MsgDatabase;
+ var msgDb = DBCParse.MsgDatabase;
if (channel < 0 || channel >= msgDb.Count) return;
RefreshCanSignalsForChannel(args.Channel, msgDb[channel]);
diff --git a/TSMasterCAN/CAN.cs b/TSMasterCAN/CAN.cs
new file mode 100644
index 0000000..029c0d6
--- /dev/null
+++ b/TSMasterCAN/CAN.cs
@@ -0,0 +1,679 @@
+using Common.Attributes;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Text.Json;
+using TSMaster;
+namespace TSMasterCAN
+{
+ [ACPCommand]
+ public class CAN : IDisposable
+ {
+ #region 静态成员
+
+ public static event Action? ConnectEvent;
+ public static event Action? DisConnectEvent;
+ public static bool ConnectFlag { get; set; } = false;
+
+ ///
+ /// 实时接收到的 CAN 报文缓存(按报文 ID 索引,保留最新帧)。
+ /// 供 CANViewModel.Refresh 等界面轮询读取。
+ ///
+ public static ConcurrentDictionary RealTimeMessages { get; } = new();
+
+ #endregion
+
+ #region 实例字段与属性
+
+ /// 设备类型号(43 = USBCANFD-400U 等,TSMaster 中作为配置参考保留)
+ public uint DeviceType { get; }
+ /// 设备索引
+ public uint DeviceIndex { get; }
+ /// 最大通道数
+ public int MaxChannels { get; }
+ /// 仲裁域波特率
+ public string ABitBaud { get; }
+ /// 数据域波特率
+ public string DBitBaud { get; }
+ /// 是否开启终端电阻
+ public bool EnableTerminalResistance { get; }
+
+ /// DBC 解析器(提供 MsgDatabase、MaxChannels 等访问)
+ public DBCParse DBCParser => DBCParse.Instance;
+
+ ///
+ /// DBC 报文解码事件:当接收到 CAN 帧并通过 DBC 解码后触发。
+ /// 参数:(通道号, 解码后的报文信息)
+ ///
+ public event Action? OnDbcMessageDecoded;
+
+ private bool _disposed;
+ private bool _isOpened;
+ private TCANFDQueueEvent_Win32? _instanceListener;
+
+ #endregion
+
+ #region 构造函数
+
+ /// 默认构造函数(兼容 SystemConfig.CANFD = new() 等场景)
+ public CAN() : this(43, 0, 4, "500000", "2000000", true) { }
+
+ ///
+ /// 带配置参数的构造函数(兼容原 ZLG 设备管理流程)。
+ ///
+ /// 设备类型号
+ /// 设备索引
+ /// 最大通道数
+ /// 仲裁域波特率
+ /// 数据域波特率
+ /// 是否开启终端电阻
+ public CAN(uint deviceType, uint deviceIndex, int maxChannels, string aBitBaud, string dBitBaud, bool enableTerminalResistance)
+ {
+ DeviceType = deviceType;
+ DeviceIndex = deviceIndex;
+ MaxChannels = maxChannels;
+ ABitBaud = aBitBaud;
+ DBitBaud = dBitBaud;
+ EnableTerminalResistance = enableTerminalResistance;
+ }
+
+ #endregion
+
+ #region 实例方法 — 设备管理(替代原 ZLG 实例方法)
+
+ ///
+ /// 打开设备:初始化 TSMaster 库 → 设置通道数 → 配置波特率 → 连接 → 启动 RBS → 注册监听。
+ ///
+ /// true 表示成功
+ public bool 打开设备()
+ {
+ if (_isOpened) return true;
+ if (ConnectFlag) { _isOpened = true; return true; }
+
+ try
+ {
+ // 1. 初始化 TSMaster 库
+ var re = Init("ACP");
+ if (re != 0)
+ {
+ Debug.WriteLine($"TSMaster 初始化失败,错误代码:{re}");
+ return false;
+ }
+
+ // 2. 设置通道数
+ TsMasterApi.tsapp_set_can_channel_count(MaxChannels);
+
+ // 3. 配置各通道波特率
+ float arbKbps = float.Parse(ABitBaud) / 1000f;
+ float dataKbps = float.Parse(DBitBaud) / 1000f;
+ for (int ch = 0; ch < MaxChannels; ch++)
+ {
+ TsMasterApi.tsapp_configure_baudrate_canfd(
+ ch, arbKbps, dataKbps,
+ TLIBCANFDControllerType.lfdtISOCAN,
+ TLIBCANFDControllerMode.lfdmNormal,
+ EnableTerminalResistance);
+ }
+
+ // 4. 连接硬件
+ re = Connect();
+ if (re != 0)
+ {
+ Debug.WriteLine($"CAN 连接失败,错误代码:{re}");
+ return false;
+ }
+
+ // 5. 注册接收监听(用于 DBC 信号解码广播)
+ _instanceListener = new TCANFDQueueEvent_Win32(OnCanFdReceived);
+ RegisterListener(_instanceListener);
+
+ _isOpened = true;
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"打开设备异常:{ex.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// 关闭 CAN 卡设备:注销监听 → 断开连接。
+ ///
+ public void 关闭CAN卡设备()
+ {
+ if (!_isOpened && !ConnectFlag) return;
+
+ try
+ {
+ if (_instanceListener != null)
+ {
+ UnRegisterListener(_instanceListener);
+ _instanceListener = null;
+ }
+ DisConnect();
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"关闭CAN卡设备异常:{ex.Message}");
+ }
+ finally
+ {
+ _isOpened = false;
+ }
+ }
+
+ ///
+ /// 初始化并启动指定通道(配置波特率,TSMaster 在 Connect 时已自动启动所有通道)。
+ ///
+ /// 通道号
+ public void 初始化并启动通道(uint channel)
+ {
+ if (channel >= MaxChannels) return;
+ try
+ {
+ float arbKbps = float.Parse(ABitBaud) / 1000f;
+ float dataKbps = float.Parse(DBitBaud) / 1000f;
+ TsMasterApi.tsapp_configure_baudrate_canfd(
+ (int)channel, arbKbps, dataKbps,
+ TLIBCANFDControllerType.lfdtISOCAN,
+ TLIBCANFDControllerMode.lfdmNormal,
+ EnableTerminalResistance);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"初始化通道 {channel} 异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 加载通道 DBC 文件。
+ ///
+ /// 通道号
+ /// DBC 文件路径
+ /// true 表示加载成功
+ public bool 加载通道DBC文件(uint channel, string filePath)
+ {
+ try
+ {
+ var re = LoadDBC(filePath, [(int)channel], out _);
+ return re == 0;
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"加载通道 {channel} DBC 文件异常:{ex.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// CAN FD 接收回调:接收原始帧 → 查找 DBC → 解码信号 → 触发 OnDbcMessageDecoded 事件。
+ ///
+ private void OnCanFdReceived(ref int AObj, ref TLIBCANFD AData)
+ {
+ if (_disposed) return;
+
+ // 始终缓存最新报文,供界面轮询刷新
+ int identifier = AData.FIdentifier;
+ var canfdCopy = AData;
+ RealTimeMessages[identifier] = canfdCopy;
+
+ if (OnDbcMessageDecoded == null) return;
+
+ try
+ {
+ uint channel = AData.FIdxChn;
+ if (channel >= DBCParse.MsgDatabase.Count) return;
+
+ // 在 DBC 数据库中查找匹配的报文
+ var msgList = DBCParse.MsgDatabase[(int)channel];
+ var match = msgList.FirstOrDefault(m => m.msg_id == identifier);
+ if (match == null || match.signal_Name == null || match.signal_Name.Length == 0) return;
+
+ // 解码各信号值
+ var signals = new DBCSignal[match.signal_Name.Length];
+ for (int i = 0; i < match.signal_Name.Length; i++)
+ {
+ double value = 0;
+ TsMasterApi.tsdb_get_signal_value_canfd(ref canfdCopy, match.msg_name, match.signal_Name[i], ref value);
+ signals[i] = new DBCSignal
+ {
+ strName = Encoding.Default.GetBytes(match.signal_Name[i]),
+ nRawvalue = value,
+ nFactor = 1,
+ nOffset = 0
+ };
+ }
+
+ var decoded = new DBCMessage
+ {
+ nID = (uint)identifier,
+ nSignalCount = signals.Length,
+ vSignals = signals
+ };
+
+ OnDbcMessageDecoded?.Invoke(channel, decoded);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"DBC 信号解码异常:{ex.Message}");
+ }
+ }
+
+ #endregion
+
+ #region IDisposable
+
+ public void Dispose()
+ {
+ if (_disposed) return;
+ _disposed = true;
+ 关闭CAN卡设备();
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+
+ ///
+ /// 初始化TSMasterCAN
+ ///
+ ///
+ ///
+ ///
+ [Browsable(false)]
+ public static int Init(string ProjectName, string? filePath = null)
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ return TsMasterApi.initialize_lib_tsmaster(ProjectName);
+ }
+ else
+ {
+ return TsMasterApi.initialize_lib_tsmaster_with_project(ProjectName, Path.GetFullPath(filePath));
+ }
+ }
+
+ ///
+ /// 释放TSMasterCAN
+ ///
+ [Browsable(false)]
+ public static void Release()
+ {
+ TsMasterApi.finalize_lib_tsmaster();
+ }
+
+ public static int obj = 0;
+ public static TCANFDQueueEvent_Win32 listener;
+ [Browsable(false)]
+ public static int RegisterListener(TCANFDQueueEvent_Win32 listenEvent)
+ {
+ listener = listenEvent;
+ var re = TsMasterApi.tsapp_register_event_canfd(ref obj, listener);
+ Debug.Assert(re == 0);
+ return re;
+ }
+
+ [Browsable(false)]
+ public static int UnRegisterListener(TCANFDQueueEvent_Win32 listenEvent = null)
+ {
+ if (listenEvent is not null)
+ {
+ listener = listenEvent;
+ }
+ var re = TsMasterApi.tsapp_unregister_event_canfd(ref obj, listener);
+ Debug.Assert(re == 0);
+ return re;
+ }
+
+ ///
+ /// 连接
+ ///
+ ///
+ public static int Connect()
+ {
+
+ var re = TsMasterApi.tsapp_connect();
+ if (re == 0)
+ {
+ re = TsMasterApi.tscom_can_rbs_start();
+ if (re == 0)
+ {
+ ConnectFlag = true;
+ Task.Run(() => ConnectEvent?.Invoke());
+ }
+ else
+ {
+ Debug.WriteLine($"CAN_RBS启动失败,错误代码:{re}");
+ }
+ }
+ else
+ {
+ Debug.WriteLine($"CAN连接失败,错误代码:{re}");
+ return re;
+ }
+ return re;
+ }
+
+ ///
+ /// 断开
+ ///
+ ///
+ public static int DisConnect()
+ {
+ var re = TsMasterApi.tsapp_disconnect();
+ //Debug.Assert(re == 0);
+ if (re == 0)
+ {
+ ConnectFlag = false;
+ Task.Run(() => DisConnectEvent?.Invoke());
+ }
+ else
+ {
+ Debug.WriteLine($"断开CAN连接失败,错误代码:{re}");
+ }
+
+
+ return re;
+ }
+
+ ///
+ /// 加载DBC
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Browsable(false)]
+ public static int LoadDBC(string filePath, int[] channel, out uint databaseID)
+ {
+ databaseID = 0;
+
+ var re = TsMasterApi.tsdb_load_can_db(Path.GetFullPath(filePath), string.Join(",", channel), ref databaseID);
+ foreach (var item in channel)
+ {
+ DBCParse.parse(databaseID, item);
+ DBCParse.rbs_parse(databaseID, item);
+ }
+
+ return re;
+ }
+
+ ///
+ /// 卸载DBC
+ ///
+ ///
+ ///
+ [Browsable(false)]
+ public static int UnLoadDBC(uint? databaseID = null)
+ {
+ if (databaseID == null)
+ {
+ return TsMasterApi.tsdb_unload_can_dbs();
+ }
+ else
+ {
+ return TsMasterApi.tsdb_unload_can_db(databaseID.Value);
+ }
+ }
+
+ ///
+ /// 开始记录日志
+ ///
+ ///
+ ///
+ public static int StartLogging(string filePath)
+ {
+ return TsMasterApi.tsapp_start_logging(Path.GetFullPath(filePath));
+ }
+
+ ///
+ /// 结束记录日志
+ ///
+ ///
+ public static int StopLogging()
+ {
+ return TsMasterApi.tsapp_stop_logging();
+ }
+
+ ///
+ /// 弹出通道映射窗口
+ ///
+ ///
+ ///
+ [Browsable(false)]
+ public static int ShowChannelMappingWindow(bool isWait = false)
+ {
+ return TsMasterApi.tsapp_show_tsmaster_window("Hardware", isWait);
+ }
+
+ ///
+ /// 获取信号值
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static double GetSignalValue(byte channel, string AMsgName, string ASgnName)
+ {
+ double value = double.NaN;
+ var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
+ var re = TsMasterApi.tsdb_get_signal_value_canfd(ref find.ACANFD, AMsgName, ASgnName, ref value);
+
+ return value;
+ }
+
+ ///
+ /// 获取信号值
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Browsable(false)]
+ public static int GetSignalValue(byte channel, string AMsgName, string ASgnName, ref double value)
+ {
+ var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
+ return TsMasterApi.tsdb_get_signal_value_canfd(ref find.ACANFD, AMsgName, ASgnName, ref value);
+ }
+
+ ///
+ /// 获取信号值
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+
+ [Browsable(false)]
+ public static int GetSignalValue(ref TLIBCANFD ACANFD, string AMsgName, string ASgnName, ref double value)
+ {
+ return TsMasterApi.tsdb_get_signal_value_canfd(ref ACANFD, AMsgName, ASgnName, ref value);
+ }
+
+ ///
+ /// 设置信号值
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int SetSignalValue(byte channel, string AMsgName, string ASgnName, double AValue, bool isSend = false, float sendPeriod = 0)
+ {
+ var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
+ find.ACANFD.FIdxChn = channel;
+ var re = TsMasterApi.tsdb_set_signal_value_canfd(ref find.ACANFD, AMsgName, ASgnName, AValue);
+ Debug.Assert(re == 0);
+ if (re != 0) throw new Exception($"设置报文失败!返回代码{re}");
+ if (re != 0) return re;
+ if (isSend)
+ {
+ if (sendPeriod == 0)
+ {
+ return TsMasterApi.tsapp_transmit_canfd_async(ref find.ACANFD);
+ }
+ else
+ {
+ return TsMasterApi.tsapp_add_cyclic_msg_canfd(ref find.ACANFD, sendPeriod);
+ }
+ }
+ return 0;
+ }
+
+
+ ///
+ /// 设置信号值
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int SetSignalValue(APP_CHANNEL channel, string AMsgName, float sendPeriod = 0)
+ {
+ var find = DBCParse.MsgDatabase[(byte)channel].First(s => s.msg_name == AMsgName);
+ find.ACANFD.FIdxChn = (byte)channel;
+ if (sendPeriod == 0)
+ {
+ return TsMasterApi.tsapp_transmit_canfd_async(ref find.ACANFD);
+ }
+ else
+ {
+ return TsMasterApi.tsapp_add_cyclic_msg_canfd(ref find.ACANFD, sendPeriod);
+ }
+ }
+
+ ///
+ /// 发送自定义报文
+ ///
+ ///
+ [Browsable(false)]
+ public static int SetMsg(TLIBCANFD msg)
+ {
+ return TsMasterApi.tsapp_transmit_canfd_async(ref msg);
+ }
+
+ ///
+ /// 设置报文
+ ///
+ /// 通道
+ /// DBC数据库ID
+ /// 报文数组
+ public static void SetMsg(APP_CHANNEL channel, int ID, byte[] bytes)
+ {
+ var find = DBCParse.MsgDatabase[(byte)channel].FirstOrDefault(s => s.ACANFD.FIdentifier == ID);
+ if (find != null)
+ {
+ Array.Copy(bytes, 0, find.ACANFD.FData, 0, Math.Min(bytes.Length, find.ACANFD.FData.Length));
+ }
+ }
+
+ ///
+ /// 发送自定义报文
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int SendMsg(APP_CHANNEL AIdxChn, int AID, bool AIsTx, bool AIsExt,
+ bool AIsRemote, byte ADLC, byte[] ADataArray, bool AIsFD = true, bool AIsBRS = false,
+ bool isUpdateDBCDatabase = false, float sendPeriod = 0)
+ {
+ var send = new TLIBCANFD
+ {
+ FIdxChn = (byte)AIdxChn,
+ FProperties = 0,
+ FIdentifier = AID,
+ FDLC = ADLC,
+ FTimeUS = 0uL,
+ FData = new byte[64],
+ FFDProperties = 0,
+ FIsTx = AIsTx,
+ FIsError = false,
+ FIsExt = AIsExt,
+ FIsRemote = AIsRemote,
+ FIsFD = AIsFD,
+ FIsBRS = AIsBRS
+ };
+ int length = Math.Min(ADataArray.Length, 64);
+ Array.Copy(ADataArray, 0, send.FData, 0, length);
+ int re;
+ if (sendPeriod == 0)
+ {
+ re = TsMasterApi.tsapp_transmit_canfd_async(ref send);
+ }
+ else
+ {
+ re = TsMasterApi.tsapp_add_cyclic_msg_canfd(ref send, sendPeriod);
+ }
+
+ if (isUpdateDBCDatabase)
+ {
+ var find = DBCParse.MsgDatabase[(byte)AIdxChn].FirstOrDefault(s => s.ACANFD.FIdentifier == send.FIdentifier);
+ if (find != null)
+ {
+ Array.Copy(send.FData, 0, find.ACANFD.FData, 0, Math.Min(ADataArray.Length, find.ACANFD.FData.Length));
+ }
+ }
+ return re;
+ }
+
+ ///
+ /// 添加循环发送报文
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static int AddCyclicMsg(byte channel, string AMsgName, float sendPeriod)
+ {
+ var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
+ find.ACANFD.FIdxChn = channel;
+ return TsMasterApi.tsapp_add_cyclic_msg_canfd(ref find.ACANFD, sendPeriod);
+ }
+
+ ///
+ /// 清除循环发送的报文
+ ///
+ ///
+ public static int DeleteCyclicMsgs()
+ {
+ return TsMasterApi.tsapp_delete_cyclic_msgs();
+ }
+
+ ///
+ /// 获取错误提示
+ ///
+ /// 错误代码
+ ///
+ public static string GetErrorDescription(int errorCode)
+ {
+ IntPtr ADesc = IntPtr.Zero;
+ TsMasterApi.tsapp_get_error_description(errorCode, ref ADesc);
+
+ if (ADesc == IntPtr.Zero) return $"未知错误代码: {errorCode}";
+
+ // 假设返回的是 ANSI 字符串(如 C 的 char*)
+ string? description = Marshal.PtrToStringAnsi(ADesc);
+
+ return description ?? $"未知错误代码: {errorCode}";
+ }
+
+ }
+}
diff --git a/TSMasterCAN/DBCParse.cs b/TSMasterCAN/DBCParse.cs
new file mode 100644
index 0000000..e515d6f
--- /dev/null
+++ b/TSMasterCAN/DBCParse.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+using TSMaster;
+
+namespace TSMasterCAN
+{
+ public struct can_network
+ {
+ [JsonInclude]
+ public string network_name;
+ [JsonInclude]
+ public can_node[] can_nodes;
+
+ }
+ public struct can_node
+ {
+ [JsonInclude]
+ public string node_name;
+ [JsonInclude]
+ public can_message[] tx_can_Messages;
+ [JsonInclude]
+ public can_message[] rx_can_Messages;
+ }
+ public struct can_message
+ {
+ [JsonInclude]
+ public string message_name;
+ [JsonInclude]
+ public string[] signals;
+ }
+
+ 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 TLIBCANFD ACANFD;
+ }
+ public enum Msg_Type
+ {
+ CAN = 0,
+ CANFD = 1,
+ }
+ ///
+ /// DBC 文件信息类型枚举,用于指定 tsdb_get_can_db_info 查询的内容类型。
+ ///
+ public enum DBCINFO
+ {
+ /// 网络名称
+ NETWORK_Name = 0,
+
+ /// CAN 报文总数
+ CAN_MSG_COUNT = 11,
+ /// CAN FD 报文总数
+ CANFD_MSG_COUNT = 12,
+ /// 节点总数
+ NODE_COUNT = 14,
+
+ /// 信号名称
+ SIGNAL_NAME = 33,
+
+ /// CAN 报文类型
+ CAN_MSG_TYPE = 40,
+ /// CAN 报文 DLC(数据长度码)
+ CAN_MSG_DLC = 41,
+ /// CAN 报文 ID
+ CAN_MSG_ID = 42,
+ /// CAN 报文周期
+ CAN_MSG_CYCLIC = 43,
+ /// CAN 报文名称
+ CAN_MSG_NAME = 44,
+ /// CAN 报文信号数量
+ CAN_MSG_SIGNAL_COUNT = 47,
+ /// CAN 报文信号名称索引
+ CAN_MSG_SIGNAL_NAME_INDEX = 48,
+
+ /// CAN FD 报文类型
+ CANFD_MSG_TYPE = 60,
+ /// CAN FD 报文 DLC(数据长度码)
+ CANFD_MSG_DLC = 61,
+ /// CAN FD 报文 ID
+ CANFD_MSG_ID = 62,
+ /// CAN FD 报文周期
+ CANFD_MSG_CYCLIC = 63,
+ /// CAN FD 报文名称
+ CANFD_MSG_NAME = 64,
+ /// CAN FD 报文信号数量
+ CANFD_MSG_SIGNAL_COUNT = 67,
+ /// CAN FD 报文信号名称索引
+ CANFD_MSG_SIGNAL_NAME_INDEX = 68,
+
+ /// 节点名称
+ NODE_Name = 101,
+ /// 节点发送 CAN 报文数量
+ NODE_TX_CAN_COUNT = 103,
+ /// 节点发送 CAN 报文索引
+ NODE_TX_CAN_MESSAGE_INDEX = 104,
+ /// 节点接收 CAN 报文数量
+ NODE_RX_CAN_COUNT = 105,
+ /// 节点接收 CAN 报文索引
+ NODE_RX_CAN_MESSAGE_INDEX = 106,
+ /// 节点发送 CAN FD 报文数量
+ NODE_TX_CANFD_COUNT = 107,
+ /// 节点发送 CAN FD 报文索引
+ NODE_TX_CANFD_MESSAGE_INDEX = 108,
+ /// 节点接收 CAN FD 报文数量
+ NODE_RX_CANFD_COUNT = 109,
+ /// 节点接收 CAN FD 报文索引
+ NODE_RX_CANFD_MESSAGE_INDEX = 110,
+ }
+
+ ///
+ /// DBC 解码后的信号信息(替代原 ZLG ZDBC.DBCSignal)。
+ ///
+ public struct DBCSignal
+ {
+ /// 信号名称(原始字节,兼容 Encoding.Default 解码)
+ public byte[] strName;
+ /// 原始值(TSMaster tsdb_get_signal_value_canfd 返回的物理值)
+ public double nRawvalue;
+ /// 因子(TSMaster 返回物理值,因子固定为 1)
+ public double nFactor;
+ /// 偏移(TSMaster 返回物理值,偏移固定为 0)
+ public double nOffset;
+ }
+
+ ///
+ /// DBC 解码后的报文信息(替代原 ZLG ZDBC.DBCMessage)。
+ /// 在 CAN 接收回调中对原始 TLIBCANFD 帧解码后构建此对象并触发 OnDbcMessageDecoded 事件。
+ ///
+ public class DBCMessage
+ {
+ /// 报文 ID
+ public uint nID;
+ /// 信号数量
+ public int nSignalCount;
+ /// 信号数组
+ public DBCSignal[] vSignals;
+ }
+
+ public class DBCParse
+ {
+ private static DBCParse? _instance;
+ /// 单例实例,供 CAN.DBCParser 属性使用(MsgDatabase 等成员为 static,实例仅用于属性访问兼容)。
+ public static DBCParse Instance => _instance ??= new DBCParse();
+
+ /// 最大通道数(等于 MsgDatabase 的维度)
+ public int MaxChannels => MsgDatabase.Count;
+
+ public static List> MsgDatabase { get; set; } =
+ [.. Enumerable.Range(0, 12).Select(_ => new List<_Msg_>())];
+ public static can_network can_Network;
+ public static string tsdb_get_can_db_info(uint ADatabaseId, int AType, int AIndex, int ASubIndex)
+ {
+ nint tmpInt = new nint();
+ int ret = TsMasterApi.tsdb_get_can_db_info(ADatabaseId, AType, AIndex, ASubIndex, ref tmpInt);
+ if (ret == 0)
+ {
+ return Marshal.PtrToStringAnsi(tmpInt) ?? "";
+ }
+ else
+ return "";
+ }
+
+ public static void parse(uint Aid, int channel)
+ {
+ int CANcount = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_COUNT, 0, 0));
+ for (int i = 0; i < CANcount; i++)
+ {
+ _Msg_ temp = new _Msg_();
+ temp.msg_type = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_TYPE, i, 0));
+ temp.msg_dlc = byte.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_DLC, i, 0));
+ temp.msg_id = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_ID, i, 0));
+ temp.msg_name = tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_NAME, i, 0);
+ temp.msg_cyclic = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_CYCLIC, i, 0));
+ temp.signal_Name = new string[int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_SIGNAL_COUNT, i, 0))];
+ for (int signalcount = 0; signalcount < temp.signal_Name.Length; signalcount++)
+ {
+ temp.signal_Name[signalcount] = tsdb_get_can_db_info(Aid, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_SIGNAL_NAME_INDEX, i, signalcount)), 0);
+ }
+ temp.msg_brs = 0;
+ temp.ACANFD = new TLIBCANFD(APP_CHANNEL.CHN1,
+ temp.msg_id,
+ true,
+ temp.msg_type == 1 || temp.msg_type == 4 ? true : false,
+ false, temp.msg_dlc,
+ temp.msg_type < 2 ? false : true,
+ false);
+ MsgDatabase[channel].Add(temp);
+
+ }
+
+ CANcount = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_COUNT, 0, 0));
+ for (int i = 0; i < CANcount; i++)
+ {
+ _Msg_ temp = new _Msg_();
+ temp.msg_type = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_TYPE, i, 0));
+ temp.msg_dlc = byte.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_DLC, i, 0));
+ temp.msg_id = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_ID, i, 0));
+ temp.msg_name = tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_NAME, i, 0);
+ temp.msg_cyclic = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_CYCLIC, i, 0));
+ temp.signal_Name = new string[int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_SIGNAL_COUNT, i, 0))];
+ for (int signalcount = 0; signalcount < temp.signal_Name.Length; signalcount++)
+ {
+ temp.signal_Name[signalcount] = tsdb_get_can_db_info(Aid, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_SIGNAL_NAME_INDEX, i, signalcount)), 0);
+ }
+ temp.msg_brs = int.Parse(tsdb_get_can_db_info(Aid, 69, i, 0));
+ temp.ACANFD = new TLIBCANFD(APP_CHANNEL.CHN1, temp.msg_id, true, temp.msg_type == 1 || temp.msg_type == 4 ? true : false, false, temp.msg_dlc, temp.msg_type < 2 ? false : true, temp.msg_brs == 1 ? true : false);
+ MsgDatabase[channel].Add(temp);
+ }
+ MsgDatabase[channel].Sort((a, b) => a.msg_id.CompareTo(b.msg_id));
+ }
+
+ public static void rbs_parse(uint AID, int channel)
+ {
+ can_Network = new can_network();
+ can_Network.network_name = tsdb_get_can_db_info(AID, (int)DBCINFO.NETWORK_Name, 0, 0);
+ int Node_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_COUNT, 0, 0));
+ can_Network.can_nodes = new can_node[Node_count];
+ for (int i = 0; i < Node_count; i++)
+ {
+ can_Network.can_nodes[i].node_name = tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_Name, i, 0);
+ int tx_can_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CAN_COUNT, i, 0));
+ int tx_canfd_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CANFD_COUNT, i, 0));
+
+ int rx_can_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CAN_COUNT, i, 0));
+ int rx_canfd_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CANFD_COUNT, i, 0));
+
+ //获取tx_can结构体
+ can_Network.can_nodes[i].tx_can_Messages = new can_message[tx_can_count + tx_canfd_count];
+
+ can_Network.can_nodes[i].rx_can_Messages = new can_message[rx_can_count + rx_canfd_count];
+ //获取报文名以及信号名
+ //1 get can_message idnex
+ //2 get can message name
+ //3 get signal count
+ //4 get signal name
+ int tx_index = -1;
+ for (int tx_can = 0; tx_can < tx_can_count; tx_can++)
+ {
+ int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CAN_MESSAGE_INDEX, i, tx_can));
+ can_Network.can_nodes[i].tx_can_Messages[tx_can].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_NAME, can_message_idnex, 0);
+
+ can_Network.can_nodes[i].tx_can_Messages[tx_can].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
+ for (int signalcount = 0; signalcount < can_Network.can_nodes[i].tx_can_Messages[tx_can].signals.Length; signalcount++)
+ {
+ can_Network.can_nodes[i].tx_can_Messages[tx_can].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
+ }
+
+ tx_index = tx_can;
+ }
+ for (int tx_can = 0; tx_can < tx_canfd_count; tx_can++, tx_index++)
+ {
+ int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CANFD_MESSAGE_INDEX, i, tx_can));
+ can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_NAME, can_message_idnex, 0);
+
+ can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
+ for (int signalcount = 0; signalcount < can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].signals.Length; signalcount++)
+ {
+ can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
+ }
+ }
+
+ int rx_index = -1;
+ for (int tx_can = 0; tx_can < rx_can_count; tx_can++)
+ {
+ int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CAN_MESSAGE_INDEX, i, tx_can));
+ can_Network.can_nodes[i].rx_can_Messages[tx_can].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_NAME, can_message_idnex, 0);
+
+ can_Network.can_nodes[i].rx_can_Messages[tx_can].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
+ for (int signalcount = 0; signalcount < can_Network.can_nodes[i].rx_can_Messages[tx_can].signals.Length; signalcount++)
+ {
+ can_Network.can_nodes[i].rx_can_Messages[tx_can].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
+ }
+
+ rx_index = tx_can;
+ }
+ for (int tx_can = 0; tx_can < rx_canfd_count; tx_can++, rx_index++)
+ {
+ int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CANFD_MESSAGE_INDEX, i, tx_can));
+ can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_NAME, can_message_idnex, 0);
+
+ can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
+ for (int signalcount = 0; signalcount < can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].signals.Length; signalcount++)
+ {
+ can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
+ }
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/TSMasterCAN/Interop.TSMasterAPI.dll b/TSMasterCAN/Interop.TSMasterAPI.dll
new file mode 100644
index 0000000..1d1400b
Binary files /dev/null and b/TSMasterCAN/Interop.TSMasterAPI.dll differ
diff --git a/TSMasterCAN/TSMaster.dll b/TSMasterCAN/TSMaster.dll
new file mode 100644
index 0000000..a34dd33
Binary files /dev/null and b/TSMasterCAN/TSMaster.dll differ
diff --git a/ZLGUSBCANFD/ZLGUSBCANFD.csproj b/TSMasterCAN/TSMasterCAN.csproj
similarity index 52%
rename from ZLGUSBCANFD/ZLGUSBCANFD.csproj
rename to TSMasterCAN/TSMasterCAN.csproj
index 2e99c7b..0a6e281 100644
--- a/ZLGUSBCANFD/ZLGUSBCANFD.csproj
+++ b/TSMasterCAN/TSMasterCAN.csproj
@@ -1,14 +1,20 @@
-
+
net8.0
- enable
enable
+ false
+ enable
-
+
+
+
+
+ ..\CanDriver\bin\Debug\net8.0\Interop.TSMasterAPI.dll
+
diff --git a/UIShare/GlobalVariable/CANSignalBroadcaster.cs b/UIShare/GlobalVariable/CANSignalBroadcaster.cs
index 67f70a0..32ef9ca 100644
--- a/UIShare/GlobalVariable/CANSignalBroadcaster.cs
+++ b/UIShare/GlobalVariable/CANSignalBroadcaster.cs
@@ -4,8 +4,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using TSMasterCAN;
using UIShare.PubEvent;
-using ZLGUSBCANFD;
namespace UIShare.GlobalVariable
{
@@ -22,8 +22,7 @@ namespace UIShare.GlobalVariable
private bool _disposed;
/// 已订阅解码事件的 CANFD 实例 → 委托 映射
- private readonly Dictionary> _handlers = new();
-
+ private readonly Dictionary> _handlers = new();
public CANSignalBroadcaster(GlobalInfo globalInfo, IEventAggregator eventAggregator)
{
_globalInfo = globalInfo;
@@ -48,7 +47,7 @@ namespace UIShare.GlobalVariable
if (_handlers.ContainsKey(canfd)) continue;
// 使用闭包捕获指纹,回调时即可区分不同 CAN 卡
- Action handler = (channel, msg) => OnDbcMessageDecoded(fingerprint, channel, msg);
+ Action handler = (channel, msg) => OnDbcMessageDecoded(fingerprint, channel, msg);
canfd.OnDbcMessageDecoded += handler;
_handlers[canfd] = handler;
}
@@ -65,7 +64,7 @@ namespace UIShare.GlobalVariable
///
/// DBC 解码回调:提取所有信号,向引用该 CAN 设备的作用域广播,并检查报警。
///
- private void OnDbcMessageDecoded(string canFingerprint, uint channel, ZDBC.DBCMessage msg)
+ private void OnDbcMessageDecoded(string canFingerprint, uint channel, DBCMessage msg)
{
if (_disposed) return;
diff --git a/UIShare/GlobalVariable/DeviceManager.cs b/UIShare/GlobalVariable/DeviceManager.cs
index ee4eb56..6db7b4d 100644
--- a/UIShare/GlobalVariable/DeviceManager.cs
+++ b/UIShare/GlobalVariable/DeviceManager.cs
@@ -10,9 +10,10 @@ using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
+using TSMasterCAN;
using UIShare.PubEvent;
using UIShare.UIViewModel;
-using ZLGUSBCANFD;
+using TSMasterCAN;
namespace UIShare.GlobalVariable
{
@@ -34,7 +35,7 @@ namespace UIShare.GlobalVariable
/// 类名 → Type 的反射缓存(仅扫描一次)。
private static readonly IReadOnlyDictionary _deviceTypeMap = BuildDeviceTypeMap();
- public ZLGCANFD CANFD { get; set; }
+ public CAN CANFD { get; set; }
public IOBoardGroup IOGroup { get; set; }
public DeviceManager(SystemConfig systemConfig, GlobalInfo globalInfo, IEventAggregator eventAggregator)
@@ -116,10 +117,10 @@ namespace UIShare.GlobalVariable
try
{
- // 按指纹全局唯一创建 ZLGCANFD 实例(maxChannels 默认 4,对应 USBCANFD-400U)
+ // 按指纹全局唯一创建同星 CAN 实例(maxChannels 默认 4,对应 USBCANFD-400U)
// 波特率与终端电阻从 CANConfigVM 传入,初始化并启动通道 时直接使用
- var canLazy = _globalInfo.CanPool.GetOrAdd(fingerprint, key => new Lazy(() =>
- new ZLGCANFD(config.CANConfig.DeviceType, config.CANConfig.DeviceIndex, 4,
+ var canLazy = _globalInfo.CanPool.GetOrAdd(fingerprint, key => new Lazy(() =>
+ new CAN(config.CANConfig.DeviceType, config.CANConfig.DeviceIndex, 4,
config.CANConfig.ABitBaud, config.CANConfig.DBitBaud, config.CANConfig.EnableTerminalResistance)));
_systemConfig.CANFD = canLazy.Value;
diff --git a/UIShare/GlobalVariable/GlobalInfo.cs b/UIShare/GlobalVariable/GlobalInfo.cs
index 305e81e..01d911f 100644
--- a/UIShare/GlobalVariable/GlobalInfo.cs
+++ b/UIShare/GlobalVariable/GlobalInfo.cs
@@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using ZLGUSBCANFD;
+using TSMasterCAN;
namespace UIShare.GlobalVariable
{
@@ -21,7 +21,7 @@ namespace UIShare.GlobalVariable
public ConcurrentDictionary> HardwarePool { get; set; }
/// CAN 硬件指纹 → ZLGCANFD 实例的并发池,确保同一 CAN 卡全局只创建一个驱动实例。
- public ConcurrentDictionary> CanPool { get; set; }
+ public ConcurrentDictionary> CanPool { get; set; }
/// 硬件指纹 → 正在使用该设备的作用域名称列表,用于引用计数与安全销毁。
public ConcurrentDictionary>> DeviceAndScopeDic { get; set; }
@@ -49,7 +49,7 @@ namespace UIShare.GlobalVariable
ConfigDic = new();
ScopeDic = new();
HardwarePool = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase);
- CanPool = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase);
+ CanPool = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase);
DeviceAndScopeDic = new ConcurrentDictionary>>(StringComparer.OrdinalIgnoreCase);
CurrentScope = "default";
}
diff --git a/UIShare/GlobalVariable/SystemConfig.cs b/UIShare/GlobalVariable/SystemConfig.cs
index 21f2ec0..d945803 100644
--- a/UIShare/GlobalVariable/SystemConfig.cs
+++ b/UIShare/GlobalVariable/SystemConfig.cs
@@ -8,8 +8,8 @@ using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
+using TSMasterCAN;
using UIShare.UIViewModel;
-using ZLGUSBCANFD;
using static UIShare.UIViewModel.ParameterVM;
namespace UIShare.GlobalVariable
@@ -40,7 +40,7 @@ namespace UIShare.GlobalVariable
/// 监测通道持久化配置列表(包含 Fingerprint、MethodName、IsDisplayed)
///
public ObservableCollection MonitorChannels = new();
- public ZLGCANFD CANFD = new();
+ public CAN CANFD = new();
[JsonIgnore]
public ObservableCollection ParameterList = new()
{
diff --git a/UIShare/UIShare.csproj b/UIShare/UIShare.csproj
index 2946368..60b5c1e 100644
--- a/UIShare/UIShare.csproj
+++ b/UIShare/UIShare.csproj
@@ -23,6 +23,6 @@
-
+
diff --git a/UIShare/UIViewModel/CanMessageShowVM.cs b/UIShare/UIViewModel/CanMessageShowVM.cs
index d406b6c..96e9724 100644
--- a/UIShare/UIViewModel/CanMessageShowVM.cs
+++ b/UIShare/UIViewModel/CanMessageShowVM.cs
@@ -7,7 +7,10 @@
private int _报文ID;
private double _时间戳;
private byte _长度;
-
+ private bool _FD;
+ private bool _IsTx;
+ private byte[] _Bytes = new byte[64];
+ private string _报文 = "[]";
// 通道属性
public byte 通道
@@ -37,6 +40,32 @@
set { SetProperty(ref _长度, value); }
}
-
+ // 是否FD帧
+ public bool FD
+ {
+ get { return _FD; }
+ set { SetProperty(ref _FD, value); }
+ }
+
+ // 是否发送帧
+ public bool IsTx
+ {
+ get { return _IsTx; }
+ set { SetProperty(ref _IsTx, value); }
+ }
+
+ // 原始字节数据
+ public byte[] Bytes
+ {
+ get { return _Bytes; }
+ set { SetProperty(ref _Bytes, value); }
+ }
+
+ // 报文十六进制字符串
+ public string 报文
+ {
+ get { return _报文; }
+ set { SetProperty(ref _报文, value); }
+ }
}
}
diff --git a/ZLGUSBCANFD/USBCANFD.cs b/ZLGUSBCANFD/USBCANFD.cs
deleted file mode 100644
index b63e527..0000000
--- a/ZLGUSBCANFD/USBCANFD.cs
+++ /dev/null
@@ -1,983 +0,0 @@
-using Common.Attributes;
-using Logger;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace ZLGUSBCANFD
-{
- [ACPCommand]
- public class ZLGCANFD : IDisposable
- {
- // 硬件设备与通道句柄
- private IntPtr _deviceHandle = IntPtr.Zero;
- private readonly IntPtr[] _channelHandles;
-
- // 每个通道分配独立的 DBC 引擎句柄与锁,彻底解决台架间DBC冲突与锁竞争
- private readonly uint[] _dbcHandles;
- private readonly bool[] _isDbcLoadedArray;
- private readonly object[] _channelLocks; // 通道级细粒度锁
-
- // 异步高性能接收线程控制
- private volatile bool _isRunning = false;
- private volatile bool _isClosing = false; // 关闭流程标志:通知循环发送任务尽快退出
- private readonly List _receiveThreads = new List();
-
- // DBC 循环发送任务管理:Key = (通道号, 帧ID),Value = (CTS, Task)
- private readonly ConcurrentDictionary<(uint 通道号, uint 帧ID), (CancellationTokenSource Cts, Task SendTask)> _cyclicSenders = new ConcurrentDictionary<(uint, uint), (CancellationTokenSource, Task)>();
-
- // 信号值持久化覆盖表:Key = (通道号, 帧ID),Value = 信号名 → 物理值
- // 每次 设置报文 会累积写入此表,发送时以 DBC 初始值为底再叠加此表覆盖值
- private readonly ConcurrentDictionary<(uint 通道号, uint 帧ID), Dictionary> _signalOverrides = new ConcurrentDictionary<(uint, uint), Dictionary>();
-
- // 动态硬件参数
- private readonly uint _deviceType; // 76: USBCANFD-400U
- private readonly uint _deviceIndex; // 设备索引
- private readonly int _maxChannels; // 动态通道数
-
- // 通道波特率与终端电阻配置(构造时传入,所有通道共用)
- private readonly string _abitBaud;
- private readonly string _dbitBaud;
- private readonly bool _enableTerminalResistance;
-
- ///
- /// 当前 CAN 卡专属的 DBC 解析器,按通道隔离报文数据库。
- ///
- public ZLGDBCParser DBCParser { get; }
-
- ///
- /// 事件:当接收到 CAN/CANFD 报文并且通过 DBC 成功解析后触发
- /// 参数:uint 通道号 (0,1,2,3), ZDBC.DBCMessage 解析后的DBC消息结构体
- ///
- public event Action? OnDbcMessageDecoded;
-
- public ZLGCANFD(uint deviceType = 76, uint deviceIndex = 0, int maxChannels = 4,
- string abitBaud = "500000", string dbitBaud = "2000000", bool enableTerminalResistance = true)
- {
- _deviceType = deviceType;
- _deviceIndex = deviceIndex;
- _maxChannels = maxChannels;
- _abitBaud = abitBaud;
- _dbitBaud = dbitBaud;
- _enableTerminalResistance = enableTerminalResistance;
-
- // 初始化通道相关状态数组
- _channelHandles = new IntPtr[_maxChannels];
- _dbcHandles = new uint[_maxChannels];
- _isDbcLoadedArray = new bool[_maxChannels];
- _channelLocks = new object[_maxChannels];
- DBCParser = new ZLGDBCParser(_maxChannels);
-
- for (int i = 0; i < _maxChannels; i++)
- {
- _channelHandles[i] = IntPtr.Zero;
- _dbcHandles[i] = 0;
- _isDbcLoadedArray[i] = false;
- _channelLocks[i] = new object();
- }
- }
-
- #region 1. 硬件连接与通道初始化
-
- ///
- /// 仅仅打开设备,不做具体的通道波特率配置(留给具体的台架去分别配置)
- ///
- public virtual bool 打开设备()
- {
- if (_deviceHandle != IntPtr.Zero) return true;
- _deviceHandle = ZLGCAN.ZCAN_OpenDevice(ZLGCAN.ZCAN_USBCANFD_400U, _deviceIndex, 0);
- return _deviceHandle != IntPtr.Zero;
- }
-
- ///
- /// 针对特定通道进行参数初始化并启动(使用构造时传入的波特率与终端电阻配置)
- ///
- public virtual bool 初始化并启动通道(uint 通道号)
- {
- _isClosing = false; // 重置关闭标志,允许循环发送
- if (_deviceHandle == IntPtr.Zero) throw new InvalidOperationException("请先调用 '打开设备()' 才能初始化通道。");
- if (通道号 >= _maxChannels) return false;
-
- lock (_channelLocks[通道号])
- {
- // 如果已经启动过,直接退出
- if (_channelHandles[通道号] != IntPtr.Zero)
- {
- return true;
- //ZLGCAN.ZCAN_ResetCAN(_channelHandles[通道号]);
- }
-
- // 1. 设置该通道专属的仲裁域与数据域波特率
- if (ZLGCAN.ZCAN_SetValue(_deviceHandle, $"{通道号}/canfd_abit_baud_rate", _abitBaud) != 1) return false;
- if (ZLGCAN.ZCAN_SetValue(_deviceHandle, $"{通道号}/canfd_dbit_baud_rate", _dbitBaud) != 1) return false;
-
- // 2. 设置该通道专属内部终端电阻状态
- string resistanceStr = _enableTerminalResistance ? "1" : "0";
- if (ZLGCAN.ZCAN_SetValue(_deviceHandle, $"{通道号}/initenal_resistance", resistanceStr) != 1) return false;
-
- // 3. 规范配置通道结构体
- ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG config = new ZLGCAN.ZCAN_CHANNEL_INIT_CONFIG();
- config.can_type = 1; // 1 代表 CANFD 模式
- config.config.canfd.mode = 0; // 0 代表正常工作模式
-
- IntPtr pConfig = Marshal.AllocHGlobal(Marshal.SizeOf(config));
- Marshal.StructureToPtr(config, pConfig, true);
- _channelHandles[通道号] = ZLGCAN.ZCAN_InitCAN(_deviceHandle, 通道号, pConfig);
- Marshal.FreeHGlobal(pConfig);
-
- if (_channelHandles[通道号] == IntPtr.Zero) return false;
-
- // 4. 启动 CAN 通道
- if (ZLGCAN.ZCAN_StartCAN(_channelHandles[通道号]) != 1) return false;
-
- // 5. 为该通道启动专属的独立后台高性能轮询接收线程(如果尚未启动轮询)
- if (!_isRunning) _isRunning = true;
-
- int chnIdx = (int)通道号;
- Thread rxThread = new Thread(() => 接收轮询核心(_channelHandles[chnIdx], (uint)chnIdx))
- {
- IsBackground = true,
- Name = $"ZLGCANFD_Dev{_deviceIndex}_CH{chnIdx}_RxThread"
- };
- _receiveThreads.Add(rxThread);
- rxThread.Start();
-
- return true;
- }
- }
-
- public virtual void 关闭CAN卡设备()
- {
- _isClosing = true; // 通知循环发送任务尽快退出
- _isRunning = false; // 通知接收轮询线程退出
- 停止所有循环发送(); // 内部会等待所有循环发送 Task 退出
-
- // 等待所有接收轮询线程真正退出(每个最多 1 秒)
- foreach (var thread in _receiveThreads)
- {
- if (thread.IsAlive)
- thread.Join(1000);
- }
- _receiveThreads.Clear();
-
- // 动态复位所有通道并释放 DBC(使用 TryEnter 防止死锁)
- for (uint i = 0; i < _maxChannels; i++)
- {
- if (Monitor.TryEnter(_channelLocks[i], TimeSpan.FromSeconds(2)))
- {
- try
- {
- if (_channelHandles[i] != IntPtr.Zero)
- {
- ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]);
- _channelHandles[i] = IntPtr.Zero;
- }
- 释放通道DBC(i);
- }
- finally
- {
- Monitor.Exit(_channelLocks[i]);
- }
- }
- else
- {
- // 锁超时:循环发送 Task 可能仍阻塞在原生 API 调用中,强制清理
- LoggerHelper.Info($"[ZLGCANFD] 关闭通道 {i} 时获取锁超时,强制清理");
- if (_channelHandles[i] != IntPtr.Zero)
- {
- try { ZLGCAN.ZCAN_ResetCAN(_channelHandles[i]); } catch { }
- _channelHandles[i] = IntPtr.Zero;
- }
- 释放通道DBC(i);
- }
- }
-
- // 关闭设备主句柄
- if (_deviceHandle != IntPtr.Zero)
- {
- ZLGCAN.ZCAN_CloseDevice(_deviceHandle);
- _deviceHandle = IntPtr.Zero;
- }
-
- _isClosing = false;
- }
-
- #endregion
-
- #region 2. DBC 矩阵文件操作
-
- ///
- /// 指定通道加载特定的 DBC 文件(支持不同通道加载不同的DBC矩阵)
- ///
- public virtual bool 加载通道DBC文件(uint 通道号, string dbcFilePath)
- {
- if (通道号 >= _maxChannels) return false;
-
- lock (_channelLocks[通道号])
- {
- try
- {
- if (_isDbcLoadedArray[通道号]) return true;
- //加载前先卸载
- 释放通道DBC(通道号);
- uint chDbcHandle = ZDBC.ZDBC_Init();
- if (chDbcHandle == 0) return false;
-
- IntPtr ptrPath = Marshal.StringToHGlobalAnsi(dbcFilePath);
- bool success = ZDBC.ZDBC_LoadFile(chDbcHandle, ptrPath);
- Marshal.FreeHGlobal(ptrPath);
-
- if (success)
- {
- _dbcHandles[通道号] = chDbcHandle;
- _isDbcLoadedArray[通道号] = true;
- DBCParser.ParseAndLoadToDatabase(chDbcHandle, (int)通道号);
- }
- else
- {
- ZDBC.ZDBC_Release(chDbcHandle);
- }
- return success;
- }
- catch
- {
- return false;
- }
- }
- }
-
- public virtual void 释放通道DBC(uint 通道号)
- {
- if (通道号 >= _maxChannels) return;
-
- lock (_channelLocks[通道号])
- {
- if (_isDbcLoadedArray[通道号] && _dbcHandles[通道号] != 0)
- {
- ZDBC.ZDBC_Release(_dbcHandles[通道号]);
- _dbcHandles[通道号] = 0;
- _isDbcLoadedArray[通道号] = false;
- DBCParser.MsgDatabase[(int)通道号].Clear();
- }
- }
- }
-
- #endregion
-
- #region 3. 轮询接收与实时自动化 DBC 解码
-
- private void 接收轮询核心(IntPtr channelHandle, uint channelIndex)
- {
- const int bufferSize = 100;
- int canStructSize = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_Receive_Data));
- int canfdStructSize = Marshal.SizeOf(typeof(ZLGCAN.ZCAN_ReceiveFD_Data));
- int dbcMsgSize = Marshal.SizeOf(typeof(ZDBC.DBCMessage));
-
- IntPtr ptrCanBuffer = Marshal.AllocHGlobal(canStructSize * bufferSize);
- IntPtr ptrCanFDBuffer = Marshal.AllocHGlobal(canfdStructSize * bufferSize);
- IntPtr ptrDbcMsg = Marshal.AllocHGlobal(dbcMsgSize);
-
- try
- {
- while (_isRunning)
- {
- bool currentTurnHasData = false;
-
- // 1. 自动提取并解析经典 CAN 帧
- uint canNum = ZLGCAN.ZCAN_GetReceiveNum(channelHandle, 0);
- if (canNum > 0)
- {
- uint actualRecv = ZLGCAN.ZCAN_Receive(channelHandle, ptrCanBuffer, bufferSize, 5);
- for (int i = 0; i < actualRecv; i++)
- {
- IntPtr framePtr = IntPtr.Add(ptrCanBuffer, i * canStructSize);
-
- // 只锁定当前通道的DBC句柄进行解码,高并发完全不卡顿
- lock (_channelLocks[channelIndex])
- {
- if (_isDbcLoadedArray[channelIndex] && ZDBC.ZDBC_Decode(_dbcHandles[channelIndex], ptrDbcMsg, framePtr, 1, 0))
- {
- var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage));
- OnDbcMessageDecoded?.Invoke(channelIndex, msg);
- }
- }
- }
- currentTurnHasData = true;
- }
-
- // 2. 自动提取并解析高速 CANFD 帧
- uint canfdNum = ZLGCAN.ZCAN_GetReceiveNum(channelHandle, 1);
- if (canfdNum > 0)
- {
- uint actualRecvFd = ZLGCAN.ZCAN_ReceiveFD(channelHandle, ptrCanFDBuffer, bufferSize, 5);
- for (int i = 0; i < actualRecvFd; i++)
- {
- IntPtr framePtr = IntPtr.Add(ptrCanFDBuffer, i * canfdStructSize);
-
- lock (_channelLocks[channelIndex])
- {
- if (_isDbcLoadedArray[channelIndex] && ZDBC.ZDBC_Decode(_dbcHandles[channelIndex], ptrDbcMsg, framePtr, 1, 1))
- {
- var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage));
- OnDbcMessageDecoded?.Invoke(channelIndex, msg);
- }
- }
- }
- currentTurnHasData = true;
- }
-
- if (!currentTurnHasData)
- {
- Thread.Sleep(2);
- }
- }
- }
- finally
- {
- Marshal.FreeHGlobal(ptrCanBuffer);
- Marshal.FreeHGlobal(ptrCanFDBuffer);
- Marshal.FreeHGlobal(ptrDbcMsg);
- }
- }
-
- #endregion
-
- #region 4. DBC 自动打包与智能报文发送
-
- ///
- /// 发送一条 DBC 定义报文。
- ///
- /// 通道号
- /// DBC 中定义的帧 ID
- /// 信号名称 → 物理值;只设置字典中包含的信号,其余信号保持 DBC 默认值
- /// 0 = 只发送一次;>0 = 按指定间隔循环发送(毫秒)
- /// 1 = CANFD,0 = CAN
- /// 是否成功启动/发送
- public virtual bool 发送DBC定义报文(
- uint 通道号,
- uint 帧ID,
- Dictionary 信号物理值字典,
- int 循环间隔毫秒 = 0,
- int 是否使用CANFD = 1)
- {
- if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
- if (!_isDbcLoadedArray[通道号]) throw new InvalidOperationException($"通道 {通道号} 的 DBC 协议未加载,无法执行打包发送指令。");
- if (循环间隔毫秒 < 0) throw new ArgumentOutOfRangeException(nameof(循环间隔毫秒), "循环间隔必须大于或等于 0。");
- if (信号物理值字典 == null || 信号物理值字典.Count == 0)
- throw new ArgumentException("信号物理值字典不能为空。", nameof(信号物理值字典));
-
- if (循环间隔毫秒 == 0)
- {
- // 单次发送:同步执行
- lock (_channelLocks[通道号])
- {
- return 发送DBC定义报文单次(通道号, 帧ID, 信号物理值字典, 是否使用CANFD);
- }
- }
-
- // 循环发送:先停止同通道同帧 ID 的旧循环,再启动新循环
- 停止循环发送(通道号, 帧ID);
-
- var cts = new CancellationTokenSource();
- var sendTask = Task.Run(async () =>
- {
- while (!cts.Token.IsCancellationRequested)
- {
- if (_isClosing) break; // 关闭流程中立即退出
- try
- {
- lock (_channelLocks[通道号])
- {
- if (_channelHandles[通道号] == IntPtr.Zero || _isClosing) break;
- 发送DBC定义报文单次(通道号, 帧ID, 信号物理值字典, 是否使用CANFD);
- }
-
- await Task.Delay(循环间隔毫秒, cts.Token);
- }
- catch (OperationCanceledException)
- {
- break;
- }
- catch (Exception ex)
- {
- Logger.LoggerHelper.Error($"[ZLGCANFD] 循环发送 DBC 报文失败: {ex.Message}");
- break;
- }
- }
-
- // 清理:仅当字典中存的仍然是本任务创建的 CTS 时才移除,避免误删新任务的 CTS
- if (_cyclicSenders.TryGetValue((通道号, 帧ID), out var current) && ReferenceEquals(current.Cts, cts))
- {
- _cyclicSenders.TryRemove((通道号, 帧ID), out _);
- }
- cts.Dispose();
- }, cts.Token);
-
- _cyclicSenders[(通道号, 帧ID)] = (cts, sendTask);
-
- return true;
- }
-
- ///
- /// 停止指定通道、指定帧 ID 的循环发送。
- ///
- public virtual void 停止循环发送(uint 通道号, uint 帧ID)
- {
- if (_cyclicSenders.TryRemove((通道号, 帧ID), out var entry))
- {
- entry.Cts.Cancel();
- // 不在这里 Dispose,由 Task 的清理代码负责释放,避免 Task 仍在使用已释放的 Token
- }
- }
-
- ///
- /// 停止所有 DBC 循环发送任务。
- ///
- public virtual void 停止所有循环发送()
- {
- var entries = _cyclicSenders.ToArray();
-
- // 1. 取消所有 CTS(不 Dispose,由 Task 清理代码负责)
- foreach (var kvp in entries)
- {
- kvp.Value.Cts.Cancel();
- }
-
- // 2. 等待所有循环发送 Task 退出(最多 3 秒)
- var tasks = new List();
- foreach (var kvp in entries)
- {
- if (!kvp.Value.SendTask.IsCompleted)
- tasks.Add(kvp.Value.SendTask);
- }
- if (tasks.Count > 0)
- {
- try
- {
- Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(3));
- }
- catch { /* 忽略等待异常 */ }
- }
-
- _cyclicSenders.Clear();
- }
-
- ///
- /// 清除指定通道、指定帧 ID 的信号覆盖值,恢复为 DBC 初始值。
- ///
- public virtual void 清除信号覆盖(uint 通道号, uint 帧ID)
- {
- if (_signalOverrides.TryRemove((通道号, 帧ID), out var dict))
- {
- lock (dict) dict.Clear();
- }
- }
-
- ///
- /// 清除指定通道所有帧的信号覆盖值。
- ///
- public virtual void 清除通道信号覆盖(uint 通道号)
- {
- foreach (var key in _signalOverrides.Keys)
- {
- if (key.通道号 == 通道号 && _signalOverrides.TryRemove(key, out var dict))
- {
- lock (dict) dict.Clear();
- }
- }
- }
-
-
-
- ///
- /// 单次发送 DBC 报文(调用方已持有通道锁)。
- ///
- private bool 发送DBC定义报文单次(uint 通道号, uint 帧ID, Dictionary 信号物理值字典, int 是否使用CANFD)
- {
- uint chDbcHandle = _dbcHandles[通道号];
-
- IntPtr ptrDbcMsg = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCMessage)));
- IntPtr ptrCount = Marshal.AllocHGlobal(sizeof(uint));
- Marshal.WriteInt32(ptrCount, 1);
-
- try
- {
- if (!ZDBC.ZDBC_GetMessageById(chDbcHandle, 帧ID, ptrDbcMsg)) return false;
- var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage));
-
- // 根据传入的物理值设置对应信号的原始值
- for (int i = 0; i < msg.nSignalCount; i++)
- {
- var signal = msg.vSignals[i];
- string signalName = Encoding.Default.GetString(signal.strName).TrimEnd('\0');
- if (信号物理值字典.TryGetValue(signalName, out double physicalValue))
- {
- signal.nRawvalue = 物理值转原始值(signal, physicalValue);
- msg.vSignals[i] = signal;
- }
- }
-
- Marshal.StructureToPtr(msg, ptrDbcMsg, true);
-
- if (是否使用CANFD == 0)
- {
- IntPtr ptrCanFrame = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.can_frame)));
- try
- {
- if (!ZDBC.ZDBC_Encode(chDbcHandle, ptrCanFrame, ptrCount, ptrDbcMsg, 0)) return false;
-
- ZLGCAN.can_frame canFrame = (ZLGCAN.can_frame)Marshal.PtrToStructure(ptrCanFrame, typeof(ZLGCAN.can_frame));
- canFrame.__pad |= 0x20;
-
- ZLGCAN.ZCAN_Transmit_Data txData = new ZLGCAN.ZCAN_Transmit_Data { frame = canFrame, transmit_type = 2 };
- IntPtr pTx = Marshal.AllocHGlobal(Marshal.SizeOf(txData));
- try
- {
- Marshal.StructureToPtr(txData, pTx, true);
- return ZLGCAN.ZCAN_Transmit(_channelHandles[通道号], pTx, 1) == 1;
- }
- finally
- {
- Marshal.FreeHGlobal(pTx);
- }
- }
- finally
- {
- Marshal.FreeHGlobal(ptrCanFrame);
- }
- }
- else
- {
- IntPtr ptrCanFDFrame = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZLGCAN.canfd_frame)));
- try
- {
- if (!ZDBC.ZDBC_Encode(chDbcHandle, ptrCanFDFrame, ptrCount, ptrDbcMsg, 1)) return false;
-
- ZLGCAN.canfd_frame canfdFrame = (ZLGCAN.canfd_frame)Marshal.PtrToStructure(ptrCanFDFrame, typeof(ZLGCAN.canfd_frame));
- canfdFrame.flags |= 0x20;
-
- ZLGCAN.ZCAN_TransmitFD_Data txFdData = new ZLGCAN.ZCAN_TransmitFD_Data { frame = canfdFrame, transmit_type = 2 };
- IntPtr pTxFd = Marshal.AllocHGlobal(Marshal.SizeOf(txFdData));
- try
- {
- Marshal.StructureToPtr(txFdData, pTxFd, true);
- return ZLGCAN.ZCAN_TransmitFD(_channelHandles[通道号], pTxFd, 1) == 1;
- }
- finally
- {
- Marshal.FreeHGlobal(pTxFd);
- }
- }
- finally
- {
- Marshal.FreeHGlobal(ptrCanFDFrame);
- }
- }
- }
- finally
- {
- Marshal.FreeHGlobal(ptrDbcMsg);
- Marshal.FreeHGlobal(ptrCount);
- }
- }
-
- ///
- /// 不依赖通道锁的物理值到原始值转换。
- ///
- private static ulong 物理值转原始值(ZDBC.DBCSignal 信号定义, double 实际物理值)
- {
- IntPtr pSignal = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCSignal)));
- IntPtr pValue = Marshal.AllocHGlobal(sizeof(double));
- try
- {
- Marshal.StructureToPtr(信号定义, pSignal, true);
- Marshal.StructureToPtr(实际物理值, pValue, true);
- return ZDBC.ZDBC_CalcRawValue(pSignal, pValue);
- }
- finally
- {
- Marshal.FreeHGlobal(pSignal);
- Marshal.FreeHGlobal(pValue);
- }
- }
-
- #endregion
-
- #region 4.1 报文设置与发送 (支持智能进制转换)
- ///
- /// 设置并发送指定信号值(帧 ID 支持 string 兼容模式)。
- /// 其余未指定信号使用 DBC 中定义的初始值填充,避免总线数据被意外清零。
- ///
- /// CAN/CANFD 通道索引
- /// 对应报文的帧 ID(可以是 "26"、"0x1A"、"1A")
- /// DBC 中定义的英文信号名称(不区分大小写)
- /// 要写入的实际物理数值
- /// 0 = 单次发送;>0 = 周期循环发送(单位毫秒)
- /// 操作是否成功
- public virtual bool 设置报文(uint 通道号, string 帧IDStr, string 信号名称, double 物理值, int 循环发送间隔毫秒 = 0, bool 直接发送 = false)
- {
- if (!TryParseFrameId(帧IDStr, out uint 帧ID))
- {
- Console.WriteLine($"[ZLGCANFD] 设置报文失败: 无法解析的帧 ID '{帧IDStr}'");
- return false;
- }
-
- if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
- if (!_isDbcLoadedArray[通道号]) return false;
- if (string.IsNullOrWhiteSpace(信号名称)) return false;
-
- // 将本次设置的信号值写入持久化覆盖表(累积,不会丢失之前设置的值)
- var overrides = _signalOverrides.GetOrAdd((通道号, 帧ID), _ => new Dictionary(StringComparer.OrdinalIgnoreCase));
- lock (overrides)
- {
- overrides[信号名称] = 物理值;
- }
-
- // 构建发送字典:DBC 初始值 + 持久化覆盖表(已包含本次设置)
- var merged = 构建报文发送字典(通道号, 帧ID);
-
- if (直接发送) return 发送DBC定义报文(通道号, 帧ID, merged, 循环发送间隔毫秒);
- else return true;
- }
-
- ///
- /// 发送报文:以 DBC 中所有信号的初始值作为默认值发送(帧 ID 支持 string 兼容模式)。
- /// 如果之前调用 设置报文 保存过覆盖值,则会优先使用覆盖值。
- ///
- /// CAN/CANFD 通道索引
- /// DBC 中定义的帧 ID(可以是 "26"、"0x1A"、"1A")
- /// 0 = 单次发送;>0 = 周期循环发送(毫秒)
- /// 1 = 以 CANFD 格式发送;0 = 经典 CAN 格式
- 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 (!_isDbcLoadedArray[通道号]) return false;
- if (循环发送间隔毫秒 < 0) throw new ArgumentOutOfRangeException(nameof(循环发送间隔毫秒));
-
- var merged = 构建报文发送字典(通道号, 帧ID);
- return 发送DBC定义报文(通道号, 帧ID, merged, 循环发送间隔毫秒, 是否使用CANFD);
- }
-
- ///
- /// 发送自定义报文(原始字节,帧 ID 支持 string 兼容模式)。
- ///
- /// CAN/CANFD 通道索引
- /// 帧 ID(可以是 "26"、"0x1A"、"1A");扩展帧会自动置位 0x80000000
- /// 原始帧数据
- /// 数据长度;CANFD 仅允许 0-8,12,16,20,24,32,48,64
- /// 是否为 29 位扩展帧
- /// true = CANFD;false = 经典 CAN
- /// CANFD 是否开启波特率加速
- public virtual bool 发送自定义报文(
- uint 通道号,
- string 帧IDStr,
- byte[] 原始数据,
- byte dlcLength,
- bool 是否是扩展帧 = false,
- bool 是否是CANFD = 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 (原始数据 == null) return false;
-
- // 扩展帧需要把最高位标志位置起来
- uint canId = 帧ID & 0x7FFFFFFF;
- if (是否是扩展帧) canId |= 0x80000000;
-
- lock (_channelLocks[通道号])
- {
- if (是否是CANFD)
- {
- // CANFD 有效 DLC 校验
- byte validFdDlc = 校验CANFD的Dlc(dlcLength);
-
- ZLGCAN.canfd_frame fdFrame = new ZLGCAN.canfd_frame
- {
- can_id = canId,
- len = validFdDlc,
- flags = (byte)((是否是扩展帧 ? 0x01 : 0x00) | (开启波特率加速BRS ? 0x02 : 0x00) | 0x20), // 0x20 本地回显
- data = new byte[64]
- };
- Array.Copy(原始数据, 0, fdFrame.data, 0, Math.Min(原始数据.Length, 64));
-
- ZLGCAN.ZCAN_TransmitFD_Data txFdData = new ZLGCAN.ZCAN_TransmitFD_Data { frame = fdFrame, transmit_type = 2 };
- IntPtr pTxFd = Marshal.AllocHGlobal(Marshal.SizeOf(txFdData));
- try
- {
- Marshal.StructureToPtr(txFdData, pTxFd, true);
- return ZLGCAN.ZCAN_TransmitFD(_channelHandles[通道号], pTxFd, 1) == 1;
- }
- finally { Marshal.FreeHGlobal(pTxFd); }
- }
- else
- {
- ZLGCAN.can_frame standardFrame = new ZLGCAN.can_frame
- {
- can_id = canId,
- can_dlc = dlcLength > 8 ? (byte)8 : dlcLength,
- __pad = 0x20, // 发送回显
- data = new byte[8]
- };
- Array.Copy(原始数据, 0, standardFrame.data, 0, Math.Min(原始数据.Length, 8));
-
- ZLGCAN.ZCAN_Transmit_Data txData = new ZLGCAN.ZCAN_Transmit_Data { frame = standardFrame, transmit_type = 2 };
- IntPtr pTx = Marshal.AllocHGlobal(Marshal.SizeOf(txData));
- try
- {
- Marshal.StructureToPtr(txData, pTx, true);
- return ZLGCAN.ZCAN_Transmit(_channelHandles[通道号], pTx, 1) == 1;
- }
- finally { Marshal.FreeHGlobal(pTx); }
- }
- }
- }
-
- ///
- /// 直接发送 8 字节原始报文(经典 CAN 或 CANFD 均可)。
- /// 无需加载 DBC,适合手动构造简单报文。
- ///
- /// 通道号(0 ~ MaxChannels-1)
- /// 帧 ID(标准 11 位,扩展帧自动置位 0x80000000)
- /// 原始数据;超过 8 字节会自动截断,不足 8 字节自动补零
- /// 是否为 29 位扩展帧
- /// true = CANFD 格式;false = 经典 CAN 格式
- /// CANFD 是否开启波特率加速(经典 CAN 忽略此参数)
- /// 是否发送成功
- public virtual bool 发送原始报文(
- uint 通道号,
- uint 帧ID,
- byte[] data,
- bool 是否是扩展帧 = false,
- bool 是否是CANFD = true,
- bool 开启波特率加速BRS = true)
- {
- if (通道号 >= _maxChannels || _channelHandles[通道号] == IntPtr.Zero) return false;
-
- byte[] buffer = new byte[8];
- if (data != null)
- {
- Array.Copy(data, 0, buffer, 0, Math.Min(data.Length, 8));
- }
-
- uint canId = 帧ID & 0x7FFFFFFF;
- if (是否是扩展帧) canId |= 0x80000000;
-
- lock (_channelLocks[通道号])
- {
- if (是否是CANFD)
- {
- ZLGCAN.canfd_frame fdFrame = new ZLGCAN.canfd_frame
- {
- can_id = canId,
- len = 8,
- flags = (byte)((是否是扩展帧 ? 0x01 : 0x00) | (开启波特率加速BRS ? 0x02 : 0x00) | 0x20),
- data = new byte[64]
- };
- Array.Copy(buffer, 0, fdFrame.data, 0, 8);
-
- ZLGCAN.ZCAN_TransmitFD_Data txFdData = new ZLGCAN.ZCAN_TransmitFD_Data { frame = fdFrame, transmit_type = 2 };
- IntPtr pTxFd = Marshal.AllocHGlobal(Marshal.SizeOf(txFdData));
- try
- {
- Marshal.StructureToPtr(txFdData, pTxFd, true);
- return ZLGCAN.ZCAN_TransmitFD(_channelHandles[通道号], pTxFd, 1) == 1;
- }
- finally { Marshal.FreeHGlobal(pTxFd); }
- }
- else
- {
- ZLGCAN.can_frame standardFrame = new ZLGCAN.can_frame
- {
- can_id = canId,
- can_dlc = 8,
- __pad = 0x20,
- data = new byte[8]
- };
- Array.Copy(buffer, 0, standardFrame.data, 0, 8);
-
- ZLGCAN.ZCAN_Transmit_Data txData = new ZLGCAN.ZCAN_Transmit_Data { frame = standardFrame, transmit_type = 2 };
- IntPtr pTx = Marshal.AllocHGlobal(Marshal.SizeOf(txData));
- try
- {
- Marshal.StructureToPtr(txData, pTx, true);
- return ZLGCAN.ZCAN_Transmit(_channelHandles[通道号], pTx, 1) == 1;
- }
- finally { Marshal.FreeHGlobal(pTx); }
- }
- }
- }
-
- ///
- /// 构建发送用信号字典:DBC 初始值 + 额外覆盖。
- /// 调用方需自行保证通道已初始化且 DBC 已加载。
- ///
- private Dictionary 构建报文发送字典(uint 通道号, uint 帧ID, Dictionary? 额外覆盖 = null)
- {
- uint chDbcHandle = _dbcHandles[通道号];
- IntPtr ptrDbcMsg = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCMessage)));
- try
- {
- lock (_channelLocks[通道号])
- {
- if (!ZDBC.ZDBC_GetMessageById(chDbcHandle, 帧ID, ptrDbcMsg))
- return new Dictionary(StringComparer.OrdinalIgnoreCase);
-
- var msg = (ZDBC.DBCMessage)Marshal.PtrToStructure(ptrDbcMsg, typeof(ZDBC.DBCMessage));
- var dict = new Dictionary(StringComparer.OrdinalIgnoreCase);
-
- // 1. DBC 初始值打底
- for (int i = 0; i < msg.nSignalCount; i++)
- {
- var signal = msg.vSignals[i];
- string signalName = Encoding.Default.GetString(signal.strName).TrimEnd('\0');
- if (!string.IsNullOrEmpty(signalName) && signal.initialValueValid != 0)
- {
- dict[signalName] = signal.initialValue;
- }
- }
-
- // 2. 叠加持久化覆盖表(之前 设置报文 累积的值)
- if (_signalOverrides.TryGetValue((通道号, 帧ID), out var persisted))
- {
- lock (persisted)
- {
- foreach (var kvp in persisted)
- dict[kvp.Key] = kvp.Value;
- }
- }
-
- // 3. 叠加本次调用传入的额外覆盖(优先级最高)
- if (额外覆盖 != null)
- {
- foreach (var kvp in 额外覆盖)
- {
- dict[kvp.Key] = kvp.Value;
- }
- }
-
- return dict;
- }
- }
- finally
- {
-
- Marshal.FreeHGlobal(ptrDbcMsg);
- }
- }
-
- ///
- /// CANFD 有效 DLC 校验,非法值自动就近取到下一个合法 DLC。
- ///
- private static byte 校验CANFD的Dlc(byte dlc)
- {
- if (dlc <= 8) return dlc;
- if (dlc <= 12) return 12;
- if (dlc <= 16) return 16;
- if (dlc <= 20) return 20;
- if (dlc <= 24) return 24;
- if (dlc <= 32) return 32;
- if (dlc <= 48) return 48;
- return 64;
- }
-
- #endregion
-
- #region 5. 辅助工具子系统
-
- ///
- /// 计算物理值也需要传入对应通道,使用通道专属的DBC句柄进行计算
- ///
- ///
- /// 智能解析帧 ID 字符串,兼容 10 进制、16 进制(如 "0x1A", "1A", "26")
- ///
- /// 输入的帧 ID 字符串
- /// 解析成功后的 uint 帧 ID
- /// 是否解析成功
- [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)]
- public ulong 物理值转原始寄存器值(uint 通道号, ZDBC.DBCSignal 信号定义, double 实际物理值)
- {
- if (通道号 >= _maxChannels) return 0;
-
- IntPtr pSignal = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ZDBC.DBCSignal)));
- IntPtr pValue = Marshal.AllocHGlobal(sizeof(double));
-
- try
- {
- Marshal.StructureToPtr(信号定义, pSignal, true);
- Marshal.StructureToPtr(实际物理值, pValue, true);
- lock (_channelLocks[通道号])
- {
- return ZDBC.ZDBC_CalcRawValue(pSignal, pValue);
- }
- }
- finally
- {
- Marshal.FreeHGlobal(pSignal);
- Marshal.FreeHGlobal(pValue);
- }
- }
-
- #endregion
-
- [Browsable(false)]
- public void Dispose()
- {
- 关闭CAN卡设备();
- }
- }
-}
\ No newline at end of file
diff --git a/ZLGUSBCANFD/ZLGAPI.cs b/ZLGUSBCANFD/ZLGAPI.cs
deleted file mode 100644
index 938a041..0000000
--- a/ZLGUSBCANFD/ZLGAPI.cs
+++ /dev/null
@@ -1,1150 +0,0 @@
-// update time 2025/7/16
-using System.Runtime.InteropServices;
-
-namespace ZLGUSBCANFD
-{
-
- public class ZLGCAN
- {
-
- #region 设备类型
- public static UInt32 ZCAN_PCI9810 = 2;
- public static UInt32 ZCAN_USBCAN1 = 3;
- public static UInt32 ZCAN_USBCAN2 = 4;
- public static UInt32 ZCAN_PCI9820 = 5;
- public static UInt32 ZCAN_CANETUDP = 12;
- public static UInt32 ZCAN_PCI9840 = 14;
- public static UInt32 ZCAN_PCI9820I = 16;
- public static UInt32 ZCAN_CANETTCP = 17;
- public static UInt32 ZCAN_PCI5010U = 19;
- public static UInt32 ZCAN_USBCAN_E_U = 20;
- public static UInt32 ZCAN_USBCAN_2E_U = 21;
- public static UInt32 ZCAN_PCI5020U = 22;
- public static UInt32 ZCAN_PCIE9221 = 24;
- public static UInt32 ZCAN_WIFICAN_TCP = 25;
- public static UInt32 ZCAN_WIFICAN_UDP = 26;
- public static UInt32 ZCAN_PCIe9120 = 27;
- public static UInt32 ZCAN_PCIe9110 = 28;
- public static UInt32 ZCAN_PCIe9140 = 29;
- public static UInt32 ZCAN_USBCAN_4E_U = 31;
- public static UInt32 ZCAN_CANDTU_200UR = 32;
- public static UInt32 ZCAN_USBCAN_8E_U = 34;
- public static UInt32 ZCAN_CANDTU_NET = 36;
- public static UInt32 ZCAN_CANDTU_100UR = 37;
- public static UInt32 ZCAN_PCIE_CANFD_200U = 39;
- public static UInt32 ZCAN_PCIE_CANFD_400U = 40;
- public static UInt32 ZCAN_USBCANFD_200U = 41;
- public static UInt32 ZCAN_USBCANFD_100U = 42;
- public static UInt32 ZCAN_USBCANFD_MINI = 43;
- public static UInt32 ZCAN_CANSCOPE = 45;
- public static UInt32 ZCAN_CLOUD = 46;
- public static UInt32 ZCAN_CANDTU_NET_400 = 47;
- public static UInt32 ZCAN_CANFDNET_TCP = 48;
- public static UInt32 ZCAN_CANFDNET_200U_TCP = 48;
- public static UInt32 ZCAN_CANFDNET_UDP = 49;
- public static UInt32 ZCAN_CANFDNET_200U_UDP = 49;
- public static UInt32 ZCAN_CANFDWIFI_TCP = 50;
- public static UInt32 ZCAN_CANFDWIFI_100U_TCP = 50;
- public static UInt32 ZCAN_CANFDWIFI_UDP = 51;
- public static UInt32 ZCAN_CANFDWIFI_100U_UDP = 51;
- public static UInt32 ZCAN_CANFDNET_400U_TCP = 52;
- public static UInt32 ZCAN_CANFDNET_400U_UDP = 53;
- public static UInt32 ZCAN_CANFDNET_100U_TCP = 55;
- public static UInt32 ZCAN_CANFDNET_100U_UDP = 56;
- public static UInt32 ZCAN_CANFDNET_800U_TCP = 57;
- public static UInt32 ZCAN_CANFDNET_800U_UDP = 58;
- public static UInt32 ZCAN_USBCANFD_800U = 59;
- public static UInt32 ZCAN_PCIE_CANFD_100U_EX = 60;
- public static UInt32 ZCAN_PCIE_CANFD_400U_EX = 61;
- public static UInt32 ZCAN_PCIE_CANFD_200U_MINI = 62;
- public static UInt32 ZCAN_PCIE_CANFD_200U_EX = 63;
- public static UInt32 ZCAN_PCIE_CANFD_200U_M2 = 63;
- public static UInt32 ZCAN_CANFDDTU_400_TCP = 64;
- public static UInt32 ZCAN_CANFDDTU_400_UDP = 65;
- public static UInt32 ZCAN_CANFDWIFI_200U_TCP = 66;
- public static UInt32 ZCAN_CANFDWIFI_200U_UDP = 67;
- public static UInt32 ZCAN_CANFDDTU_800ER_TCP = 68;
- public static UInt32 ZCAN_CANFDDTU_800ER_UDP = 69;
- public static UInt32 ZCAN_CANFDDTU_800EWGR_TCP = 70;
- public static UInt32 ZCAN_CANFDDTU_800EWGR_UDP = 71;
- public static UInt32 ZCAN_CANFDDTU_600EWGR_TCP = 72;
- public static UInt32 ZCAN_CANFDDTU_600EWGR_UDP = 73;
- public static UInt32 ZCAN_CANFDDTU_CASCADE_TCP = 74;
- public static UInt32 ZCAN_CANFDDTU_CASCADE_UDP = 75;
- public static UInt32 ZCAN_USBCANFD_400U = 76;
- public static UInt32 ZCAN_CANFDDTU_200U = 77;
- public static UInt32 ZCAN_ZPSCANFD_TCP = 78;
- public static UInt32 ZCAN_ZPSCANFD_USB = 79;
- public static UInt32 ZCAN_CANFDBRIDGE_PLUS = 80;
- public static UInt32 ZCAN_CANFDDTU_300U = 81;
- public static UInt32 ZCAN_PCIE_CANFD_800U = 82;
- public static UInt32 ZCAN_PCIE_CANFD_1200U = 83;
- public static UInt32 ZCAN_MINI_PCIE_CANFD = 84;
- public static UInt32 ZCAN_USBCANFD_800H = 85;
- #endregion
-
- #region LIN事件
- public static UInt32 ZCAN_LIN_WAKE_UP = 1;
- public static UInt32 ZCAN_LIN_ENTERED_SLEEP_MODE = 2;
- public static UInt32 ZCAN_LIN_EXITED_SLEEP_MODE = 3;
- #endregion
-
- #region 函数
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern IntPtr ZCAN_OpenDevice(uint device_type, uint device_index, uint reserved);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_CloseDevice(IntPtr device_handle);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern IntPtr ZCAN_InitCAN(IntPtr device_handle, uint can_index, IntPtr pInitConfig);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_StartCAN(IntPtr chn_handle);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_ResetCAN(IntPtr chn_handle);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_ClearBuffer(IntPtr chn_handle);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_GetReceiveNum(IntPtr channel_handle, byte type);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_Transmit(IntPtr channel_handle, IntPtr pTransmit, uint len);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_TransmitFD(IntPtr channel_handle, IntPtr pTransmit, uint len);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_TransmitData(IntPtr device_handle, IntPtr pTransmit, uint len);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_Receive(IntPtr channel_handle, IntPtr pReceive, uint len, int wait_time = -1);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_ReceiveFD(IntPtr channel_handle, IntPtr pReceive, uint len, int wait_time = -1);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_ReceiveData(IntPtr device_handle, IntPtr pReceive, uint len, int wait_time);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_SetValue(IntPtr device_handle, string path, string value);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_SetValue(IntPtr device_handle, string path, IntPtr value);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern IntPtr ZCAN_GetValue(IntPtr device_handle, string path);
-
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern IntPtr ZCAN_InitLIN(IntPtr device_handle, uint lin_index, IntPtr pLINInitConfig);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_StartLIN(IntPtr channel_handle);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_ResetLIN(IntPtr channel_handle);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_TransmitLIN(IntPtr channel_handle, IntPtr pSend, uint Len);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_GetLINReceiveNum(IntPtr channel_handle);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_ReceiveLIN(IntPtr channel_handle, IntPtr pReceive, uint Len, int WaitTime);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_SetLINPublish(IntPtr channel_handle, IntPtr pSend, uint nPublishCount);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_SetLINSubscribe(IntPtr channel_handle, IntPtr pSend, uint nSubscribeCount);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_WakeUpLIN(IntPtr channel_handle);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_UDS_Request(IntPtr device_handle, IntPtr req, IntPtr resp, IntPtr dataBuf, uint dataBufSize);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_UDS_Control(IntPtr device_handle, IntPtr ctrl, IntPtr resp);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_UDS_RequestEX(IntPtr device_handle, IntPtr requestData, IntPtr resp, IntPtr dataBuf, uint dataBufSize);
-
-
- [DllImport(".\\zlgcan.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZCAN_UDS_ControlEX(IntPtr device_handle, uint dataType, IntPtr ctrl, IntPtr resp);
- #endregion
-
- #region 结构体
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_CHANNEL_INIT_CONFIG
- {
- public uint can_type;
- public _ZCAN_CHANNEL_INIT_CONFIG config;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct _ZCAN_CHANNEL_INIT_CONFIG
- {
- public _ZCAN_CHANNEL_CAN_INIT_CONFIG can;
- public _ZCAN_CHANNEL_CANFD_INIT_CONFIG canfd;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct _ZCAN_CHANNEL_CAN_INIT_CONFIG
- {
- public uint acc_code;
- public uint acc_mask;
- public uint reserved;
- public byte filter;
- public byte timing0;
- public byte timing1;
- public byte mode;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct _ZCAN_CHANNEL_CANFD_INIT_CONFIG
- {
- public uint acc_code;
- public uint acc_mask;
- public uint abit_timing;
- public uint dbit_timing;
- public uint brp;
- public byte filter;
- public byte mode;
- public ushort pad;
- public uint reserved;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_Transmit_Data
- {
- public can_frame frame;
- public uint transmit_type;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public class can_frame
- {
- public uint can_id;
- public byte can_dlc; // frame payload length in byte (0 .. CAN_MAX_DLEN)
- public byte __pad; // padding
- public byte __res0; // reserved / padding
- public byte __res1; // reserved / padding
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
- public byte[] data; // frame data
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public class canfd_frame
- {
- public uint can_id;
- public byte len;
- public byte flags;
- public byte __res0;
- public byte __res1; /* reserved / padding */
-
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
- public byte[] data;
- };
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public class ZCAN_Receive_Data
- {
- public can_frame frame;
- public UInt64 timestamp;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public class ZCAN_ReceiveFD_Data
- {
- public canfd_frame frame;
- public UInt64 timestamp;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_AUTO_TRANSMIT_OBJ //CANFD定时发送帧结构体
- {
- public ushort enable; //0-禁用,1-使能
- public ushort index; //定时报文索引
- public uint interval; //定时周期
- public ZCAN_Transmit_Data obj;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCANFD_AUTO_TRANSMIT_OBJ //CANFD定时发送帧结构体
- {
- public ushort enable; //0-禁用,1-使能
- public ushort index; //定时报文索引
- public uint interval; //定时周期
- public ZCAN_TransmitFD_Data obj;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_TransmitFD_Data
- {
- public canfd_frame frame; // 报文数据信息,详见 canfd_frame 结构说明。
- public uint transmit_type; // 发送方式,0=正常发送,1=单次发送,2=自发自收,3=单次自发自收。
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCANCANFDData
- {
- public UInt64 timeStamp;
- public UInt32 flag; // flag用于设置一些参数,内部结构可以通过以下函数实现设置和取值
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public byte[] extraData; //未使用
- public canfd_frame frame; //实际报文结构体
-
- // frameType 帧类型 0-CAN 1-CANFD
- public uint frameType {
- get { return (flag & 0x03); }
- set { flag = (uint)((flag & ~0x03) | (value & 0x03)); }
- }
-
- // txDelay队列发送延时,延时时间存放在 timeStamp 字段;0-不启用延时,1-启用延时,单位1ms,2-启用延时,单位100us
- public uint txDelay {
- get { return ((flag >> 2) & 0x03); }
- set { flag = (uint)((flag & ~0x0C) | (value & 0x03) << 2); }
- }
-
- public uint transmitType {
- get { return ((flag >> 4) & 0x0F); }
- set { flag = (uint)((flag & ~0x0F) | (value & 0x0F) << 4); }
- }
-
- public uint txEchoRequest {
- get { return ((flag >> 8) & 0x01); }
- set { flag = (uint)(flag | (value & 0x01) << 8); }
- }
-
- public uint txEchoed {
- get { return ((flag >> 9) & 0x01); } // bit9
- set { flag = (uint)((flag & ~0x200) | (value & 0x01) << 9); }
- }
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct PID
- {
- public byte rawVal;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct RxData
- {
- public UInt64 timeStamp;
- public byte datalen;
- public byte dir;
- public byte chkSum;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)]
- public byte[] reserved;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
- public byte[] data;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCANDataObj
- {
- public byte dataType; // 1-CAN/CANFD数据, 4-LIN数据
- public byte chnl; // 数据通道
- public UInt16 flag; // 未使用
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public byte[] extraData; // 未使用
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 92)]
- public byte[] data; // 报文结构体
- }
-
-
- // LIN
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCANLINData
- {
- public PID pid; // 受保护的ID
- public RxData rxData; // 数据
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
- public byte[] reserved;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCANLINErrData
- {
- public UInt64 timeStamp; // 时间戳,单位微秒(us)
- public PID pid; // 受保护的ID
-
- public byte dataLen; // 数据长度
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
- public byte[] data; // 数据
-
-
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
- public byte[] errData; // 错误信息
-
- public byte dir; // 传输方向
- public byte chkSum; // 数据校验,部分设备不支持校验数据的获取
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
- public byte[] reserved;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCANLINEventData
- {
- public UInt64 timeStamp; // 时间戳,单位微秒(us)
- public byte type; // 数据长度
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
- public byte[] reserved;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_LIN_MSG
- {
- public byte chnl; // 数据通道
- public byte dataType; // 0-LIN,1-ErrLIN
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 46)]
- public byte[] data;
- };
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_LIN_INIT_CONFIG
- {
- public byte linMode; // 0-slave,1-master
- public byte chkSumMode; // 1-经典校验,2-增强校验 3-自动(对应eZLINChkSumMode的模式)
- public byte maxLength; // 最大数据长度,8~64
- public byte reserved;
- public uint libBaud; // 波特率,取值1000~20000
-
- };
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_LIN_PUBLISH_CFG
- {
- public byte ID; // 受保护的ID(ID取值范围为0-63)
- public byte datelen; // 范围1~8
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] // 数据段内容
- public byte[] data;
- public byte chkSumMode; // 校验方式:0-默认,启动时配置 1-经典校验 2-增强校验(对应eZLINChkSumMode的模式)
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
- public byte[] reserved;
- };
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_LIN_SUBSCIBE_CFG
- {
- public byte ID; // 受保护的ID(ID取值范围为0-63)
- public byte datelen; // dataLen范围为1-8 当为255(0xff)则表示设备自动识别报文长度
- public byte chkSumMode; // 校验方式:0-默认,启动时配置 1-经典校验 2-增强校验(对应eZLINChkSumMode的模式)
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
- public byte[] reserved;
- };
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct SESSION_PARAM
- {
- public uint timeout; // 响应超时时间(ms)。因PC定时器误差,建议设置不小于200ms
- public uint enhanced_timeout; // 收到消极响应错误码为0x78后的超时时间(ms)。因PC定时器误差,建议设置不小于200ms
- public byte threeInOne; //三合一,把下面三个变量写进这一个变量
-
- // threeInOne 包含以下三个变量
- // BYTE check_any_negative_response : 1; // 接收到非本次请求服务的消极响应时是否需要判定为响应错误
- // BYTE wait_if_suppress_response : 1; // 抑制响应时是否需要等待消极响应,等待时长为响应超时时间
- // BYTE flag : 6; // 保留
- public byte check_any_negative_response
- {
- get { return (byte)(threeInOne & 0x0001); }
- set { threeInOne = (byte)((threeInOne & ~0x0001) | (value & 0x0001)); }
- }
- public byte wait_if_suppress_response
- {
- get { return (byte)((threeInOne & 0x0002) >> 1); }
- set { threeInOne = (byte)((threeInOne & ~0x0002) | (value & 0x0002)); }
- }
- public byte flag
- {
- get { return (byte)((threeInOne & 0x00FC) >> 2); }
- set { threeInOne = (byte)((threeInOne & ~0x00FC) | (value & 0x00FC)); }
- }
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
- public byte[] reserved0;
- };
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct TRANS_PARAM
- {
- public byte version; // 传输协议版本,VERSION_0,VERSION_1
- public byte max_data_len; // 单帧最大数据长度,can:8,canfd:64
- public byte local_st_min; // 本程序发送流控时用,连续帧之间的最小间隔,0x00-0x7F(0ms~127ms),0xF1-0xF9(100us~900us)
- public byte block_size; // 流控帧的块大小
- public byte fill_byte; // 无效字节的填充数据
- public byte ext_frame; // 0:标准帧 1:扩展帧
- public byte is_modify_ecu_st_min; // 是否忽略ECU 返回流控的STmin,强制使用本程序设置的remote_st_min 参数代替
- public byte remote_st_min; // 发送多帧时用, is_modify_ecu_st_min = 1 时有效,0x00 - 0x7F(0ms~127ms), 0xF1 - 0xF9(100us~900us)
- public uint fc_timeout; // 接收流控超时时间(ms),如发送首帧后需要等待回应流控帧
- public byte fill_mode; // 数据长度填充模式 0-就近填充 1-不填充 2-最大填充
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
- public byte[] reserved0;
- };
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct TRANS_PARAM_LIN
- {
- public byte fill_byte; // 无效字节的填充数据
- public byte st_min; // 从节点准备接收诊断请求的下一帧或传输诊断响应的下一帧所需的最小时间
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
- public byte[] reserved0;
- };
-
-
- // CAN UDS请求数据
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_UDS_REQUEST // 硬件UDS接口构体
- {
- public uint req_id; // 请求事务索引ID,范围0~65535
- public byte channel; // 设备通道索引
- public byte frame_type; // 帧类型
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
- public byte[] reserved0;
- public uint src_addr; // 请求地址
- public uint dst_addr; // 响应地址
- public byte suppress_response; // 1-抑制响应
- public byte sid; // 请求服务id
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
- public byte[] reserved1;
-
- public SESSION_PARAM session_param;
- public TRANS_PARAM trans_param;
- public IntPtr data; // 数据数组(不包含SID)
- public uint data_len; // 数据数组的长度
- public uint reserved2;
- }
-
-
- // LIN UDS请求数据
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZLIN_UDS_REQUEST // 硬件UDS接口构体
- {
- public uint req_id; // 请求事务索引ID,范围0~65535
- public byte channel; // 设备通道索引
- public byte suppress_response; // 1:抑制响应 0:不抑制
- public byte sid; // 请求服务id
- public byte Nad; // 节点地址
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
- public byte[] reserved1;
-
-
- public SESSION_PARAM session_param;
- public TRANS_PARAM_LIN trans_param;
- public IntPtr data; // 数据数组(不包含SID)
- public uint data_len; // 数据数组的长度
- public uint reserved2;
- }
-
-
- // UDS响应数据
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_UDS_RESPONSE
- {
- public byte status; // 响应状态
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
- public byte[] reserved;
- public byte type; // 响应类型
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] // 大小为8
- public byte[] raw;
- };
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct UDS_RESPONSE_Positive
- {
- public byte sid; // 响应服务id
- public uint data_len; // 数据长度(不包含SID), 数据存放在接口传入的dataBuf中
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct UDS_RESPONSE_Negative
- {
- public byte neg_code; // 固定为0x7F
- public byte sid; // 请求服务id
- public byte error_code; // 错误码
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct UDS_RESPONSE_raw
- {
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] // 大小为8
- public byte[] raw;
- }
-
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCANCANFDUdsData
- {
- public IntPtr req; // 请求信息
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
- public byte[] reserved; // 保留位
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCANLINUdsData
- {
- public IntPtr req; // 请求信息
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
- public byte[] reserved; // 保留位
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCANUdsRequestDataObj
- {
- public uint dataType; // 数据类型
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 63)]
- public byte[] data;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
- public byte[] reserved; // 保留位
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZCAN_DYNAMIC_CONFIG_DATA
- {
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
- public char[] key;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
- public char[] value;
- }
- #endregion
- }
-
-
- public class ZDBC
- {
- #region 常量定义
- public const int _MAX_FILE_PATH_ = 260; // 最长文件路径
- public const int _DBC_NAME_LENGTH_ = 127; // 名称最长长度
- public const int _DBC_COMMENT_MAX_LENGTH_ = 127; // 注释最长长度
- public const int _DBC_UNIT_MAX_LENGTH_ = 23; // 单位最长长度
- public const int _DBC_SIGNAL_MAX_COUNT_ = 256; // 一个消息含有的信号的最大数目
-
- public const int MUTIPLEXER_NONE = 0; // 不使用复用器
- public const int MUTIPLEXER_M_VALUE = 1; // 复用信号,当复用器开关的值为multiplexer_value时,该信号有效
- public const int MUTIPLEXER_M_SWITCH = 2; // 复用器开关,一个DBC消息只能有一个信号为开关
-
- public const int FT_CAN = 0; // CAN
- public const int FT_CANFD = 1; // CANFD
-
- public const int PROTOCOL_J1939 = 0;
- public const int PROTOCOL_OTHER = 1;
- public const uint INVALID_DBC_HANDLE = 0xffffffff; // 无效的DBC句柄
- #endregion
-
- #region 函数部分
-
- // ZDBC.dll
- public delegate bool OnSend(IntPtr ctx, IntPtr pObj);
- public delegate void OnMultiTransDone(IntPtr ctx, IntPtr pMsg, IntPtr data, UInt16 nLen, byte nDirection);
- public static OnSend onSend;
- public static OnMultiTransDone onMultiTransDone;
-
- ///
- /// 此函数用于初始化解析模块,只需要初始化一次。
- ///
- /// 是否关闭多帧发送,为 1 时不支持多帧的消息发送。
- /// 是否开启异步解析;0-不启动,ZDBC_AsyncAnalyse 接口无效;1-启动, 独立线程解析出消息。
- /// 为 INVALID_DBC_HANDLE 表示初始化失败,其他表示初始化成功,保存该返回值,之后的函数调用都要用到该句柄。
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZDBC_Init(byte disableMultiSend = 0, byte enableAsyncAnalyse = 1);
-
- ///
- /// 释放资源, 与DBC_Init配对使用
- ///
- /// hDBC-句柄, ZDBC_Init的返回值
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZDBC_Release(uint DBCHandle);
-
- ///
- /// 此函数用以加载 DBC 格式文件。
- ///
- /// 句柄;ZDBC_Init的返回值
- /// 结构体 FileInfo的指针
- /// 为 true 表示加载成功,false 表示失败。
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_LoadFile(uint DBCHandle, IntPtr pFileInfo);
-
- ///
- /// 从字符串加载DBC
- ///
- /// hDBC-句柄, DBC_Load的返回值
- /// pFileContent-文件内容字符串
- /// merge-是否合并到当前数据库; 1:不清除现有的数据, 即支持加载多个文件;0:清除原来的数据
- ///
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_LoadContent(uint DBCHandle, IntPtr pFileContent, uint merge);
-
- ///
- /// 获取文件的第一条消息。
- ///
- /// hDBC-句柄, DBC_Load的返回值
- /// pMsg 存储消息的信息
- /// true表示成功
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_GetFirstMessage(uint DBCHandle, IntPtr pMsg);
-
- ///
- /// 获取下一条消息。
- ///
- /// hDBC-句柄, DBC_Load的返回值
- /// pMsg 存储消息的信息
- /// true表示成功
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_GetNextMessage(uint DBCHandle, IntPtr pMsg);
-
- ///
- /// 此函数用以根据 ID 获取消息数据。
- ///
- /// 句柄;
- /// 帧 ID;
- /// 消息信息结构体
- ///
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_GetMessageById(uint DBCHandle, uint nID, IntPtr pMsg);
-
- ///
- /// 此函数用以获取 DBC 文件中含有的消息数目。
- ///
- /// DBC句柄
- /// DBC 文件中含有的消息数目
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern uint ZDBC_GetMessageCount(uint DBCHandle);
-
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_Analyse(uint DBCHandle, IntPtr pObj, IntPtr pMsg);
-
-
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_AsyncAnalyse(uint DBCHandle, IntPtr pObj, uint frame_type, UInt64 extraData);
-
-
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZDBC_OnReceive(uint DBCHandle, IntPtr pObj, uint frame_type);
-
-
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZDBC_SetSender(uint hDBC, OnSend sender, IntPtr ctx);
-
-
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZDBC_SetOnMultiTransDoneFunc(uint hDBC, OnMultiTransDone func, IntPtr ctx);
-
-
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern byte ZDBC_Send(uint hDBC, IntPtr pMsg);
-
- ///
- /// 根据原始数据解码为 DBCMessage。
- ///
- /// DBC句柄
- /// 输出参数,解析结果。
- /// 帧数据数组, ControlCAN 传入 VCI_CAN_OBJ, zlgcan 传入 can_frame。
- /// 原始帧数据个数, 即数组大小。
- /// frame_type 帧类型, 参考FT_CAN=0、FT_CANFD=1,ControlCAN不支持CANFD。
- /// 是否成功。
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_Decode(uint DBCHandle, IntPtr P2DBCMessage, IntPtr P2Obj, uint nCount, byte frame_type);
-
- ///
- /// 根据 DBCMessage 编码为原始数据。
- ///
- /// DBC句柄;
- /// 编码的原始数据缓冲区数组, ControlCAN 传入 VCI_CAN_OBJ, zlgcan 传入 can_frame。
- /// 输出参数,pObj 缓冲区大小, 返回时为实际原始数据个数。
- /// 输入参数,DBC 消息。
- /// frame_type 帧类型, FT_CAN=0、FT_CANFD=1,ControlCAN不支持CANFD。
- /// 是否成功。
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_Encode(uint DBCHandle, IntPtr P2Obj, IntPtr P2nCount, IntPtr pMsg, byte frame_type);
-
- ///
- /// 信号原始值转换为实际值
- ///
- /// sgl 信号
- /// rawVal 原始值, 如果该值超出信号长度可表示范围,会被截断。
- /// 实际值
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern double ZDBC_CalcActualValue(IntPtr sgl, IntPtr rawVal); //原始值通过计算转为实际值,实际值会传入rawVal的地址
-
- ///
- /// 信号实际值转换为原始值
- ///
- /// sgl 信号
- /// actualVal 实际值, 超出可表示范围时会被修正
- /// 原始值
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern UInt64 ZDBC_CalcRawValue(IntPtr sgl, IntPtr actualVal);
-
- ///
- /// 获取网络节点数量
- ///
- /// ZDBC_Init的返回值
- /// 网络节点总数量
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern UInt32 ZDBC_GetNetworkNodeCount(uint DBCHandle);
-
- ///
- ///
- ///
- /// ZDBC_Init的返回值
- /// index 位置索引
- /// DBCNetworkNode * node 网络节点信息
- ///
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern bool ZDBC_GetNetworkNodeAt(uint DBCHandle, UInt32 index, IntPtr node);
-
-
- ///
- /// 获取具体信号的值与含义对个数
- ///
- /// ZDBC_Init的返回值
- /// message的ID
- /// signal的名字
- ///
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern UInt32 ZDBC_GetValDescPairCount(uint DBCHandle, UInt32 mag_id, string signal_name);
-
-
- ///
- /// 获取具体信号的值与含义对
- ///
- /// ZDBC_Init的返回值
- /// message的ID
- /// signal的名字
- /// ValDescPair结构体类型
- [DllImport(".\\zdbc.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZDBC_GetValDescPair(uint DBCHandle, UInt32 mag_id, string signal_name, IntPtr pair);
-
-
- #endregion
-
- #region DBC 结构体部分
-
- public struct FileInfo
- {
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = _MAX_FILE_PATH_ + 1)]
- public byte[] strFilePath; // dbc文件路径
- public byte type; // dbc的协议类型, j1939选择PROTOCOL_J1939, 其他协议选择PROTOCOL_OTHER
- public byte merge; // 1:不清除现有的数据, 即支持加载多个文件 0:清除原来的数据
- };
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- public struct DBCSignal
- {
-
- public UInt32 nStartBit; // 起始位
- public UInt32 nLen; // 位长度
- public double nFactor; // 转换因子
- public double nOffset; // 转换偏移实际值=原始值*nFactor+nOffset
- public double nMin; // 最小值
- public double nMax; // 最大值
- public UInt64 nRawvalue; // 原始值
- public byte is_signed; // 1:有符号数据, 0:无符号
- public byte is_motorola; // 是否摩托罗拉格式
- public byte multiplexer_type; // 复用器类型
- public byte val_type; // 0:integer, 1:float, 2:double
- public UInt32 multiplexer_value; // 复用器开关值为此值时信号有效
-
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_UNIT_MAX_LENGTH_ + 1)]
- public byte[] unit; //单位
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_NAME_LENGTH_ + 1)]
- public byte[] strName; //名称
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_COMMENT_MAX_LENGTH_ + 1)]
- public byte[] strComment; //注释
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_NAME_LENGTH_ + 1)]
- public byte[] strValDesc; //值描述
-
- public double initialValue; // 初始化值(原始值)
- public uint initialValueValid; // 初始值是否有效
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- public struct DBCMessage
- {
- public UInt32 nSignalCount; // 信号数量
- public UInt32 nID; // ID
- public UInt32 nSize; // 消息占的字节数目
- public double nCycleTime; // 发送周期
- public byte nExtend; // 1:扩展帧, 0:标准帧
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_SIGNAL_MAX_COUNT_)]
- public DBCSignal[] vSignals; // 信号集合
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_NAME_LENGTH_ + 1)]
- public byte[] strName; // 名称
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_COMMENT_MAX_LENGTH_ + 1)]
- public byte[] strComment; // 注释
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- public struct ValDescPair
- {
- public double value; // 信号值
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = _DBC_NAME_LENGTH_ + 1)]
- public byte[] strName; // 对应的值描述
- }
- #endregion
- }
-
-
- public class ZUDS
- {
- #region 参数定义
-
- public static uint udsRTR = 0x40000000; // Remote Transmission Request
- public static uint udsEFF = 0x80000000; // Extend Frame Flag
- public static uint udsERR = 0x20000000; // Err flag
-
- #endregion
-
- #region 函数部分
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate uint OnUDSTransmitDelegate(IntPtr ctx, IntPtr frame, uint count);
-
-
- ///
- /// 该函数用于初始化 UDS 函数库,返回操作句柄,用于后续的操作,与 ZUDS_Release
- /// 配对使用。
- /// typedef uint32 TP_TYPE; // transport protocol
- /// #define DoCAN 0
- ///
- ///
- /// 操作句柄,= ZUDS_INVALID_HANDLE 为无效句柄,其他值为有效句柄。
- [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern UInt32 ZUDS_Init(uint type);
-
-
- ///
- /// 该函数用于释放资源,与 ZUDS_Init 配对使用。
- ///
- ///
- ///
- [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZUDS_Release(uint type);
-
-
- ///
- /// 该函数用于设置函数库的参数。
- ///
- ///
- /// 参数类型,= PARAM_TYPE_SESSION 0 用 于 设 置 会 话 层 参 数 , =
- ///PARAM_TYPE_ISO15765 1 用于设置 ISO15765 的通信参数;
- /// 参数值,type =PARAM_TYPE_SESSION 0 时为 ZUDS_SESSION_PARAM,
- ///type= PARAM_TYPE_ISO15765 1 时为 ZUDS_ISO15765_PARAM。
- [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZUDS_SetParam(UInt32 ZUDS_HANDLE, byte type, IntPtr param);
-
-
- ///
- /// 该函数用于设置发送回调函数。函数库自身并不发送帧数据,把打包的帧数据通过回调
- ///函数传出给用户发送,用户可通过 zlgcan 函数库进行帧数据发送。
- ///
- ///
- /// ctx 上下文参数, 在回调函数中传出, 库内部不会处理该参数;
- /// :回调函数原型;typedef uint32 (*OnUDSTransmit)(void* ctx, const ZUDS_FRAME* frame, uint32 count);
- [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZUDS_SetTransmitHandler(UInt32 ZUDS_HANDLE, IntPtr ctx, OnUDSTransmitDelegate onUDSTransmit);
-
-
- [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZUDS_OnReceive(UInt32 ZUDS_HANDLE, IntPtr ZUDS_FRAME);
-
-
- [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZUDS_Request(UInt32 ZUDS_HANDLE, IntPtr ZUDS_REQUEST, IntPtr ZUDS_RESPONSE);
-
-
- [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZUDS_Stop(UInt32 ZUDS_HANDLE);
-
-
- [DllImport(".\\zuds.dll", CallingConvention = CallingConvention.StdCall)]
- public static extern void ZUDS_SetTesterPresent(UInt32 ZUDS_HANDLE, byte enable, IntPtr param);
-
- #endregion
-
- #region 结构体部分
- ///
- /// 会话层面参数;即一应一答传输时的通讯参数。
- ///
- public struct ZUDS_SESSION_PARAM
- {
- public UInt16 timeout;// ms, timeout to wait the response of the server
- public UInt16 enhanced_timeout; // ms,timeout to wait after negative response: error code 0x78
- public UInt32 reserved0; // 保留
- public UInt32 reserved1; // 保留
- }
-
-
- ///
- /// 传输数据部分的参数,例如传输时侯每帧报文的字节数。
- ///
- public struct ZUDS_ISO15765_PARAM
- {
- public byte version; // VERSION_0, VERSION_1格式版本,为 VERSION_0 时符合 ISO15765-2 的 2004 版本格式要求;为
- //hVERSION_1 是符合 ISO15765-2 的 2016 版本新增的格式要求,如下图所示
- public byte max_data_len; // max data length, can:8, canfd:64
- public byte local_st_min; // ms, min time between two consecutive frames
- public byte block_size;
- public byte fill_byte; // fill to invalid byte
- public byte frame_type; // 0:std 1:ext
- public byte is_modify_ecu_st_min; //是否忽略 ECU 返回流控的 STmin,强制使用本程序设置的
- //remote_st_min 参数代替
-
- public byte remote_st_min; //发 送 多 帧 时 用, is_ignore_ecu_st_min = 1 时 有 效 ,
- //0x00-0x7F(0ms ~127ms), 0xF1-0xF9(100us ~900us)
- public UInt16 fc_timeout; //接收流控超时时间(ms), 如发送首帧后需要等待回应流控帧。
- public byte fill_mode;//字节填充模式。FILL_MODE_NONE-不填充0;FILL_MODE_SHORT- 小于 8 字节填充至 8 字节,大于 8 字节时按 DLC 就近填充1;FILL_MODE_MAX- 始终填充至最大数据长度 (不建议)2。
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
- public byte[] reserved;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZUDS_TESTER_PRESENT_PARAM
- {
- public UInt32 addr;//会话保持的请求地址;
- public UInt16 cycle;//发送周期,单位毫秒;
- public byte suppress_response; // 1:suppress是否抑制响应,建议设置为 1;
- public UInt32 reserved;//:保留,忽略即可。
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZUDS_REQUEST
- {
- public uint src_addr; // 请求地址
- public uint dst_addr; // 响应地址
- public byte suppress_response; // 1:抑制响应
- public byte sid; //service id of request
- public ushort reserve0;
- public IntPtr param; //array,params of the service
- public uint param_len; //参数数组的长度
- public uint reserved;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public class ZUDS_RESPONSE
- {
- public byte status;
- public byte type; // RT_POSITIVE, RT_NEGATIVE
- public _ZUDS_Union union;
- public uint reserved;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct ZUDS_positive
- {
- public byte sid; // service id of response
- public IntPtr param; // array, params of the service, don't free
- public uint param_len;
-
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct _ZUDS_negative
- {
- public byte neg_code; // 0x7F
- public byte sid; //service id of response
- public byte error_code;//消极响应的错误码
-
- }
-
-
- [StructLayout(LayoutKind.Explicit)]
- public struct _ZUDS_Union
- {
- [FieldOffset(0)]
- public ZUDS_positive zudsPositive;
-
- [FieldOffset(0)]
- public _ZUDS_negative zudsNegative;
- }
-
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public class ZUDS_FRAME
- {
- public uint id;
- public byte extend;
- public byte remote;
- public byte data_len;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
- public byte[] data;
- public uint reserved;
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public class ZUDS_CTX
- {
- public IntPtr can_type; // 0-CAN 1-CANFD 2-CANFD加速
- public IntPtr chn_handle; // 通道句柄
- }
- #endregion
- }
-}
diff --git a/ZLGUSBCANFD/ZLGDBCParser.cs b/ZLGUSBCANFD/ZLGDBCParser.cs
deleted file mode 100644
index f361398..0000000
--- a/ZLGUSBCANFD/ZLGDBCParser.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-
-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,
- }
-
- ///
- /// DBC 报文解析器(实例类,每个 ZLGCANFD 拥有独立的解析器实例)。
- /// 不同 CAN 卡的作用域各自维护自己的 MsgDatabase,互不干扰。
- ///
- public class ZLGDBCParser
- {
- ///
- /// 每个通道的报文数据库缓存,供 ViewModel 直接读取。
- /// 索引 = 通道号 (0 ~ maxChannels-1)。
- ///
- public List> MsgDatabase { get; private set; }
-
- ///
- /// 最大通道数(与所属 ZLGCANFD 一致)。
- ///
- public int MaxChannels { get; }
-
- public ZLGDBCParser(int maxChannels = 4)
- {
- MaxChannels = maxChannels;
- MsgDatabase = new List>(
- Enumerable.Range(0, maxChannels).Select(_ => new List<_Msg_>())
- );
- }
-
- ///
- /// 解析特定通道的 DBC 并自动存入对应的 MsgDatabase 缓存中。
- ///
- /// ZDBC 句柄
- /// 通道号索引 (0 ~ maxChannels-1)
- public void ParseAndLoadToDatabase(uint chDbcHandle, int channel)
- {
- if (channel < 0 || channel >= MsgDatabase.Count) return;
-
- // 清空当前通道旧缓存
- MsgDatabase[channel].Clear();
-
- // 解析并填充
- var parsedList = ParseZlgDbc(chDbcHandle);
- MsgDatabase[channel].AddRange(parsedList);
- }
-
- ///
- /// 全手工解析周立功 DBC 句柄下的所有消息和信号。
- ///
- /// 对应通道的 ZDBC 句柄
- /// 返回对齐同星业务层的自定义报文列表
- public static List<_Msg_> ParseZlgDbc(uint chDbcHandle)
- {
- List<_Msg_> msgList = new List<_Msg_>();
-
- if (chDbcHandle == 0 || chDbcHandle == ZDBC.INVALID_DBC_HANDLE)
- return msgList;
-
- int msgSize = Marshal.SizeOf(typeof(ZDBC.DBCMessage));
- IntPtr pMsg = Marshal.AllocHGlobal(msgSize);
-
- try
- {
- bool hasMessage = ZDBC.ZDBC_GetFirstMessage(chDbcHandle, pMsg);
-
- while (hasMessage)
- {
- var zlgMsg = (ZDBC.DBCMessage)Marshal.PtrToStructure(pMsg, typeof(ZDBC.DBCMessage));
-
- int nullIndex = Array.IndexOf(zlgMsg.strName, (byte)0);
-
- _Msg_ myMsg = new _Msg_
- {
- msg_id = (int)zlgMsg.nID,
- 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,
- msg_type = zlgMsg.nExtend == 1 ? (int)Msg_Type.CANFD : (int)Msg_Type.CAN,
- signal_Name = new string[zlgMsg.nSignalCount]
- };
-
- 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);
- hasMessage = ZDBC.ZDBC_GetNextMessage(chDbcHandle, pMsg);
- }
- }
- finally
- {
- Marshal.FreeHGlobal(pMsg);
- }
-
- msgList.Sort((a, b) => a.msg_id.CompareTo(b.msg_id));
- return msgList;
- }
- }
-}