From 8923dd1ed857cf7bb0ef371b263e4937c4bc6416 Mon Sep 17 00:00:00 2001 From: hsc Date: Thu, 4 Dec 2025 17:11:48 +0800 Subject: [PATCH] =?UTF-8?q?CAN=E6=9B=B2=E7=BA=BF=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BOB.sln | 6 + BOB/App.xaml.cs | 1 + BOB/BOB.csproj | 1 + BOB/Converters/HexConverter.cs | 40 + BOB/Singleton/Devices.cs | 17 + BOB/ViewModels/Dialogs/CANViewModel.cs | 107 ++ BOB/ViewModels/Dialogs/EAEL9080ViewModel.cs | 1 + BOB/ViewModels/Dialogs/IOBoardViewModel.cs | 124 ++- BOB/ViewModels/MainViewModel.cs | 1 + BOB/ViewModels/ShellViewModel.cs | 81 +- BOB/Views/Dialogs/CANView.xaml | 225 ++++ BOB/Views/Dialogs/CANView.xaml.cs | 36 + BOB/Views/Dialogs/IOBoardView.xaml | 8 +- BOB/Views/ShellView.xaml | 22 +- CAN驱动/CAN驱动.csproj | 20 + CAN驱动/DBCParse.cs | 269 +++++ CAN驱动/Interop.TSMasterAPI.dll | Bin 0 -> 109568 bytes CAN驱动/TSMaster.dll | Bin 0 -> 1565184 bytes CAN驱动/同星驱动类.cs | 1048 +++++++++++++++++++ DeviceCommand/Device/IOBoard.cs | 22 +- 20 files changed, 1937 insertions(+), 92 deletions(-) create mode 100644 BOB/Converters/HexConverter.cs create mode 100644 BOB/ViewModels/Dialogs/CANViewModel.cs create mode 100644 BOB/Views/Dialogs/CANView.xaml create mode 100644 BOB/Views/Dialogs/CANView.xaml.cs create mode 100644 CAN驱动/CAN驱动.csproj create mode 100644 CAN驱动/DBCParse.cs create mode 100644 CAN驱动/Interop.TSMasterAPI.dll create mode 100644 CAN驱动/TSMaster.dll create mode 100644 CAN驱动/同星驱动类.cs diff --git a/BOB.sln b/BOB.sln index 78585c8..75c0f6c 100644 --- a/BOB.sln +++ b/BOB.sln @@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessManager", "ProcessMa EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{E2897246-96B3-48BE-AA08-4E774BE2BCFB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CAN驱动", "CAN驱动\CAN驱动.csproj", "{65DCA56F-A0EB-407F-80B9-C5C5F0E69681}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -63,6 +65,10 @@ Global {E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Debug|Any CPU.Build.0 = Debug|Any CPU {E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Release|Any CPU.ActiveCfg = Release|Any CPU {E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Release|Any CPU.Build.0 = Release|Any CPU + {65DCA56F-A0EB-407F-80B9-C5C5F0E69681}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {65DCA56F-A0EB-407F-80B9-C5C5F0E69681}.Debug|Any CPU.Build.0 = Debug|Any CPU + {65DCA56F-A0EB-407F-80B9-C5C5F0E69681}.Release|Any CPU.ActiveCfg = Release|Any CPU + {65DCA56F-A0EB-407F-80B9-C5C5F0E69681}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BOB/App.xaml.cs b/BOB/App.xaml.cs index 5563313..7e6fb6c 100644 --- a/BOB/App.xaml.cs +++ b/BOB/App.xaml.cs @@ -113,6 +113,7 @@ namespace BOB containerRegistry.RegisterDialog("SQ0030G1D"); containerRegistry.RegisterDialog("WS_68030_380T"); containerRegistry.RegisterDialog("ZXKS"); + containerRegistry.RegisterDialog("CAN"); //注册全局单例变量 containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); diff --git a/BOB/BOB.csproj b/BOB/BOB.csproj index 3f9f277..3561f0f 100644 --- a/BOB/BOB.csproj +++ b/BOB/BOB.csproj @@ -44,6 +44,7 @@ + diff --git a/BOB/Converters/HexConverter.cs b/BOB/Converters/HexConverter.cs new file mode 100644 index 0000000..57b435d --- /dev/null +++ b/BOB/Converters/HexConverter.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace BOB.Converters +{ + public class HexConverter : IValueConverter + { + // 显示时:int → hex 字符串 + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is int i) + return $"0x{i:X}"; // 例如 255 → 0xFF + return "0x0"; + } + + // 用户输入时:hex 字符串 → int + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + var str = value?.ToString()?.Trim(); + + if (string.IsNullOrWhiteSpace(str)) + return 0; + + if (str.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + str = str.Substring(2); + + if (int.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int result)) + return result; + + return 0; // 或 return DependencyProperty.UnsetValue; + } + } + + +} diff --git a/BOB/Singleton/Devices.cs b/BOB/Singleton/Devices.cs index 8f98a98..9eda09f 100644 --- a/BOB/Singleton/Devices.cs +++ b/BOB/Singleton/Devices.cs @@ -1,9 +1,11 @@ using BOB.Services; +using CAN驱动; using Castle.DynamicProxy; using DeviceCommand.Base; using DeviceCommand.Device; using Logger; using Model; +using Npgsql.TypeHandlers; using System; using System.Collections.Generic; using System.Reflection; @@ -171,6 +173,21 @@ namespace BOB.Singleton } } + public void InitCan() + { + 同星驱动类.DisConnect(); + var re1 = 同星驱动类.Init("ATS测试系统"); + var re2 = 同星驱动类.Connect(); + if (re1 == 0 && re2 == 0) + { + + } + else + { + + } + + } public async Task ConnectAllDevicesAsync() { if (DeviceDic.Count == 0) diff --git a/BOB/ViewModels/Dialogs/CANViewModel.cs b/BOB/ViewModels/Dialogs/CANViewModel.cs new file mode 100644 index 0000000..9961dcd --- /dev/null +++ b/BOB/ViewModels/Dialogs/CANViewModel.cs @@ -0,0 +1,107 @@ +using BOB.Singleton; +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace BOB.ViewModels.Dialogs +{ + public class CANViewModel : BindableBase, IDialogAware + { + + #region 属性 + private string _Title = "同星CAN"; + + public string Title + { + get { return _Title; } + set { SetProperty(ref _Title, value); } + } + private string _BLFPath; + + public string BLFPath + { + get { return _BLFPath; } + set { SetProperty(ref _BLFPath, value); } + } + + + #endregion + #region 命令 + public ICommand SelectBLFPathCommand { get; set; } + public ICommand SaveBLFPathCommand { get; set; } + public ICommand StartTranscirbeCommand { get; set; } + public ICommand EndTranscirbeCommand { get; set; } + + #endregion + private IEventAggregator _eventAggregator { get; set; } + private Devices _devices { get; set; } + private GlobalVariables _globalVariables { get; set; } + public CANViewModel(IContainerProvider containerProvider) + { + _devices = containerProvider.Resolve(); + _globalVariables = containerProvider.Resolve(); + _eventAggregator = containerProvider.Resolve(); + SelectBLFPathCommand = new DelegateCommand(SelectBLFPath); + SaveBLFPathCommand = new DelegateCommand(SaveBLFPath); + StartTranscirbeCommand = new DelegateCommand(StartTranscirbe); + EndTranscirbeCommand = new DelegateCommand(EndTranscirbe); + } + + #region 命令 + private void EndTranscirbe() + { + + } + + private void StartTranscirbe() + { + + } + + private void SaveBLFPath() + { + + } + + 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); + } + } + #endregion + + #region dialog规范 + public DialogCloseListener RequestClose { get; set; } + + public bool CanCloseDialog() + { + return true; + } + + public void OnDialogClosed() + { + + } + + public void OnDialogOpened(IDialogParameters parameters) + { + + } + #endregion + } +} diff --git a/BOB/ViewModels/Dialogs/EAEL9080ViewModel.cs b/BOB/ViewModels/Dialogs/EAEL9080ViewModel.cs index e89c303..4069006 100644 --- a/BOB/ViewModels/Dialogs/EAEL9080ViewModel.cs +++ b/BOB/ViewModels/Dialogs/EAEL9080ViewModel.cs @@ -19,6 +19,7 @@ namespace BOB.ViewModels.Dialogs { public class EAEL9080ViewModel : BindableBase, IDialogAware { + #region 属性 private string _Title = "低压直流负载"; private string _设备标识字符串; diff --git a/BOB/ViewModels/Dialogs/IOBoardViewModel.cs b/BOB/ViewModels/Dialogs/IOBoardViewModel.cs index 052a9de..82160da 100644 --- a/BOB/ViewModels/Dialogs/IOBoardViewModel.cs +++ b/BOB/ViewModels/Dialogs/IOBoardViewModel.cs @@ -1,9 +1,13 @@ using BOB.Singleton; +using DeviceCommand.Device; +using Logger; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using System.Windows.Input; @@ -12,8 +16,26 @@ namespace BOB.ViewModels.Dialogs { public class IOBoardViewModel : BindableBase, IDialogAware { + public enum Address : ushort + { + ushort0 = 0, + ushort1 = 1, + ushort2 = 2, + ushort3 = 3, + ushort4 = 4, + ushort5 = 5, + ushort6 = 6, + ushort7 = 7, + ushort8 = 8, + ushort9 = 9, + ushort10 = 10, + ushort11 = 11, + ushort12 = 12, + ushort13 = 13, + ushort14 = 14, + ushort15 = 15 + } #region 属性 - private string _title = "IO板卡"; public string Title @@ -22,16 +44,7 @@ namespace BOB.ViewModels.Dialogs set { SetProperty(ref _title, value); } } - private int _startAddress; - public int StartAddress - { - get { return _startAddress; } - set { SetProperty(ref _startAddress, value); } - } - - public ObservableCollection AddressNames { get; set; } - - private string _offset; + private string _offset="0"; public string Offset { get { return _offset; } @@ -44,6 +57,18 @@ namespace BOB.ViewModels.Dialogs get { return _batchWriteStatus; } set { SetProperty(ref _batchWriteStatus, value); } } + private Address _SelectedAddress; + public Address SelectedAddress + { + get { return _SelectedAddress; } + set { SetProperty(ref _SelectedAddress, value); } + } + private List
_AddressList=Enum.GetValues(typeof(Address)).Cast
().ToList(); + public List
AddressList + { + get { return _AddressList; } + set { SetProperty(ref _AddressList, value); } + } #endregion @@ -62,56 +87,72 @@ namespace BOB.ViewModels.Dialogs private IEventAggregator _eventAggregator { get; set; } private Devices _devices { get; set; } + private IOBoard device { get; set; } private GlobalVariables _globalVariables { get; set; } public IOBoardViewModel(IContainerProvider containerProvider) { _devices = containerProvider.Resolve(); _globalVariables = containerProvider.Resolve(); _eventAggregator = containerProvider.Resolve(); - ConnectCommand = new DelegateCommand(OnConnect); + ConnectCommand = new AsyncDelegateCommand(OnConnect); DisconnectCommand = new DelegateCommand(OnDisconnect); - PowerOnCommand = new DelegateCommand(OnPowerOn); - PowerOffCommand = new DelegateCommand(OnPowerOff); - SetCommand = new DelegateCommand(OnSet); - ReadCommand = new DelegateCommand(OnRead); + PowerOnCommand = new AsyncDelegateCommand(OnPowerOn); + PowerOffCommand = new AsyncDelegateCommand(OnPowerOff); + SetCommand = new AsyncDelegateCommand(OnSet); + ReadCommand = new AsyncDelegateCommand(OnRead); CloseCommand = new DelegateCommand(OnClose); } - private void OnConnect() + private async Task OnConnect() { - // 连接逻辑 - Console.WriteLine("连接设备..."); + await device.ConnectAsync(); } private void OnDisconnect() { - // 断开连接逻辑 - Console.WriteLine("断开设备..."); + device.Close(); } - private void OnPowerOn() + private async Task OnPowerOn() { - // 开启电源逻辑 - Console.WriteLine("电源开启..."); + await device.写输出开关(1, (ushort)SelectedAddress, true); } - private void OnPowerOff() + private async Task OnPowerOff() { - // 关闭电源逻辑 - Console.WriteLine("电源关闭..."); + await device.写输出开关(1, (ushort)SelectedAddress, false); } - private void OnSet() + private async Task OnSet() { - // 设置逻辑 - Console.WriteLine("设置..."); + bool[] statusArray = JsonConvert.DeserializeObject(BatchWriteStatus); + + if (ushort.TryParse(Offset, out ushort offset)) + { + if (statusArray==null||statusArray.Length+offset>16||statusArray.Length<=0||offset<0) + { + LoggerHelper.Error("BatchWriteStatus 数组内容不符合预期"); + return; + } + await device.批量写输出开关(1, offset, System.Text.Json.JsonSerializer.Deserialize(BatchWriteStatus)); + } + else + { + LoggerHelper.Error("BatchWriteStatus 数组内容不符合预期"); + } } - private void OnRead() + private async Task OnRead() { - // 读取逻辑 - Console.WriteLine("读取..."); + if (ushort.TryParse(Offset, out ushort offset)) + { + BatchWriteStatus = System.Text.Json.JsonSerializer.Serialize( await device.批量读输出开关(1, offset, 16)); + } + else + { + LoggerHelper.Error("Offset 解析失败,确保其是有效的数字!"); + } } private void OnClose() { @@ -132,6 +173,23 @@ namespace BOB.ViewModels.Dialogs public void OnDialogOpened(IDialogParameters parameters) { + try + { + var a = _devices.DeviceDic["IOBoard"] as IOBoard; + if (a != null) + { + device = a; + } + else + { + LoggerHelper.ErrorWithNotify("设备没有初始化无法打开测试界面"); + RequestClose.Invoke(); + } + } + catch (Exception) + { + LoggerHelper.ErrorWithNotify("找不到设备无法打开测试界面"); + } } #endregion diff --git a/BOB/ViewModels/MainViewModel.cs b/BOB/ViewModels/MainViewModel.cs index 8ea2e44..2bb6b2b 100644 --- a/BOB/ViewModels/MainViewModel.cs +++ b/BOB/ViewModels/MainViewModel.cs @@ -44,6 +44,7 @@ namespace BOB.ViewModels { _devices.Init(SystemConfig.Instance.DeviceList); await _devices.ConnectAllDevicesAsync(); + _devices.InitCan(); _devices.StartPollingCollectionAsync(); } catch (Exception ex) diff --git a/BOB/ViewModels/ShellViewModel.cs b/BOB/ViewModels/ShellViewModel.cs index 57e2217..54b1f48 100644 --- a/BOB/ViewModels/ShellViewModel.cs +++ b/BOB/ViewModels/ShellViewModel.cs @@ -1,6 +1,7 @@ using BOB.Models; using BOB.Singleton; using BOB.Views; +using CAN驱动; using Common.PubEvent; using Logger; using MaterialDesignThemes.Wpf; @@ -95,6 +96,8 @@ namespace BOB.ViewModels public ICommand SetDefaultCommand { get; set; } public ICommand LoadCommand { get; set; } public ICommand NavigateCommand { get; set; } + public ICommand SettingChannelCommand { get; set; } + public ICommand NavigateToCanPageCommand { get; set; } #endregion private IEventAggregator _eventAggregator; @@ -102,14 +105,16 @@ namespace BOB.ViewModels private IContainerProvider _containerProvider; private IRegionManager _regionManager; private StepRunning _stepRunning; + private IDialogService _dialogService; private Task? currentExecutionTask; - public ShellViewModel(IEventAggregator eventAggregator, IContainerProvider containerProvider,GlobalVariables globalVariables, StepRunning stepRunning,IRegionManager regionManager) + public ShellViewModel(IContainerProvider containerProvider) { - _eventAggregator = eventAggregator; + _eventAggregator = containerProvider.Resolve(); ; _containerProvider = containerProvider; - _globalVariables = globalVariables; - _regionManager = regionManager; - _stepRunning =stepRunning; + _globalVariables = containerProvider.Resolve(); ; + _regionManager = containerProvider.Resolve(); ; + _dialogService= containerProvider.Resolve(); + _stepRunning = containerProvider.Resolve(); ; LeftDrawerOpenCommand = new DelegateCommand(LeftDrawerOpen); MinimizeCommand = new DelegateCommand(MinimizeWindow); MaximizeCommand = new DelegateCommand(MaximizeWindow); @@ -125,9 +130,29 @@ namespace BOB.ViewModels SetDefaultCommand = new DelegateCommand(SetDefault); LoadCommand = new DelegateCommand(Load); NavigateCommand = new DelegateCommand(Navigate); + SettingChannelCommand = new DelegateCommand(SettingChannel); + NavigateToCanPageCommand = new DelegateCommand(NavigateToCanPage); _eventAggregator.GetEvent().Subscribe(UpdateRunIcon); } + + + #region ToolBar命令 + private bool isConnect = false; + + private void SettingChannel() + { + var re = 同星驱动类.ShowChannelMappingWindow(true); + if (re != 0) + { + var msg = 同星驱动类.GetErrorDescription(re); + LoggerHelper.ErrorWithNotify($"同星通道映射界面打开失败:{msg}"); + } + } + private void NavigateToCanPage() + { + _dialogService.Show("CAN"); + } private void Navigate(string content) { switch (content) @@ -152,30 +177,6 @@ namespace BOB.ViewModels break; } } - - private void UpdateRunIcon(string obj) - { - RunIcon= obj switch - { - "Play" => PackIconKind.Play, - "Pause" => PackIconKind.Pause, - _ => RunIcon - }; - } - private void Load() - { - SystemConfig.Instance.LoadFromFile(); - if (SystemConfig.Instance.DefaultSubProgramFilePath != null) - { - if (File.Exists(SystemConfig.Instance.DefaultSubProgramFilePath)) - { - Open(SystemConfig.Instance.DefaultSubProgramFilePath); - } - } - Title = SystemConfig.Instance.Title; - } - #region ToolBar命令 - private void SetDefault() { if(_globalVariables.CurrentFilePath!=null) @@ -405,5 +406,27 @@ namespace BOB.ViewModels window?.Close(); } #endregion + + private void UpdateRunIcon(string obj) + { + RunIcon = obj switch + { + "Play" => PackIconKind.Play, + "Pause" => PackIconKind.Pause, + _ => RunIcon + }; + } + private void Load() + { + SystemConfig.Instance.LoadFromFile(); + if (SystemConfig.Instance.DefaultSubProgramFilePath != null) + { + if (File.Exists(SystemConfig.Instance.DefaultSubProgramFilePath)) + { + Open(SystemConfig.Instance.DefaultSubProgramFilePath); + } + } + Title = SystemConfig.Instance.Title; + } } } diff --git a/BOB/Views/Dialogs/CANView.xaml b/BOB/Views/Dialogs/CANView.xaml new file mode 100644 index 0000000..0e00a5f --- /dev/null +++ b/BOB/Views/Dialogs/CANView.xaml @@ -0,0 +1,225 @@ + + +