周立功换同星

This commit is contained in:
“hsc”
2026-07-29 14:20:32 +08:00
parent d8a22a15b1
commit 3bf33bb561
29 changed files with 1913 additions and 3255 deletions

679
TSMasterCAN/CAN.cs Normal file
View File

@@ -0,0 +1,679 @@
using Common.Attributes;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using TSMaster;
namespace TSMasterCAN
{
[ACPCommand]
public class CAN : IDisposable
{
#region
public static event Action? ConnectEvent;
public static event Action? DisConnectEvent;
public static bool ConnectFlag { get; set; } = false;
/// <summary>
/// 实时接收到的 CAN 报文缓存(按报文 ID 索引,保留最新帧)。
/// 供 CANViewModel.Refresh 等界面轮询读取。
/// </summary>
public static ConcurrentDictionary<int, TLIBCANFD> RealTimeMessages { get; } = new();
#endregion
#region
/// <summary>设备类型号43 = USBCANFD-400U 等TSMaster 中作为配置参考保留)</summary>
public uint DeviceType { get; }
/// <summary>设备索引</summary>
public uint DeviceIndex { get; }
/// <summary>最大通道数</summary>
public int MaxChannels { get; }
/// <summary>仲裁域波特率</summary>
public string ABitBaud { get; }
/// <summary>数据域波特率</summary>
public string DBitBaud { get; }
/// <summary>是否开启终端电阻</summary>
public bool EnableTerminalResistance { get; }
/// <summary>DBC 解析器(提供 MsgDatabase、MaxChannels 等访问)</summary>
public DBCParse DBCParser => DBCParse.Instance;
/// <summary>
/// DBC 报文解码事件:当接收到 CAN 帧并通过 DBC 解码后触发。
/// 参数:(通道号, 解码后的报文信息)
/// </summary>
public event Action<uint, DBCMessage>? OnDbcMessageDecoded;
private bool _disposed;
private bool _isOpened;
private TCANFDQueueEvent_Win32? _instanceListener;
#endregion
#region
/// <summary>默认构造函数(兼容 SystemConfig.CANFD = new() 等场景)</summary>
public CAN() : this(43, 0, 4, "500000", "2000000", true) { }
/// <summary>
/// 带配置参数的构造函数(兼容原 ZLG 设备管理流程)。
/// </summary>
/// <param name="deviceType">设备类型号</param>
/// <param name="deviceIndex">设备索引</param>
/// <param name="maxChannels">最大通道数</param>
/// <param name="aBitBaud">仲裁域波特率</param>
/// <param name="dBitBaud">数据域波特率</param>
/// <param name="enableTerminalResistance">是否开启终端电阻</param>
public CAN(uint deviceType, uint deviceIndex, int maxChannels, string aBitBaud, string dBitBaud, bool enableTerminalResistance)
{
DeviceType = deviceType;
DeviceIndex = deviceIndex;
MaxChannels = maxChannels;
ABitBaud = aBitBaud;
DBitBaud = dBitBaud;
EnableTerminalResistance = enableTerminalResistance;
}
#endregion
#region ZLG
/// <summary>
/// 打开设备:初始化 TSMaster 库 → 设置通道数 → 配置波特率 → 连接 → 启动 RBS → 注册监听。
/// </summary>
/// <returns>true 表示成功</returns>
public bool ()
{
if (_isOpened) return true;
if (ConnectFlag) { _isOpened = true; return true; }
try
{
// 1. 初始化 TSMaster 库
var re = Init("ACP");
if (re != 0)
{
Debug.WriteLine($"TSMaster 初始化失败,错误代码:{re}");
return false;
}
// 2. 设置通道数
TsMasterApi.tsapp_set_can_channel_count(MaxChannels);
// 3. 配置各通道波特率
float arbKbps = float.Parse(ABitBaud) / 1000f;
float dataKbps = float.Parse(DBitBaud) / 1000f;
for (int ch = 0; ch < MaxChannels; ch++)
{
TsMasterApi.tsapp_configure_baudrate_canfd(
ch, arbKbps, dataKbps,
TLIBCANFDControllerType.lfdtISOCAN,
TLIBCANFDControllerMode.lfdmNormal,
EnableTerminalResistance);
}
// 4. 连接硬件
re = Connect();
if (re != 0)
{
Debug.WriteLine($"CAN 连接失败,错误代码:{re}");
return false;
}
// 5. 注册接收监听(用于 DBC 信号解码广播)
_instanceListener = new TCANFDQueueEvent_Win32(OnCanFdReceived);
RegisterListener(_instanceListener);
_isOpened = true;
return true;
}
catch (Exception ex)
{
Debug.WriteLine($"打开设备异常:{ex.Message}");
return false;
}
}
/// <summary>
/// 关闭 CAN 卡设备:注销监听 → 断开连接。
/// </summary>
public void CAN卡设备()
{
if (!_isOpened && !ConnectFlag) return;
try
{
if (_instanceListener != null)
{
UnRegisterListener(_instanceListener);
_instanceListener = null;
}
DisConnect();
}
catch (Exception ex)
{
Debug.WriteLine($"关闭CAN卡设备异常{ex.Message}");
}
finally
{
_isOpened = false;
}
}
/// <summary>
/// 初始化并启动指定通道配置波特率TSMaster 在 Connect 时已自动启动所有通道)。
/// </summary>
/// <param name="channel">通道号</param>
public void (uint channel)
{
if (channel >= MaxChannels) return;
try
{
float arbKbps = float.Parse(ABitBaud) / 1000f;
float dataKbps = float.Parse(DBitBaud) / 1000f;
TsMasterApi.tsapp_configure_baudrate_canfd(
(int)channel, arbKbps, dataKbps,
TLIBCANFDControllerType.lfdtISOCAN,
TLIBCANFDControllerMode.lfdmNormal,
EnableTerminalResistance);
}
catch (Exception ex)
{
Debug.WriteLine($"初始化通道 {channel} 异常:{ex.Message}");
}
}
/// <summary>
/// 加载通道 DBC 文件。
/// </summary>
/// <param name="channel">通道号</param>
/// <param name="filePath">DBC 文件路径</param>
/// <returns>true 表示加载成功</returns>
public bool DBC文件(uint channel, string filePath)
{
try
{
var re = LoadDBC(filePath, [(int)channel], out _);
return re == 0;
}
catch (Exception ex)
{
Debug.WriteLine($"加载通道 {channel} DBC 文件异常:{ex.Message}");
return false;
}
}
/// <summary>
/// CAN FD 接收回调:接收原始帧 → 查找 DBC → 解码信号 → 触发 OnDbcMessageDecoded 事件。
/// </summary>
private void OnCanFdReceived(ref int AObj, ref TLIBCANFD AData)
{
if (_disposed) return;
// 始终缓存最新报文,供界面轮询刷新
int identifier = AData.FIdentifier;
var canfdCopy = AData;
RealTimeMessages[identifier] = canfdCopy;
if (OnDbcMessageDecoded == null) return;
try
{
uint channel = AData.FIdxChn;
if (channel >= DBCParse.MsgDatabase.Count) return;
// 在 DBC 数据库中查找匹配的报文
var msgList = DBCParse.MsgDatabase[(int)channel];
var match = msgList.FirstOrDefault(m => m.msg_id == identifier);
if (match == null || match.signal_Name == null || match.signal_Name.Length == 0) return;
// 解码各信号值
var signals = new DBCSignal[match.signal_Name.Length];
for (int i = 0; i < match.signal_Name.Length; i++)
{
double value = 0;
TsMasterApi.tsdb_get_signal_value_canfd(ref canfdCopy, match.msg_name, match.signal_Name[i], ref value);
signals[i] = new DBCSignal
{
strName = Encoding.Default.GetBytes(match.signal_Name[i]),
nRawvalue = value,
nFactor = 1,
nOffset = 0
};
}
var decoded = new DBCMessage
{
nID = (uint)identifier,
nSignalCount = signals.Length,
vSignals = signals
};
OnDbcMessageDecoded?.Invoke(channel, decoded);
}
catch (Exception ex)
{
Debug.WriteLine($"DBC 信号解码异常:{ex.Message}");
}
}
#endregion
#region IDisposable
public void Dispose()
{
if (_disposed) return;
_disposed = true;
CAN卡设备();
GC.SuppressFinalize(this);
}
#endregion
/// <summary>
/// 初始化TSMasterCAN
/// </summary>
/// <param name="ProjectName"></param>
/// <param name="filePath"></param>
/// <returns></returns>
[Browsable(false)]
public static int Init(string ProjectName, string? filePath = null)
{
if (string.IsNullOrEmpty(filePath))
{
return TsMasterApi.initialize_lib_tsmaster(ProjectName);
}
else
{
return TsMasterApi.initialize_lib_tsmaster_with_project(ProjectName, Path.GetFullPath(filePath));
}
}
/// <summary>
/// 释放TSMasterCAN
/// </summary>
[Browsable(false)]
public static void Release()
{
TsMasterApi.finalize_lib_tsmaster();
}
public static int obj = 0;
public static TCANFDQueueEvent_Win32 listener;
[Browsable(false)]
public static int RegisterListener(TCANFDQueueEvent_Win32 listenEvent)
{
listener = listenEvent;
var re = TsMasterApi.tsapp_register_event_canfd(ref obj, listener);
Debug.Assert(re == 0);
return re;
}
[Browsable(false)]
public static int UnRegisterListener(TCANFDQueueEvent_Win32 listenEvent = null)
{
if (listenEvent is not null)
{
listener = listenEvent;
}
var re = TsMasterApi.tsapp_unregister_event_canfd(ref obj, listener);
Debug.Assert(re == 0);
return re;
}
/// <summary>
/// 连接
/// </summary>
/// <returns></returns>
public static int Connect()
{
var re = TsMasterApi.tsapp_connect();
if (re == 0)
{
re = TsMasterApi.tscom_can_rbs_start();
if (re == 0)
{
ConnectFlag = true;
Task.Run(() => ConnectEvent?.Invoke());
}
else
{
Debug.WriteLine($"CAN_RBS启动失败,错误代码:{re}");
}
}
else
{
Debug.WriteLine($"CAN连接失败,错误代码:{re}");
return re;
}
return re;
}
/// <summary>
/// 断开
/// </summary>
/// <returns></returns>
public static int DisConnect()
{
var re = TsMasterApi.tsapp_disconnect();
//Debug.Assert(re == 0);
if (re == 0)
{
ConnectFlag = false;
Task.Run(() => DisConnectEvent?.Invoke());
}
else
{
Debug.WriteLine($"断开CAN连接失败,错误代码:{re}");
}
return re;
}
/// <summary>
/// 加载DBC
/// </summary>
/// <param name="filePath"></param>
/// <param name="channel"></param>
/// <param name="databaseID"></param>
/// <returns></returns>
[Browsable(false)]
public static int LoadDBC(string filePath, int[] channel, out uint databaseID)
{
databaseID = 0;
var re = TsMasterApi.tsdb_load_can_db(Path.GetFullPath(filePath), string.Join(",", channel), ref databaseID);
foreach (var item in channel)
{
DBCParse.parse(databaseID, item);
DBCParse.rbs_parse(databaseID, item);
}
return re;
}
/// <summary>
/// 卸载DBC
/// </summary>
/// <param name="databaseID"></param>
/// <returns></returns>
[Browsable(false)]
public static int UnLoadDBC(uint? databaseID = null)
{
if (databaseID == null)
{
return TsMasterApi.tsdb_unload_can_dbs();
}
else
{
return TsMasterApi.tsdb_unload_can_db(databaseID.Value);
}
}
/// <summary>
/// 开始记录日志
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public static int StartLogging(string filePath)
{
return TsMasterApi.tsapp_start_logging(Path.GetFullPath(filePath));
}
/// <summary>
/// 结束记录日志
/// </summary>
/// <returns></returns>
public static int StopLogging()
{
return TsMasterApi.tsapp_stop_logging();
}
/// <summary>
/// 弹出通道映射窗口
/// </summary>
/// <param name="isWait"></param>
/// <returns></returns>
[Browsable(false)]
public static int ShowChannelMappingWindow(bool isWait = false)
{
return TsMasterApi.tsapp_show_tsmaster_window("Hardware", isWait);
}
/// <summary>
/// 获取信号值
/// </summary>
/// <param name="channel"></param>
/// <param name="AMsgName"></param>
/// <param name="ASgnName"></param>
/// <returns></returns>
public static double GetSignalValue(byte channel, string AMsgName, string ASgnName)
{
double value = double.NaN;
var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
var re = TsMasterApi.tsdb_get_signal_value_canfd(ref find.ACANFD, AMsgName, ASgnName, ref value);
return value;
}
/// <summary>
/// 获取信号值
/// </summary>
/// <param name="channel"></param>
/// <param name="AMsgName"></param>
/// <param name="ASgnName"></param>
/// <param name="value"></param>
/// <returns></returns>
[Browsable(false)]
public static int GetSignalValue(byte channel, string AMsgName, string ASgnName, ref double value)
{
var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
return TsMasterApi.tsdb_get_signal_value_canfd(ref find.ACANFD, AMsgName, ASgnName, ref value);
}
/// <summary>
/// 获取信号值
/// </summary>
/// <param name="ACANFD"></param>
/// <param name="AMsgName"></param>
/// <param name="ASgnName"></param>
/// <param name="value"></param>
/// <returns></returns>
[Browsable(false)]
public static int GetSignalValue(ref TLIBCANFD ACANFD, string AMsgName, string ASgnName, ref double value)
{
return TsMasterApi.tsdb_get_signal_value_canfd(ref ACANFD, AMsgName, ASgnName, ref value);
}
/// <summary>
/// 设置信号值
/// </summary>
/// <param name="channel"></param>
/// <param name="AMsgName"></param>
/// <param name="ASgnName"></param>
/// <param name="AValue"></param>
/// <param name="isSend"></param>
/// <param name="sendPeriod"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static int SetSignalValue(byte channel, string AMsgName, string ASgnName, double AValue, bool isSend = false, float sendPeriod = 0)
{
var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
find.ACANFD.FIdxChn = channel;
var re = TsMasterApi.tsdb_set_signal_value_canfd(ref find.ACANFD, AMsgName, ASgnName, AValue);
Debug.Assert(re == 0);
if (re != 0) throw new Exception($"设置报文失败!返回代码{re}");
if (re != 0) return re;
if (isSend)
{
if (sendPeriod == 0)
{
return TsMasterApi.tsapp_transmit_canfd_async(ref find.ACANFD);
}
else
{
return TsMasterApi.tsapp_add_cyclic_msg_canfd(ref find.ACANFD, sendPeriod);
}
}
return 0;
}
/// <summary>
/// 设置信号值
/// </summary>
/// <param name="channel"></param>
/// <param name="AMsgName"></param>
/// <param name="sendPeriod"></param>
/// <returns></returns>
public static int SetSignalValue(APP_CHANNEL channel, string AMsgName, float sendPeriod = 0)
{
var find = DBCParse.MsgDatabase[(byte)channel].First(s => s.msg_name == AMsgName);
find.ACANFD.FIdxChn = (byte)channel;
if (sendPeriod == 0)
{
return TsMasterApi.tsapp_transmit_canfd_async(ref find.ACANFD);
}
else
{
return TsMasterApi.tsapp_add_cyclic_msg_canfd(ref find.ACANFD, sendPeriod);
}
}
/// <summary>
/// 发送自定义报文
/// </summary>
/// <returns></returns>
[Browsable(false)]
public static int SetMsg(TLIBCANFD msg)
{
return TsMasterApi.tsapp_transmit_canfd_async(ref msg);
}
/// <summary>
/// 设置报文
/// </summary>
/// <param name="channel">通道</param>
/// <param name="ID">DBC数据库ID</param>
/// <param name="bytes">报文数组</param>
public static void SetMsg(APP_CHANNEL channel, int ID, byte[] bytes)
{
var find = DBCParse.MsgDatabase[(byte)channel].FirstOrDefault(s => s.ACANFD.FIdentifier == ID);
if (find != null)
{
Array.Copy(bytes, 0, find.ACANFD.FData, 0, Math.Min(bytes.Length, find.ACANFD.FData.Length));
}
}
/// <summary>
/// 发送自定义报文
/// </summary>
/// <param name="AIdxChn"></param>
/// <param name="AID"></param>
/// <param name="AIsTx"></param>
/// <param name="AIsExt"></param>
/// <param name="AIsRemote"></param>
/// <param name="ADLC"></param>
/// <param name="ADataArray"></param>
/// <param name="AIsFD"></param>
/// <param name="AIsBRS"></param>
/// <param name="isUpdateDBCDatabase"></param>
/// <param name="sendPeriod"></param>
/// <returns></returns>
public static int SendMsg(APP_CHANNEL AIdxChn, int AID, bool AIsTx, bool AIsExt,
bool AIsRemote, byte ADLC, byte[] ADataArray, bool AIsFD = true, bool AIsBRS = false,
bool isUpdateDBCDatabase = false, float sendPeriod = 0)
{
var send = new TLIBCANFD
{
FIdxChn = (byte)AIdxChn,
FProperties = 0,
FIdentifier = AID,
FDLC = ADLC,
FTimeUS = 0uL,
FData = new byte[64],
FFDProperties = 0,
FIsTx = AIsTx,
FIsError = false,
FIsExt = AIsExt,
FIsRemote = AIsRemote,
FIsFD = AIsFD,
FIsBRS = AIsBRS
};
int length = Math.Min(ADataArray.Length, 64);
Array.Copy(ADataArray, 0, send.FData, 0, length);
int re;
if (sendPeriod == 0)
{
re = TsMasterApi.tsapp_transmit_canfd_async(ref send);
}
else
{
re = TsMasterApi.tsapp_add_cyclic_msg_canfd(ref send, sendPeriod);
}
if (isUpdateDBCDatabase)
{
var find = DBCParse.MsgDatabase[(byte)AIdxChn].FirstOrDefault(s => s.ACANFD.FIdentifier == send.FIdentifier);
if (find != null)
{
Array.Copy(send.FData, 0, find.ACANFD.FData, 0, Math.Min(ADataArray.Length, find.ACANFD.FData.Length));
}
}
return re;
}
/// <summary>
/// 添加循环发送报文
/// </summary>
/// <param name="channel"></param>
/// <param name="AMsgName"></param>
/// <param name="sendPeriod"></param>
/// <returns></returns>
public static int AddCyclicMsg(byte channel, string AMsgName, float sendPeriod)
{
var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
find.ACANFD.FIdxChn = channel;
return TsMasterApi.tsapp_add_cyclic_msg_canfd(ref find.ACANFD, sendPeriod);
}
/// <summary>
/// 清除循环发送的报文
/// </summary>
/// <returns></returns>
public static int DeleteCyclicMsgs()
{
return TsMasterApi.tsapp_delete_cyclic_msgs();
}
/// <summary>
/// 获取错误提示
/// </summary>
/// <param name="errorCode">错误代码</param>
/// <returns></returns>
public static string GetErrorDescription(int errorCode)
{
IntPtr ADesc = IntPtr.Zero;
TsMasterApi.tsapp_get_error_description(errorCode, ref ADesc);
if (ADesc == IntPtr.Zero) return $"未知错误代码: {errorCode}";
// 假设返回的是 ANSI 字符串(如 C 的 char*
string? description = Marshal.PtrToStringAnsi(ADesc);
return description ?? $"未知错误代码: {errorCode}";
}
}
}

