CAN功能移植兼容

This commit is contained in:
hsc
2026-07-06 13:29:34 +08:00
parent aec0044595
commit 3b41459dcd
16 changed files with 1658 additions and 58 deletions

View File

@@ -96,8 +96,10 @@ namespace UIShare.GlobalVariable
try
{
// 按指纹全局唯一创建 ZLGCANFD 实例maxChannels 默认 4对应 USBCANFD-400U
// 波特率与终端电阻从 CANConfigVM 传入,初始化并启动通道 时直接使用
var canLazy = _globalInfo.CanPool.GetOrAdd(fingerprint, key => new Lazy<ZLGCANFD>(() =>
new ZLGCANFD(config.CANConfig.DeviceType, config.CANConfig.DeviceIndex, 4)));
new ZLGCANFD(config.CANConfig.DeviceType, config.CANConfig.DeviceIndex, 4,
config.CANConfig.ABitBaud, config.CANConfig.DBitBaud, config.CANConfig.EnableTerminalResistance)));
_systemConfig.CANFD = canLazy.Value;
CANFD = canLazy.Value;
@@ -190,15 +192,22 @@ namespace UIShare.GlobalVariable
public async Task ConnectAllDevices(CancellationToken ct = default)
{
if (_systemConfig?.DeviceList == null || DeviceMap.Count == 0) return;
if (_systemConfig?.DeviceList == null) return;
var tasks = new List<Task>();
foreach (var info in _systemConfig.DeviceList)
{
if (info == null || !info.IsEnabled) continue;
if (string.IsNullOrWhiteSpace(info.DeviceName)) continue;
if (!DeviceMap.TryGetValue(info.DeviceName, out var device)) continue;
// CAN 设备:直接打开 CAN 卡
if (string.Equals(info.ConnectionType, "CAN", StringComparison.OrdinalIgnoreCase))
{
tasks.Add(ConnectCanAsync(info));
continue;
}
if (!DeviceMap.TryGetValue(info.DeviceName, out var device)) continue;
tasks.Add(ConnectInternalAsync(info, device, ct));
}
@@ -214,15 +223,28 @@ namespace UIShare.GlobalVariable
return;
}
var info = _systemConfig?.DeviceList?
.FirstOrDefault(d => d != null && string.Equals(d.DeviceName, deviceName, StringComparison.OrdinalIgnoreCase));
if (info == null)
{
LoggerHelper.Warn($"ConnectSpecifiedDevice未找到设备配置 [{deviceName}]。");
return;
}
// CAN 设备:直接打开 CAN 卡
if (string.Equals(info.ConnectionType, "CAN", StringComparison.OrdinalIgnoreCase))
{
await ConnectCanAsync(info);
return;
}
if (!DeviceMap.TryGetValue(deviceName, out var device))
{
LoggerHelper.Warn($"ConnectSpecifiedDevice未找到设备 [{deviceName}]。");
return;
}
var info = _systemConfig?.DeviceList?
.FirstOrDefault(d => d != null && string.Equals(d.DeviceName, deviceName, StringComparison.OrdinalIgnoreCase));
await ConnectInternalAsync(info, device, ct);
}
@@ -233,15 +255,21 @@ namespace UIShare.GlobalVariable
{
if (string.IsNullOrWhiteSpace(deviceName)) return;
var info = _systemConfig?.DeviceList?
.FirstOrDefault(d => d != null && string.Equals(d.DeviceName, deviceName, StringComparison.OrdinalIgnoreCase));
// CAN 设备:直接关闭 CAN 卡
if (info != null && string.Equals(info.ConnectionType, "CAN", StringComparison.OrdinalIgnoreCase))
{
await CloseCanAsync(info);
return;
}
IBaseInterface? device;
DeviceInfoVM? info;
lock (_lockObj)
{
if (!DeviceMap.TryGetValue(deviceName, out device)) return;
info = _systemConfig?.DeviceList?
.FirstOrDefault(d => d != null && string.Equals(d.DeviceName, deviceName, StringComparison.OrdinalIgnoreCase));
}
await CloseInternalAsync(info, device);
@@ -256,7 +284,7 @@ namespace UIShare.GlobalVariable
lock (_lockObj)
{
if (DeviceMap.Count == 0) return;
if (DeviceMap.Count == 0 && (CANFD == null)) return;
foreach (var kvp in DeviceMap)
{
@@ -269,6 +297,17 @@ namespace UIShare.GlobalVariable
}
}
// CAN 设备:直接关闭 CAN 卡
if (CANFD != null)
{
var canInfo = _systemConfig?.DeviceList?
.FirstOrDefault(d => d != null && string.Equals(d.ConnectionType, "CAN", StringComparison.OrdinalIgnoreCase));
if (canInfo != null)
{
tasks.Add(CloseCanAsync(canInfo));
}
}
await Task.WhenAll(tasks);
LoggerHelper.Info("所有设备已执行关闭操作。");
}
@@ -366,6 +405,88 @@ namespace UIShare.GlobalVariable
}
return await sp.ConnectAsync(ct);
}
/// <summary>
/// 打开 CAN 卡:打开设备 + 初始化并启动所有通道
/// </summary>
private async Task<bool> ConnectCanAsync(DeviceInfoVM info)
{
string name = info.DeviceName ?? "CAN";
try
{
if (CANFD == null)
{
LoggerHelper.Warn($"CAN 设备 [{name}] 尚未实例化,无法连接。");
info.IsConnected = false;
return false;
}
if (info.IsConnected)
{
LoggerHelper.Info($"CAN 设备 [{name}] 已连接,跳过。");
return true;
}
bool ok = await Task.Run(() =>
{
if (!CANFD.()) return false;
return true;
});
info.IsConnected = ok;
if (ok)
LoggerHelper.Info($"CAN 设备 [{name}] 连接成功,已初始化 {CANFD.DBCParser.MaxChannels} 个通道。");
else
LoggerHelper.Warn($"CAN 设备 [{name}] 连接失败。");
return ok;
}
catch (Exception ex)
{
info.IsConnected = false;
var inner = ex.InnerException?.Message ?? ex.Message;
LoggerHelper.ErrorWithNotify(_scopeName, $"CAN 设备 [{name}] 连接异常:{inner}");
return false;
}
}
/// <summary>
/// 关闭 CAN 卡
/// </summary>
private async Task CloseCanAsync(DeviceInfoVM info)
{
string name = info.DeviceName ?? "CAN";
try
{
if (CANFD == null)
{
info.IsConnected = false;
return;
}
if (!info.IsConnected)
{
LoggerHelper.Info($"CAN 设备 [{name}] 本就处于断开状态。");
return;
}
await Task.Run(() => CANFD.CAN卡设备());
LoggerHelper.Info($"CAN 设备 [{name}] 已成功关闭连接。");
}
catch (Exception ex)
{
var inner = ex.InnerException?.Message ?? ex.Message;
LoggerHelper.Error($"CAN 设备 [{name}] 关闭连接时出现异常: {inner}");
}
finally
{
info.IsConnected = false;
}
}
private static IReadOnlyDictionary<string, Type> BuildDeviceTypeMap()
{
try

View File

@@ -30,6 +30,8 @@ namespace UIShare.GlobalVariable
public string DefaultDBCFilePath { get; set; } = "";
public ObservableCollection<DeviceInfoVM> DeviceList = new();
public ObservableCollection<SharedParameter> SharedParameterList = new();
public ObservableCollection<CANSignalConfig> ConfigurationList = new();
public ObservableCollection<AutoDBCLoadItem> dbcAutoLoadList = new();
public ZLGCANFD CANFD = new();
[JsonIgnore]
public ObservableCollection<ParameterVM> ParameterList = new()

View File

@@ -0,0 +1,33 @@
namespace UIShare.UIViewModel
{
/// <summary>
/// CAN 通道枚举(对应 ZLGCANFD 通道选择)
/// </summary>
public enum APP_CHANNEL
{
CH0 = 0,
CH1 = 1,
CH2 = 2,
CH3 = 3
}
/// <summary>
/// DBC 自动加载配置项
/// </summary>
public class AutoDBCLoadItem : BindableBase
{
private int _dbcChannel;
public int DBCChannel
{
get => _dbcChannel;
set => SetProperty(ref _dbcChannel, value);
}
private string _dbcFilePath;
public string DBCFilePath
{
get => _dbcFilePath;
set => SetProperty(ref _dbcFilePath, value);
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
namespace UIShare.UIViewModel
{
public class CANSignalConfig
{
public int Channel { get; set; }
public int MessageID { get; set; }
public string MessageName { get; set; }
public string SignalName { get; set; }
public int CollectionInterval { get; set; }
public Guid CollectionID { get; set; }
}
}

View File

@@ -5,12 +5,9 @@
// 字段声明
private byte _通道;
private int _报文ID;
private ulong _时间戳;
private double _时间戳;
private byte _长度;
private bool _fd;
private bool _isTx;
private byte[] _bytes = new byte[64];
private string _报文;
// 通道属性
public byte
@@ -27,7 +24,7 @@
}
// 时间戳属性
public ulong
public double
{
get { return _时间戳; }
set { SetProperty(ref _时间戳, value); }
@@ -40,32 +37,6 @@
set { SetProperty(ref _长度, value); }
}
// FD属性
public bool FD
{
get { return _fd; }
set { SetProperty(ref _fd, value); }
}
// IsTx属性
public bool IsTx
{
get { return _isTx; }
set { SetProperty(ref _isTx, value); }
}
// Bytes属性
public byte[] Bytes
{
get { return _bytes; }
set { SetProperty(ref _bytes, value); }
}
// 报文属性
public string
{
get { return _报文; }
set { SetProperty(ref _报文, value); }
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Prism.Dialogs;
namespace UIShare.ViewModelBase
{
@@ -11,12 +12,41 @@ namespace UIShare.ViewModelBase
{
public DialogCloseListener RequestClose { get; set; }
public IEventAggregator _eventAggregator;
public IDialogService _dialogService;
private INotificationManager _notificationManager;
public DialogViewModelBase(IContainerProvider containerProvider)
{
_eventAggregator = containerProvider.Resolve<IEventAggregator>();
_dialogService = containerProvider.Resolve<IDialogService>();
_notificationManager = containerProvider.Resolve<INotificationManager>();
}
protected void ShowInfoMessageBox(string Message, Action callback)
{
var dialogParams = new DialogParameters();
dialogParams.Add("Title", "提示");
dialogParams.Add("Message", Message);
dialogParams.Add("Icon", "info");
dialogParams.Add("ShowOk", true);
_dialogService.ShowDialog("MessageBoxView", dialogParams, result =>
{
callback();
});
}
protected void ShowErrorMessageBox(string Message, Action callback)
{
var dialogParams = new DialogParameters();
dialogParams.Add("Title", "错误");
dialogParams.Add("Message", Message);
dialogParams.Add("Icon", "info");
dialogParams.Add("ShowOk", true);
_dialogService.ShowDialog("MessageBoxView", dialogParams, result =>
{
callback();
});
}
#region Dialog
public virtual bool CanCloseDialog() => true;