CAN作用域优化
This commit is contained in:
@@ -15,6 +15,7 @@ using UIShare;
|
||||
using UIShare.GlobalVariable;
|
||||
using UIShare.PubEvent;
|
||||
using UIShare.UIViewModel;
|
||||
using ZLGUSBCANFD;
|
||||
|
||||
namespace ADP.ViewModels
|
||||
{
|
||||
@@ -212,7 +213,17 @@ namespace ADP.ViewModels
|
||||
#region 命令处理与事件
|
||||
private void SelectCANMessage()
|
||||
{
|
||||
_dialogService.ShowDialog("SelectCanMessageView");
|
||||
var canfd = CurrentConfig?.CANFD;
|
||||
if (canfd == null||_globalInfo.CurrentScope=="default")
|
||||
{
|
||||
LoggerHelper.Warn("当前作用域未配置 CAN 设备,无法打开报文选择窗口。");
|
||||
return;
|
||||
}
|
||||
|
||||
_dialogService.ShowDialog("SelectCanMessageView", new DialogParameters
|
||||
{
|
||||
{ "CANFD", canfd }
|
||||
}, _ => { });
|
||||
}
|
||||
|
||||
private void ShowDialogManagerView()
|
||||
|
||||
@@ -10,6 +10,10 @@ namespace CANModule.ViewModels
|
||||
{
|
||||
public class SelectCanMessageViewModel : DialogViewModelBase
|
||||
{
|
||||
#region 字段
|
||||
private ZLGCANFD? _canfd;
|
||||
#endregion
|
||||
|
||||
#region 属性
|
||||
public DialogCloseListener RequestClose { get; set; }
|
||||
|
||||
@@ -49,20 +53,22 @@ namespace CANModule.ViewModels
|
||||
{
|
||||
if (SetProperty(ref _selectedMessage, value))
|
||||
{
|
||||
// 健壮性检查:防范切换通道时清空选择引发的连锁 Bug
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
if (!string.IsNullOrEmpty(value) && _canfd != null)
|
||||
{
|
||||
// 使用 FirstOrDefault 代替 First,防止找不到匹配项时导致上位机崩溃
|
||||
var targetMsg = ZLGDBCParser.MsgDatabase[MessageChannel]
|
||||
.FirstOrDefault(x => $"[0x{x.msg_id:X}]{x.msg_name}" == 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<string>(targetMsg.signal_Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
SignalList = new ObservableCollection<string>();
|
||||
if (targetMsg != null && targetMsg.signal_Name != null)
|
||||
{
|
||||
SignalList = new ObservableCollection<string>(targetMsg.signal_Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
SignalList = new ObservableCollection<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -80,7 +86,7 @@ namespace CANModule.ViewModels
|
||||
set => SetProperty(ref _selectedSignal, value);
|
||||
}
|
||||
|
||||
private int _MessageChannel=-1;
|
||||
private int _MessageChannel = -1;
|
||||
public int MessageChannel
|
||||
{
|
||||
get => _MessageChannel;
|
||||
@@ -90,17 +96,25 @@ namespace CANModule.ViewModels
|
||||
{
|
||||
_MessageChannel = value;
|
||||
|
||||
// 1. 先安全清空旧的选择项和信号列表,断开引用链
|
||||
// 1. 先安全清空旧的选择项和信号列表
|
||||
SelectedMessage = null;
|
||||
SelectedSignal = null;
|
||||
SignalList = new ObservableCollection<string>();
|
||||
|
||||
// 2. 刷新当前通道的报文列表
|
||||
if (ZLGDBCParser.MsgDatabase != null && ZLGDBCParser.MsgDatabase.Count > value)
|
||||
if (_canfd != null)
|
||||
{
|
||||
MessageList = new ObservableCollection<string>(
|
||||
ZLGDBCParser.MsgDatabase[value].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}")
|
||||
);
|
||||
var db = _canfd.DBCParser.MsgDatabase;
|
||||
if (db != null && value >= 0 && value < db.Count)
|
||||
{
|
||||
MessageList = new ObservableCollection<string>(
|
||||
db[value].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}")
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageList = new ObservableCollection<string>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -128,6 +142,13 @@ namespace CANModule.ViewModels
|
||||
LoadCommand = new DelegateCommand(Load);
|
||||
}
|
||||
|
||||
#region Dialog 生命周期
|
||||
public override void OnDialogOpened(IDialogParameters parameters)
|
||||
{
|
||||
_canfd = parameters.GetValue<ZLGCANFD>("CANFD");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 命令处理
|
||||
private void Close()
|
||||
{
|
||||
@@ -136,7 +157,8 @@ namespace CANModule.ViewModels
|
||||
|
||||
private void Load()
|
||||
{
|
||||
ChannelList = new ObservableCollection<int>(Enumerable.Range(0, 4));
|
||||
int maxCh = _canfd?.DBCParser.MaxChannels ?? 4;
|
||||
ChannelList = new ObservableCollection<int>(Enumerable.Range(0, maxCh));
|
||||
}
|
||||
|
||||
private void GetSelectedSignal()
|
||||
@@ -152,20 +174,14 @@ namespace CANModule.ViewModels
|
||||
|
||||
private void GetSelectedMessage()
|
||||
{
|
||||
// 修复原本误写为 SelectedSignal != null 的 Bug,并增加了边界防错
|
||||
if (!string.IsNullOrEmpty(SelectedMessage) && SelectedMessage.Contains(']'))
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Clipboard.SetDataObject(SelectedMessage);
|
||||
//var parts = SelectedMessage.Split(']');
|
||||
//if (parts.Length > 1)
|
||||
//{
|
||||
// Clipboard.SetDataObject(parts[1]); // 复制纯报文名称(如:"EngineStatus")
|
||||
//}
|
||||
});
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,11 @@ namespace ZLGUSBCANFD
|
||||
private readonly uint _deviceIndex; // 设备索引
|
||||
private readonly int _maxChannels; // 动态通道数
|
||||
|
||||
/// <summary>
|
||||
/// 当前 CAN 卡专属的 DBC 解析器,按通道隔离报文数据库。
|
||||
/// </summary>
|
||||
public ZLGDBCParser DBCParser { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件:当接收到 CAN/CANFD 报文并且通过 DBC 成功解析后触发
|
||||
/// 参数:uint 通道号 (0,1,2,3), ZDBC.DBCMessage 解析后的DBC消息结构体
|
||||
@@ -51,6 +56,7 @@ namespace ZLGUSBCANFD
|
||||
_dbcHandles = new uint[_maxChannels];
|
||||
_isDbcLoadedArray = new bool[_maxChannels];
|
||||
_channelLocks = new object[_maxChannels];
|
||||
DBCParser = new ZLGDBCParser(_maxChannels);
|
||||
|
||||
for (int i = 0; i < _maxChannels; i++)
|
||||
{
|
||||
@@ -185,7 +191,7 @@ namespace ZLGUSBCANFD
|
||||
{
|
||||
_dbcHandles[通道号] = chDbcHandle;
|
||||
_isDbcLoadedArray[通道号] = true;
|
||||
ZLGDBCParser.ParseAndLoadToDatabase(chDbcHandle, 0);
|
||||
DBCParser.ParseAndLoadToDatabase(chDbcHandle, (int)通道号);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ZLGUSBCANFD
|
||||
{
|
||||
@@ -24,18 +23,37 @@ namespace ZLGUSBCANFD
|
||||
CANFD = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DBC 报文解析器(实例类,每个 ZLGCANFD 拥有独立的解析器实例)。
|
||||
/// 不同 CAN 卡的作用域各自维护自己的 MsgDatabase,互不干扰。
|
||||
/// </summary>
|
||||
public class ZLGDBCParser
|
||||
{
|
||||
// 补齐这个属性!4个通道的静态报文数据库缓存,供 ViewModel 直接读取
|
||||
public static List<List<_Msg_>> MsgDatabase { get; set; } =
|
||||
[.. Enumerable.Range(0, 4).Select(_ => new List<_Msg_>())];
|
||||
/// <summary>
|
||||
/// 每个通道的报文数据库缓存,供 ViewModel 直接读取。
|
||||
/// 索引 = 通道号 (0 ~ maxChannels-1)。
|
||||
/// </summary>
|
||||
public List<List<_Msg_>> MsgDatabase { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 外部调用:解析特定通道的 DBC 并自动存入对应的 MsgDatabase 缓存中
|
||||
/// 最大通道数(与所属 ZLGCANFD 一致)。
|
||||
/// </summary>
|
||||
/// <param name="chDbcHandle">ZDBC句柄</param>
|
||||
/// <param name="channel">通道号索引 (0-11)</param>
|
||||
public static void ParseAndLoadToDatabase(uint chDbcHandle, int channel)
|
||||
public int MaxChannels { get; }
|
||||
|
||||
public ZLGDBCParser(int maxChannels = 4)
|
||||
{
|
||||
MaxChannels = maxChannels;
|
||||
MsgDatabase = new List<List<_Msg_>>(
|
||||
Enumerable.Range(0, maxChannels).Select(_ => new List<_Msg_>())
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析特定通道的 DBC 并自动存入对应的 MsgDatabase 缓存中。
|
||||
/// </summary>
|
||||
/// <param name="chDbcHandle">ZDBC 句柄</param>
|
||||
/// <param name="channel">通道号索引 (0 ~ maxChannels-1)</param>
|
||||
public void ParseAndLoadToDatabase(uint chDbcHandle, int channel)
|
||||
{
|
||||
if (channel < 0 || channel >= MsgDatabase.Count) return;
|
||||
|
||||
@@ -48,7 +66,7 @@ namespace ZLGUSBCANFD
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全手工解析周立功 DBC 句柄下的所有消息和信号
|
||||
/// 全手工解析周立功 DBC 句柄下的所有消息和信号。
|
||||
/// </summary>
|
||||
/// <param name="chDbcHandle">对应通道的 ZDBC 句柄</param>
|
||||
/// <returns>返回对齐同星业务层的自定义报文列表</returns>
|
||||
@@ -56,43 +74,34 @@ namespace ZLGUSBCANFD
|
||||
{
|
||||
List<_Msg_> msgList = new List<_Msg_>();
|
||||
|
||||
// 显式指定周立功命名空间下的 INVALID_DBC_HANDLE 校验
|
||||
if (chDbcHandle == 0 || chDbcHandle == ZLGUSBCANFD.ZDBC.INVALID_DBC_HANDLE)
|
||||
if (chDbcHandle == 0 || chDbcHandle == ZDBC.INVALID_DBC_HANDLE)
|
||||
return msgList;
|
||||
|
||||
// 显式指定周立功命名空间下的结构体大小
|
||||
int msgSize = Marshal.SizeOf(typeof(ZLGUSBCANFD.ZDBC.DBCMessage));
|
||||
int msgSize = Marshal.SizeOf(typeof(ZDBC.DBCMessage));
|
||||
IntPtr pMsg = Marshal.AllocHGlobal(msgSize);
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 获取周立功 DBC 的第一条报文
|
||||
bool hasMessage = ZLGUSBCANFD.ZDBC.ZDBC_GetFirstMessage(chDbcHandle, pMsg);
|
||||
bool hasMessage = ZDBC.ZDBC_GetFirstMessage(chDbcHandle, pMsg);
|
||||
|
||||
while (hasMessage)
|
||||
{
|
||||
// 强制指定周立功底层 DBCMessage 结构映射
|
||||
var zlgMsg = (ZLGUSBCANFD.ZDBC.DBCMessage)Marshal.PtrToStructure(pMsg, typeof(ZLGUSBCANFD.ZDBC.DBCMessage));
|
||||
var zlgMsg = (ZDBC.DBCMessage)Marshal.PtrToStructure(pMsg, typeof(ZDBC.DBCMessage));
|
||||
|
||||
// 1. 优先在字节数组中找到第一个 \0 的位置
|
||||
int nullIndex = Array.IndexOf(zlgMsg.strName, (byte)0);
|
||||
|
||||
_Msg_ myMsg = new _Msg_
|
||||
{
|
||||
msg_id = (int)zlgMsg.nID,
|
||||
|
||||
// 2. 只翻译 \0 之前的有效字节,彻底解决乱码与规避不必要的内存开销
|
||||
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,
|
||||
// 如果底层识别出是扩展帧(nExtend==1),这里对齐映射为你的业务类型
|
||||
msg_type = zlgMsg.nExtend == 1 ? (int)Msg_Type.CANFD : (int)Msg_Type.CAN,
|
||||
signal_Name = new string[zlgMsg.nSignalCount]
|
||||
};
|
||||
// 2. 提取该报文下的所有信号名称
|
||||
|
||||
for (int i = 0; i < zlgMsg.nSignalCount; i++)
|
||||
{
|
||||
var signal = zlgMsg.vSignals[i];
|
||||
@@ -101,20 +110,16 @@ namespace ZLGUSBCANFD
|
||||
}
|
||||
|
||||
msgList.Add(myMsg);
|
||||
|
||||
// 3. 移向下一条报文
|
||||
hasMessage = ZLGUSBCANFD.ZDBC.ZDBC_GetNextMessage(chDbcHandle, pMsg);
|
||||
hasMessage = ZDBC.ZDBC_GetNextMessage(chDbcHandle, pMsg);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 彻底释放非托管内存,避免上位机高频切换加载 DBC 时导致内存泄漏
|
||||
Marshal.FreeHGlobal(pMsg);
|
||||
}
|
||||
|
||||
// 按 ID 排序,对齐你的树状展现或者二分查找业务逻辑
|
||||
msgList.Sort((a, b) => a.msg_id.CompareTo(b.msg_id));
|
||||
return msgList;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user