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 } }