Files
ACP/CANModule/ViewModels/ZLGCANFDViewModel.cs
2026-07-29 13:12:27 +08:00

650 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<CanMessageShowVM> _CanMessageList = new();
public ObservableCollection<CanMessageShowVM> 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<string> _Message;
public ObservableCollection<string> Message
{
get => _Message;
set => SetProperty(ref _Message, value);
}
private ObservableCollection<string> _Signal;
public ObservableCollection<string> 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<string>(targetMsg.signal_Name);
}
else
{
Signal = new ObservableCollection<string>();
}
}
}
else
{
Signal = new ObservableCollection<string>();
}
_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<AutoDBCLoadItem> DBCAutoLoadList
{
get => _systemConfig?.DBCAutoLoadList ?? new ObservableCollection<AutoDBCLoadItem>();
}
private AutoDBCLoadItem _SelectedDcAutoLoad;
public AutoDBCLoadItem SelectedDcAutoLoad
{
get => _SelectedDcAutoLoad;
set => SetProperty(ref _SelectedDcAutoLoad, value);
}
// ===== 自定义报文发送属性 =====
private APP_CHANNEL[] _appChannelNames = Enum.GetValues<APP_CHANNEL>();
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<int> _ChannelList;
public ObservableCollection<int> 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<SystemConfig>();
_deviceManager = containerProvider.Resolve<DeviceManager>();
_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<int>(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<string>(
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<byte> 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
}
}