305
TSMasterCAN/DBCParse.cs Normal file
View File

@@ -0,0 +1,305 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using TSMaster;
namespace TSMasterCAN
{
public struct can_network
{
[JsonInclude]
public string network_name;
[JsonInclude]
public can_node[] can_nodes;
}
public struct can_node
{
[JsonInclude]
public string node_name;
[JsonInclude]
public can_message[] tx_can_Messages;
[JsonInclude]
public can_message[] rx_can_Messages;
}
public struct can_message
{
[JsonInclude]
public string message_name;
[JsonInclude]
public string[] signals;
}
public class _Msg_
{
public int msg_type { get; set; }
public int msg_id { get; set; }
public int msg_cyclic { get; set; }
public byte msg_dlc { get; set; }
public string msg_name { get; set; }
public string[] signal_Name { get; set; }
public int msg_brs { get; set; }
public TLIBCANFD ACANFD;
}
public enum Msg_Type
{
CAN = 0,
CANFD = 1,
}
/// <summary>
/// DBC 文件信息类型枚举,用于指定 tsdb_get_can_db_info 查询的内容类型。
/// </summary>
public enum DBCINFO
{
/// <summary>网络名称</summary>
NETWORK_Name = 0,
/// <summary>CAN 报文总数</summary>
CAN_MSG_COUNT = 11,
/// <summary>CAN FD 报文总数</summary>
CANFD_MSG_COUNT = 12,
/// <summary>节点总数</summary>
NODE_COUNT = 14,
/// <summary>信号名称</summary>
SIGNAL_NAME = 33,
/// <summary>CAN 报文类型</summary>
CAN_MSG_TYPE = 40,
/// <summary>CAN 报文 DLC数据长度码</summary>
CAN_MSG_DLC = 41,
/// <summary>CAN 报文 ID</summary>
CAN_MSG_ID = 42,
/// <summary>CAN 报文周期</summary>
CAN_MSG_CYCLIC = 43,
/// <summary>CAN 报文名称</summary>
CAN_MSG_NAME = 44,
/// <summary>CAN 报文信号数量</summary>
CAN_MSG_SIGNAL_COUNT = 47,
/// <summary>CAN 报文信号名称索引</summary>
CAN_MSG_SIGNAL_NAME_INDEX = 48,
/// <summary>CAN FD 报文类型</summary>
CANFD_MSG_TYPE = 60,
/// <summary>CAN FD 报文 DLC数据长度码</summary>
CANFD_MSG_DLC = 61,
/// <summary>CAN FD 报文 ID</summary>
CANFD_MSG_ID = 62,
/// <summary>CAN FD 报文周期</summary>
CANFD_MSG_CYCLIC = 63,
/// <summary>CAN FD 报文名称</summary>
CANFD_MSG_NAME = 64,
/// <summary>CAN FD 报文信号数量</summary>
CANFD_MSG_SIGNAL_COUNT = 67,
/// <summary>CAN FD 报文信号名称索引</summary>
CANFD_MSG_SIGNAL_NAME_INDEX = 68,
/// <summary>节点名称</summary>
NODE_Name = 101,
/// <summary>节点发送 CAN 报文数量</summary>
NODE_TX_CAN_COUNT = 103,
/// <summary>节点发送 CAN 报文索引</summary>
NODE_TX_CAN_MESSAGE_INDEX = 104,
/// <summary>节点接收 CAN 报文数量</summary>
NODE_RX_CAN_COUNT = 105,
/// <summary>节点接收 CAN 报文索引</summary>
NODE_RX_CAN_MESSAGE_INDEX = 106,
/// <summary>节点发送 CAN FD 报文数量</summary>
NODE_TX_CANFD_COUNT = 107,
/// <summary>节点发送 CAN FD 报文索引</summary>
NODE_TX_CANFD_MESSAGE_INDEX = 108,
/// <summary>节点接收 CAN FD 报文数量</summary>
NODE_RX_CANFD_COUNT = 109,
/// <summary>节点接收 CAN FD 报文索引</summary>
NODE_RX_CANFD_MESSAGE_INDEX = 110,
}
/// <summary>
/// DBC 解码后的信号信息(替代原 ZLG ZDBC.DBCSignal
/// </summary>
public struct DBCSignal
{
/// <summary>信号名称(原始字节,兼容 Encoding.Default 解码)</summary>
public byte[] strName;
/// <summary>原始值TSMaster tsdb_get_signal_value_canfd 返回的物理值)</summary>
public double nRawvalue;
/// <summary>因子TSMaster 返回物理值,因子固定为 1</summary>
public double nFactor;
/// <summary>偏移TSMaster 返回物理值,偏移固定为 0</summary>
public double nOffset;
}
/// <summary>
/// DBC 解码后的报文信息(替代原 ZLG ZDBC.DBCMessage
/// 在 CAN 接收回调中对原始 TLIBCANFD 帧解码后构建此对象并触发 OnDbcMessageDecoded 事件。
/// </summary>
public class DBCMessage
{
/// <summary>报文 ID</summary>
public uint nID;
/// <summary>信号数量</summary>
public int nSignalCount;
/// <summary>信号数组</summary>
public DBCSignal[] vSignals;
}
public class DBCParse
{
private static DBCParse? _instance;
/// <summary>单例实例,供 CAN.DBCParser 属性使用MsgDatabase 等成员为 static实例仅用于属性访问兼容。</summary>
public static DBCParse Instance => _instance ??= new DBCParse();
/// <summary>最大通道数(等于 MsgDatabase 的维度)</summary>
public int MaxChannels => MsgDatabase.Count;
public static List<List<_Msg_>> MsgDatabase { get; set; } =
[.. Enumerable.Range(0, 12).Select(_ => new List<_Msg_>())];
public static can_network can_Network;
public static string tsdb_get_can_db_info(uint ADatabaseId, int AType, int AIndex, int ASubIndex)
{
nint tmpInt = new nint();
int ret = TsMasterApi.tsdb_get_can_db_info(ADatabaseId, AType, AIndex, ASubIndex, ref tmpInt);
if (ret == 0)
{
return Marshal.PtrToStringAnsi(tmpInt) ?? "";
}
else
return "";
}
public static void parse(uint Aid, int channel)
{
int CANcount = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_COUNT, 0, 0));
for (int i = 0; i < CANcount; i++)
{
_Msg_ temp = new _Msg_();
temp.msg_type = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_TYPE, i, 0));
temp.msg_dlc = byte.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_DLC, i, 0));
temp.msg_id = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_ID, i, 0));
temp.msg_name = tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_NAME, i, 0);
temp.msg_cyclic = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_CYCLIC, i, 0));
temp.signal_Name = new string[int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_SIGNAL_COUNT, i, 0))];
for (int signalcount = 0; signalcount < temp.signal_Name.Length; signalcount++)
{
temp.signal_Name[signalcount] = tsdb_get_can_db_info(Aid, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CAN_MSG_SIGNAL_NAME_INDEX, i, signalcount)), 0);
}
temp.msg_brs = 0;
temp.ACANFD = new TLIBCANFD(APP_CHANNEL.CHN1,
temp.msg_id,
true,
temp.msg_type == 1 || temp.msg_type == 4 ? true : false,
false, temp.msg_dlc,
temp.msg_type < 2 ? false : true,
false);
MsgDatabase[channel].Add(temp);
}
CANcount = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_COUNT, 0, 0));
for (int i = 0; i < CANcount; i++)
{
_Msg_ temp = new _Msg_();
temp.msg_type = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_TYPE, i, 0));
temp.msg_dlc = byte.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_DLC, i, 0));
temp.msg_id = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_ID, i, 0));
temp.msg_name = tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_NAME, i, 0);
temp.msg_cyclic = int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_CYCLIC, i, 0));
temp.signal_Name = new string[int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_SIGNAL_COUNT, i, 0))];
for (int signalcount = 0; signalcount < temp.signal_Name.Length; signalcount++)
{
temp.signal_Name[signalcount] = tsdb_get_can_db_info(Aid, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(Aid, (int)DBCINFO.CANFD_MSG_SIGNAL_NAME_INDEX, i, signalcount)), 0);
}
temp.msg_brs = int.Parse(tsdb_get_can_db_info(Aid, 69, i, 0));
temp.ACANFD = new TLIBCANFD(APP_CHANNEL.CHN1, temp.msg_id, true, temp.msg_type == 1 || temp.msg_type == 4 ? true : false, false, temp.msg_dlc, temp.msg_type < 2 ? false : true, temp.msg_brs == 1 ? true : false);
MsgDatabase[channel].Add(temp);
}
MsgDatabase[channel].Sort((a, b) => a.msg_id.CompareTo(b.msg_id));
}
public static void rbs_parse(uint AID, int channel)
{
can_Network = new can_network();
can_Network.network_name = tsdb_get_can_db_info(AID, (int)DBCINFO.NETWORK_Name, 0, 0);
int Node_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_COUNT, 0, 0));
can_Network.can_nodes = new can_node[Node_count];
for (int i = 0; i < Node_count; i++)
{
can_Network.can_nodes[i].node_name = tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_Name, i, 0);
int tx_can_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CAN_COUNT, i, 0));
int tx_canfd_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CANFD_COUNT, i, 0));
int rx_can_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CAN_COUNT, i, 0));
int rx_canfd_count = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CANFD_COUNT, i, 0));
//获取tx_can结构体
can_Network.can_nodes[i].tx_can_Messages = new can_message[tx_can_count + tx_canfd_count];
can_Network.can_nodes[i].rx_can_Messages = new can_message[rx_can_count + rx_canfd_count];
//获取报文名以及信号名
//1 get can_message idnex
//2 get can message name
//3 get signal count
//4 get signal name
int tx_index = -1;
for (int tx_can = 0; tx_can < tx_can_count; tx_can++)
{
int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CAN_MESSAGE_INDEX, i, tx_can));
can_Network.can_nodes[i].tx_can_Messages[tx_can].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_NAME, can_message_idnex, 0);
can_Network.can_nodes[i].tx_can_Messages[tx_can].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
for (int signalcount = 0; signalcount < can_Network.can_nodes[i].tx_can_Messages[tx_can].signals.Length; signalcount++)
{
can_Network.can_nodes[i].tx_can_Messages[tx_can].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
}
tx_index = tx_can;
}
for (int tx_can = 0; tx_can < tx_canfd_count; tx_can++, tx_index++)
{
int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_TX_CANFD_MESSAGE_INDEX, i, tx_can));
can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_NAME, can_message_idnex, 0);
can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
for (int signalcount = 0; signalcount < can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].signals.Length; signalcount++)
{
can_Network.can_nodes[i].tx_can_Messages[tx_index + 1].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
}
}
int rx_index = -1;
for (int tx_can = 0; tx_can < rx_can_count; tx_can++)
{
int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CAN_MESSAGE_INDEX, i, tx_can));
can_Network.can_nodes[i].rx_can_Messages[tx_can].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_NAME, can_message_idnex, 0);
can_Network.can_nodes[i].rx_can_Messages[tx_can].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
for (int signalcount = 0; signalcount < can_Network.can_nodes[i].rx_can_Messages[tx_can].signals.Length; signalcount++)
{
can_Network.can_nodes[i].rx_can_Messages[tx_can].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CAN_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
}
rx_index = tx_can;
}
for (int tx_can = 0; tx_can < rx_canfd_count; tx_can++, rx_index++)
{
int can_message_idnex = int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.NODE_RX_CANFD_MESSAGE_INDEX, i, tx_can));
can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].message_name = tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_NAME, can_message_idnex, 0);
can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].signals = new string[int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_COUNT, can_message_idnex, 0))];
for (int signalcount = 0; signalcount < can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].signals.Length; signalcount++)
{
can_Network.can_nodes[i].rx_can_Messages[rx_index + 1].signals[signalcount] = tsdb_get_can_db_info(AID, (int)DBCINFO.SIGNAL_NAME, int.Parse(tsdb_get_can_db_info(AID, (int)DBCINFO.CANFD_MSG_SIGNAL_NAME_INDEX, can_message_idnex, signalcount)), 0);
}
}
}
}
}
}

Binary file not shown.

BIN
TSMasterCAN/TSMaster.dll Normal file

Binary file not shown.

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>false</UseWPF>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Interop.TSMasterAPI">
<HintPath>..\CanDriver\bin\Debug\net8.0\Interop.TSMasterAPI.dll</HintPath>
</Reference>
</ItemGroup>
</Project>