BDU/TOSUNCAN/CAN.cs

1225 lines
45 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 Common.Attributes;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.Json;
using TSMaster;
using static Common.Attributes.ATSCommandAttribute;
namespace TSMasterCAN
{
/// <summary>
/// 同星CAN驱动类
/// </summary>
[ATSCommand]
[DeviceCategory("CAN卡驱动")]
public class CAN
{
public static event Action ConnectEvent;
public static event Action DisConnectEvent;
public static bool ConnectFlag { get; set; } = false;
/// <summary>
/// 用于接收CAN报文的队列
/// </summary>
private static readonly Queue<TLIBCANFD> _receivedMessages = new Queue<TLIBCANFD>();
private static readonly object _lock = new object(); // 线程安全锁
/// <summary>
/// 初始化CAN驱动
/// </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>
/// 释放CAN驱动
/// </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();
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);
}
#region
/// <summary>
/// 获取信号值 (基于DBC)
/// </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].FirstOrDefault(s => s.msg_name == AMsgName);
if (find != null)
{
var re = TsMasterApi.tsdb_get_signal_value_canfd(ref find.ACANFD, AMsgName, ASgnName, ref value);
if (re != 0)
{
Debug.WriteLine($"GetSignalValue: 获取信号值失败, 错误代码: {re}, 消息: {AMsgName}, 信号: {ASgnName}");
}
}
else
{
Debug.WriteLine($"GetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
}
return value;
}
/// <summary>
/// 获取信号值 (基于DBC) - 带返回值
/// </summary>
/// <param name="channel">通道</param>
/// <param name="AMsgName">消息名称</param>
/// <param name="ASgnName">信号名称</param>
/// <param name="value">输出信号值</param>
/// <returns>TSMaster API 返回值</returns>
[Browsable(false)]
public static int GetSignalValue(byte channel, string AMsgName, string ASgnName, ref double value)
{
var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName);
if (find != null)
{
return TsMasterApi.tsdb_get_signal_value_canfd(ref find.ACANFD, AMsgName, ASgnName, ref value);
}
else
{
Debug.WriteLine($"GetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
return -1; // 假设 -1 为未找到定义的错误码
}
}
/// <summary>
/// 获取信号值 (基于已有的CANFD报文对象) - 已优化,无需用户传入 TLIBCANFD
/// 此方法保留用于高级场景,但通常不推荐外部直接使用
/// </summary>
/// <param name="ACANFD">CANFD报文对象</param>
/// <param name="AMsgName">消息名称</param>
/// <param name="ASgnName">信号名称</param>
/// <param name="value">输出信号值</param>
/// <returns>TSMaster API 返回值</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);
}
#endregion
#region
/// <summary>
/// 设置信号值 (基于DBC)
/// </summary>
/// <param name="channel">通道</param>
/// <param name="AMsgName">消息名称</param>
/// <param name="ASgnName">信号名称</param>
/// <param name="AValue">信号值</param>
/// <param name="isSend">是否立即发送</param>
/// <param name="sendPeriod">发送周期 (ms)0表示单次发送</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].FirstOrDefault(s => s.msg_name == AMsgName);
if (find == null)
{
Debug.WriteLine($"SetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
return -1; // 或抛出异常
}
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>
/// 设置信号值 (基于DBC) - 仅发送报文
/// </summary>
/// <param name="channel">通道</param>
/// <param name="AMsgName">消息名称</param>
/// <param name="sendPeriod">发送周期 (ms)0表示单次发送</param>
/// <returns></returns>
public static int SetSignalValue(APP_CHANNEL channel, string AMsgName, float sendPeriod = 0)
{
var find = DBCParse.MsgDatabase[(byte)channel].FirstOrDefault(s => s.msg_name == AMsgName);
if (find == null)
{
Debug.WriteLine($"SetSignalValue: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
return -1; // 或抛出异常
}
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);
}
}
#endregion
#region
/// <summary>
/// 发送自定义报文 (基于 TLIBCANFD 对象) - 已优化,内部使用,外部不直接暴露
/// </summary>
/// <param name="msg">CANFD报文对象</param>
/// <returns></returns>
[Browsable(false)]
public static int SetMsg(TLIBCANFD msg)
{
return TsMasterApi.tsapp_transmit_canfd_async(ref msg);
}
/// <summary>
/// 设置报文数据 (在DBC缓存中)
/// </summary>
/// <param name="channel">通道</param>
/// <param name="ID">报文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));
}
else
{
Debug.WriteLine($"SetMsg: 未找到报文定义, ID: 0x{ID:X}, 通道: {channel}");
}
}
/// <summary>
/// 发送自定义报文
/// </summary>
/// <param name="AIdxChn">通道</param>
/// <param name="AID">报文ID</param>
/// <param name="AIsTx">是否为发送帧</param>
/// <param name="AIsExt">是否为扩展帧</param>
/// <param name="AIsRemote">是否为远程帧</param>
/// <param name="ADLC">数据长度</param>
/// <param name="ADataArray">数据数组</param>
/// <param name="AIsFD">是否为FD帧</param>
/// <param name="AIsBRS">是否为BRS</param>
/// <param name="isUpdateDBCDatabase">是否更新DBC数据库</param>
/// <param name="sendPeriod">发送周期 (ms)</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">发送周期 (ms)</param>
/// <returns></returns>
public static int AddCyclicMsg(byte channel, string AMsgName, float sendPeriod)
{
var find = DBCParse.MsgDatabase[channel].FirstOrDefault(s => s.msg_name == AMsgName);
if (find == null)
{
Debug.WriteLine($"AddCyclicMsg: 未找到消息定义, 消息: {AMsgName}, 通道: {channel}");
return -1; // 或抛出异常
}
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();
}
#endregion
#region ()
/// <summary>
/// 符合 TCANFDQueueEvent_Win32 委托签名的回调方法
/// </summary>
/// <param name="AObj">对象句柄</param>
/// <param name="AData">接收到的 CANFD 报文</param>
private static void OnCanFdMessageReceived(ref int AObj, ref TLIBCANFD AData)
{
// 将接收到的报文加入队列
lock (_lock)
{
// 为防止队列无限增长,可以添加一个简单的大小限制
if (_receivedMessages.Count < 10000) // 例如限制队列最大10000个报文
{
_receivedMessages.Enqueue(AData);
}
// 可选:记录队列溢出
else
{
Debug.WriteLine("接收队列已满,丢弃新报文。");
}
}
}
/// <summary>
/// 注册接收报文的监听器 (需要在连接前调用)
/// </summary>
/// <returns></returns>
public static int RegisterReceiveListener()
{
return RegisterListener(OnCanFdMessageReceived);
}
/// <summary>
/// 尝试获取一个接收到的CANFD报文
/// </summary>
/// <param name="receivedMsg">输出报文对象</param>
/// <returns>如果队列不为空则返回true否则返回false</returns>
public static bool TryGetReceivedMessage(out TLIBCANFD receivedMsg)
{
lock (_lock)
{
if (_receivedMessages.Count > 0)
{
receivedMsg = _receivedMessages.Dequeue();
return true;
}
else
{
receivedMsg = new TLIBCANFD(); // 返回默认值
return false;
}
}
}
/// <summary>
/// 获取接收队列中的报文数量
/// </summary>
/// <returns></returns>
public static int GetReceivedMessageCount()
{
lock (_lock)
{
return _receivedMessages.Count;
}
}
/// <summary>
/// 清空接收队列
/// </summary>
public static void ClearReceivedMessages()
{
lock (_lock)
{
_receivedMessages.Clear();
}
}
/// <summary>
/// 从接收到的报文中解析信号值 (基于DBC)
/// </summary>
/// <param name="receivedMsg">接收到的报文</param>
/// <param name="AMsgName">消息名称</param>
/// <param name="ASgnName">信号名称</param>
/// <returns>信号值</returns>
public static double GetSignalValueFromReceivedMessage(TLIBCANFD receivedMsg, string AMsgName, string ASgnName)
{
double value = double.NaN;
var re = TsMasterApi.tsdb_get_signal_value_canfd(ref receivedMsg, AMsgName, ASgnName, ref value);
if (re != 0)
{
Debug.WriteLine($"GetSignalValueFromReceivedMessage: 从报文中解析信号值失败, 错误代码: {re}, 消息: {AMsgName}, 信号: {ASgnName}");
}
return value;
}
/// <summary>
/// 从接收到的报文中解析信号值 (基于DBC) - 便捷方法
/// 该方法会先尝试获取一个报文,然后解析信号值
/// </summary>
/// <param name="channel">期望的通道 (用于过滤)</param>
/// <param name="expectedID">期望的报文ID (用于过滤, 0 表示不过滤)</param>
/// <param name="AMsgName">消息名称</param>
/// <param name="ASgnName">信号名称</param>
/// <returns>信号值,如果获取失败则返回 NaN</returns>
public static double GetSignalValueFromReceivedMessage(byte channel, uint expectedID, string AMsgName, string ASgnName)
{
var value = double.NaN;
// 创建一个临时队列来存放不符合条件的报文
var tempQueue = new Queue<TLIBCANFD>();
lock (_lock)
{
while (_receivedMessages.Count > 0)
{
var msg = _receivedMessages.Dequeue();
// 检查是否符合条件
if (msg.FIdxChn == channel && (expectedID == 0 || (uint)msg.FIdentifier == expectedID))
{
// 符合条件,尝试解析信号值
var re = TsMasterApi.tsdb_get_signal_value_canfd(ref msg, AMsgName, ASgnName, ref value);
if (re == 0)
{
// 解析成功,将 tempQueue 中的报文放回主队列
while (tempQueue.Count > 0)
{
_receivedMessages.Enqueue(tempQueue.Dequeue());
}
return value; // 返回解析出的值
}
else
{
Debug.WriteLine($"GetSignalValueFromReceivedMessage: 从报文中解析信号值失败, 错误代码: {re}, 消息: {AMsgName}, 信号: {ASgnName}");
}
}
// 不符合条件或解析失败,放入临时队列
tempQueue.Enqueue(msg);
}
// 将临时队列中的所有报文放回主队列
while (tempQueue.Count > 0)
{
_receivedMessages.Enqueue(tempQueue.Dequeue());
}
}
return value; // 返回 NaN
}
#endregion
/// <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}";
string? description = Marshal.PtrToStringAnsi(ADesc);
return description ?? $"未知错误代码: {errorCode}";
}
#region CANFD转换相关方法
/// <summary>
/// CANFD转CAN
/// 注意如果CANFD报文长度超过8字节转换时会截断数据。
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>CAN消息</returns>
public static TLIBCAN CANFDToCAN(TLIBCANFD canfdMsg)
{
TLIBCAN canMsg = new TLIBCAN
{
FIdxChn = canfdMsg.FIdxChn,
FProperties = canfdMsg.FProperties,
FIdentifier = canfdMsg.FIdentifier,
FData = new byte[8], // CAN标准数据长度
FTimeUS = canfdMsg.FTimeUS, // 时间戳保持不变
FDLC = canfdMsg.FDLC > 8 ? (byte)8 : canfdMsg.FDLC, // DLC限制在8以内
FIsTx = canfdMsg.FIsTx,
FIsError = canfdMsg.FIsError,
FIsExt = canfdMsg.FIsExt,
FIsRemote = canfdMsg.FIsRemote
};
// 复制数据只取前8字节
Array.Copy(canfdMsg.FData, 0, canMsg.FData, 0, Math.Min(8, canfdMsg.FData.Length));
return canMsg;
}
/// <summary>
/// CAN转CANFD
/// </summary>
/// <param name="canMsg">CAN消息</param>
/// <returns>CANFD消息</returns>
public static TLIBCANFD CANToCANFD(TLIBCAN canMsg)
{
TLIBCANFD canfdMsg = new TLIBCANFD
{
FIdxChn = canMsg.FIdxChn,
FProperties = canMsg.FProperties, // 保留原始属性
FIdentifier = canMsg.FIdentifier,
FData = new byte[64], // CANFD最大数据长度
FTimeUS = canMsg.FTimeUS,
FDLC = canMsg.FDLC,
FFDProperties = 0, // 新的CANFD报文FD属性初始化为0
FIsTx = canMsg.FIsTx,
FIsError = canMsg.FIsError,
FIsExt = canMsg.FIsExt,
FIsRemote = canMsg.FIsRemote,
FIsFD = false, // 从CAN转换明确设置为非FD
FIsBRS = false // 从CAN转换明确设置为不支持BRS
};
// 复制数据
Array.Copy(canMsg.FData, 0, canfdMsg.FData, 0, Math.Min(64, canMsg.FData.Length));
return canfdMsg;
}
#endregion
#region CANFD报文属性获取方法
/// <summary>
/// 获取CANFD报文内容
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>报文数据数组长度为FDLC指定的长度</returns>
public static byte[] GetCANFDMsgContent(TLIBCANFD canfdMsg)
{
byte[] content = new byte[Math.Min(canfdMsg.FData.Length, canfdMsg.FDLC)];
Array.Copy(canfdMsg.FData, 0, content, 0, content.Length);
return content;
}
/// <summary>
/// 获取CANFD报文时间戳 (微秒)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>时间戳 (微秒)</returns>
public static ulong GetCANFDMsgTimestamp(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FTimeUS;
}
/// <summary>
/// 获取CANFD报文数据长度 (DLC)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>数据长度 (DLC)</returns>
public static byte GetCANFDMsgDataLength(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FDLC;
}
/// <summary>
/// 获取CANFD报文是否为错误帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>是否为错误帧</returns>
public static bool GetCANFDMsgIsError(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FIsError;
}
/// <summary>
/// 获取CANFD报文通道
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>通道号</returns>
public static byte GetCANFDMsgChannel(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FIdxChn;
}
/// <summary>
/// 获取CANFD报文FD相关属性 (具体含义需参考TSMaster文档)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>FD属性</returns>
public static uint GetCANFDMsgFDProperties(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FFDProperties;
}
/// <summary>
/// 获取CANFD报文基础属性 (具体含义需参考TSMaster文档)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>基础属性</returns>
public static uint GetCANFDMsgProperties(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FProperties;
}
/// <summary>
/// 获取CANFD报文标识符 (ID)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>标识符 (ID)</returns>
public static uint GetCANFDMsgIdentifier(ref TLIBCANFD canfdMsg)
{
return (uint)canfdMsg.FIdentifier;
}
/// <summary>
/// 获取CANFD报文是否为FD帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>是否为FD帧</returns>
public static bool GetCANFDMsgIsFD(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FIsFD;
}
/// <summary>
/// 获取CANFD报文是否为远程帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>是否为远程帧</returns>
public static bool GetCANFDMsgIsRemote(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FIsRemote;
}
/// <summary>
/// 获取CANFD报文是否为扩展帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>是否为扩展帧</returns>
public static bool GetCANFDMsgIsExt(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FIsExt;
}
/// <summary>
/// 获取CANFD报文是否为BRS (Bit Rate Switch)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>是否为BRS</returns>
public static bool GetCANFDMsgIsBRS(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FIsBRS;
}
/// <summary>
/// 获取CANFD报文是否为发送帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>是否为发送帧</returns>
public static bool GetCANFDMsgIsTx(ref TLIBCANFD canfdMsg)
{
return canfdMsg.FIsTx;
}
/// <summary>
/// 获取CANFD报文是否为ESI (Error State Indicator)
/// 注意此API接口可能无法直接从TLIBCANFD结构获取ESI值。
/// ESI通常由总线决定接收时反映发送节点的错误状态。
/// 当前实现返回FFDProperties的最低位但这可能不准确。
/// 实际使用中可能需要通过其他方式或API获取。
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <returns>是否为ESI (当前实现仅供参考)</returns>
public static bool GetCANFDMsgIsESI(ref TLIBCANFD canfdMsg)
{
return (canfdMsg.FFDProperties & 0x01) != 0; // 警告:此实现可能不正确
}
#endregion
#region CANFD报文设置方法
/// <summary>
/// 设置CANFD报文内容
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="data">要设置的数据</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgContent(ref TLIBCANFD canfdMsg, byte[] data)
{
if (data == null || data.Length == 0)
return -1; // 错误代码
int length = Math.Min(data.Length, canfdMsg.FData.Length);
Array.Copy(data, 0, canfdMsg.FData, 0, length);
canfdMsg.FDLC = (byte)length; // 同时更新DLC
return 0;
}
/// <summary>
/// 设置CANFD报文时间戳 (微秒)
/// 注意:此时间戳通常由硬件/驱动在接收时设置,发送时设置可能无效或有特殊用途。
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="timestamp">时间戳 (微秒)</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgTimestamp(ref TLIBCANFD canfdMsg, ulong timestamp)
{
canfdMsg.FTimeUS = timestamp;
return 0;
}
/// <summary>
/// 设置CANFD报文数据长度 (DLC)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="length">数据长度 (DLC)</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgDataLength(ref TLIBCANFD canfdMsg, byte length)
{
if (length > canfdMsg.FData.Length)
return -1; // 错误代码,长度超出数组大小
canfdMsg.FDLC = length;
return 0;
}
/// <summary>
/// 设置CANFD报文是否为错误帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="isError">是否为错误帧</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgIsError(ref TLIBCANFD canfdMsg, bool isError)
{
canfdMsg.FIsError = isError;
return 0;
}
/// <summary>
/// 设置CANFD报文通道
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="channel">通道号</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgChannel(ref TLIBCANFD canfdMsg, byte channel)
{
canfdMsg.FIdxChn = channel;
return 0;
}
/// <summary>
/// 设置CANFD报文FD相关属性
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="fdProperties">FD属性</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgFDProperties(ref TLIBCANFD canfdMsg, uint fdProperties)
{
canfdMsg.FFDProperties = (byte)fdProperties;
return 0;
}
/// <summary>
/// 设置CANFD报文基础属性
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="properties">基础属性</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgProperties(ref TLIBCANFD canfdMsg, uint properties)
{
canfdMsg.FProperties = (byte)properties;
return 0;
}
/// <summary>
/// 设置CANFD报文标识符 (ID)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="identifier">标识符 (ID)</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgIdentifier(ref TLIBCANFD canfdMsg, uint identifier)
{
canfdMsg.FIdentifier = (int)identifier;
return 0;
}
/// <summary>
/// 设置CANFD报文是否为FD帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="isFD">是否为FD帧</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgIsFD(ref TLIBCANFD canfdMsg, bool isFD)
{
canfdMsg.FIsFD = isFD;
return 0;
}
/// <summary>
/// 设置CANFD报文是否为远程帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="isRemote">是否为远程帧</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgIsRemote(ref TLIBCANFD canfdMsg, bool isRemote)
{
canfdMsg.FIsRemote = isRemote;
return 0;
}
/// <summary>
/// 设置CANFD报文是否为扩展帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="isExt">是否为扩展帧</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgIsExt(ref TLIBCANFD canfdMsg, bool isExt)
{
canfdMsg.FIsExt = isExt;
return 0;
}
/// <summary>
/// 设置CANFD报文是否为BRS (Bit Rate Switch)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="isBRS">是否为BRS</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgIsBRS(ref TLIBCANFD canfdMsg, bool isBRS)
{
canfdMsg.FIsBRS = isBRS;
return 0;
}
/// <summary>
/// 设置CANFD报文是否为发送帧
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="isTx">是否为发送帧</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgIsTx(ref TLIBCANFD canfdMsg, bool isTx)
{
canfdMsg.FIsTx = isTx;
return 0;
}
/// <summary>
/// 设置CANFD报文是否为ESI (Error State Indicator)
/// 注意此API接口可能无法直接设置TLIBCANFD结构中的ESI值。
/// ESI通常由硬件根据发送节点的错误状态自动设置。
/// 当前实现通过操作FFDProperties的最低位来模拟但这可能无效或不正确。
/// 实际使用中可能无法或不应通过这种方式设置。
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="isESI">是否为ESI (当前实现仅供参考,可能无效)</param>
/// <returns>设置结果 (0为成功)</returns>
public static int SetCANFDMsgIsESI(ref TLIBCANFD canfdMsg, bool isESI)
{
byte mask = 0x01; // 最低位
if (isESI)
canfdMsg.FFDProperties |= mask; // 设置最低位
else
canfdMsg.FFDProperties &= (byte)~mask; // 清除最低位 (注意:~mask 会得到 -2所以需要强制转换为 byte)
return 0;
}
#endregion
/// <summary>
/// 获取CANFD报文指定字节的指定位的值 (0 或 1)
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="byteIndex">字节索引 (0-63 for CANFD)</param>
/// <param name="bitIndex">位索引 (0-7)</param>
/// <returns>位的值 (0 或 1),如果索引无效则返回 -1</returns>
public static int GetCANFDMsgBitValue(ref TLIBCANFD canfdMsg, int byteIndex, int bitIndex)
{
if (byteIndex < 0 || byteIndex >= canfdMsg.FData.Length || bitIndex < 0 || bitIndex > 7)
{
Debug.WriteLine($"GetCANFDMsgBitValue: Invalid index - byteIndex: {byteIndex}, bitIndex: {bitIndex}");
return -1; // 或者抛出异常
}
byte mask = (byte)(1 << bitIndex);
return (canfdMsg.FData[byteIndex] & mask) != 0 ? 1 : 0;
}
/// <summary>
/// 设置CANFD报文指定字节的指定位的值
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="byteIndex">字节索引 (0-63 for CANFD)</param>
/// <param name="bitIndex">位索引 (0-7)</param>
/// <param name="value">要设置的值 (0 或 1)</param>
/// <returns>操作结果 (0为成功, -1为失败)</returns>
public static int SetCANFDMsgBitValue(ref TLIBCANFD canfdMsg, int byteIndex, int bitIndex, int value)
{
if (byteIndex < 0 || byteIndex >= canfdMsg.FData.Length || bitIndex < 0 || bitIndex > 7 || (value != 0 && value != 1))
{
Debug.WriteLine($"SetCANFDMsgBitValue: Invalid input - byteIndex: {byteIndex}, bitIndex: {bitIndex}, value: {value}");
return -1; // 或者抛出异常
}
byte mask = (byte)(1 << bitIndex);
if (value == 1)
{
canfdMsg.FData[byteIndex] |= mask; // 设置该位
}
else
{
canfdMsg.FData[byteIndex] &= (byte)~mask; // 清除该位
}
return 0;
}
/// <summary>
/// 对CANFD报文指定字节执行按位与(&)操作
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="byteIndex">字节索引 (0-63 for CANFD)</param>
/// <param name="mask">要与的掩码值 (byte)</param>
/// <returns>操作结果 (0为成功, -1为失败)</returns>
public static int BitwiseAndCANFDMsgByte(ref TLIBCANFD canfdMsg, int byteIndex, byte mask)
{
if (byteIndex < 0 || byteIndex >= canfdMsg.FData.Length)
{
Debug.WriteLine($"BitwiseAndCANFDMsgByte: Invalid byteIndex - {byteIndex}");
return -1;
}
canfdMsg.FData[byteIndex] &= mask;
return 0;
}
/// <summary>
/// 对CANFD报文指定字节执行按位或(|)操作
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="byteIndex">字节索引 (0-63 for CANFD)</param>
/// <param name="mask">要或的掩码值 (byte)</param>
/// <returns>操作结果 (0为成功, -1为失败)</returns>
public static int BitwiseOrCANFDMsgByte(ref TLIBCANFD canfdMsg, int byteIndex, byte mask)
{
if (byteIndex < 0 || byteIndex >= canfdMsg.FData.Length)
{
Debug.WriteLine($"BitwiseOrCANFDMsgByte: Invalid byteIndex - {byteIndex}");
return -1;
}
canfdMsg.FData[byteIndex] |= mask;
return 0;
}
/// <summary>
/// 对CANFD报文指定字节执行按位异或(^)操作
/// </summary>
/// <param name="canfdMsg">CANFD消息</param>
/// <param name="byteIndex">字节索引 (0-63 for CANFD)</param>
/// <param name="mask">要异或的掩码值 (byte)</param>
/// <returns>操作结果 (0为成功, -1为失败)</returns>
public static int BitwiseXorCANFDMsgByte(ref TLIBCANFD canfdMsg, int byteIndex, byte mask)
{
if (byteIndex < 0 || byteIndex >= canfdMsg.FData.Length)
{
Debug.WriteLine($"BitwiseXorCANFDMsgByte: Invalid byteIndex - {byteIndex}");
return -1;
}
canfdMsg.FData[byteIndex] ^= mask;
return 0;
}
#region CAN Message Handling (CAN添加位操作方法)
/// <summary>
/// 获取CAN报文指定字节的指定位的值 (0 或 1)
/// </summary>
/// <param name="canMsg">CAN消息</param>
/// <param name="byteIndex">字节索引 (0-7 for CAN)</param>
/// <param name="bitIndex">位索引 (0-7)</param>
/// <returns>位的值 (0 或 1),如果索引无效则返回 -1</returns>
public static int GetCANMsgBitValue(ref TLIBCAN canMsg, int byteIndex, int bitIndex)
{
if (byteIndex < 0 || byteIndex >= canMsg.FData.Length || bitIndex < 0 || bitIndex > 7)
{
Debug.WriteLine($"GetCANMsgBitValue: Invalid index - byteIndex: {byteIndex}, bitIndex: {bitIndex}");
return -1;
}
byte mask = (byte)(1 << bitIndex);
return (canMsg.FData[byteIndex] & mask) != 0 ? 1 : 0;
}
/// <summary>
/// 设置CAN报文指定字节的指定位的值
/// </summary>
/// <param name="canMsg">CAN消息</param>
/// <param name="byteIndex">字节索引 (0-7 for CAN)</param>
/// <param name="bitIndex">位索引 (0-7)</param>
/// <param name="value">要设置的值 (0 或 1)</param>
/// <returns>操作结果 (0为成功, -1为失败)</returns>
public static int SetCANMsgBitValue(ref TLIBCAN canMsg, int byteIndex, int bitIndex, int value)
{
if (byteIndex < 0 || byteIndex >= canMsg.FData.Length || bitIndex < 0 || bitIndex > 7 || (value != 0 && value != 1))
{
Debug.WriteLine($"SetCANMsgBitValue: Invalid input - byteIndex: {byteIndex}, bitIndex: {bitIndex}, value: {value}");
return -1;
}
byte mask = (byte)(1 << bitIndex);
if (value == 1)
{
canMsg.FData[byteIndex] |= mask;
}
else
{
canMsg.FData[byteIndex] &= (byte)~mask;
}
return 0;
}
/// <summary>
/// 对CAN报文指定字节执行按位与(&)操作
/// </summary>
/// <param name="canMsg">CAN消息</param>
/// <param name="byteIndex">字节索引 (0-7 for CAN)</param>
/// <param name="mask">要与的掩码值 (byte)</param>
/// <returns>操作结果 (0为成功, -1为失败)</returns>
public static int BitwiseAndCANMsgByte(ref TLIBCAN canMsg, int byteIndex, byte mask)
{
if (byteIndex < 0 || byteIndex >= canMsg.FData.Length)
{
Debug.WriteLine($"BitwiseAndCANMsgByte: Invalid byteIndex - {byteIndex}");
return -1;
}
canMsg.FData[byteIndex] &= mask;
return 0;
}
/// <summary>
/// 对CAN报文指定字节执行按位或(|)操作
/// </summary>
/// <param name="canMsg">CAN消息</param>
/// <param name="byteIndex">字节索引 (0-7 for CAN)</param>
/// <param name="mask">要或的掩码值 (byte)</param>
/// <returns>操作结果 (0为成功, -1为失败)</returns>
public static int BitwiseOrCANMsgByte(ref TLIBCAN canMsg, int byteIndex, byte mask)
{
if (byteIndex < 0 || byteIndex >= canMsg.FData.Length)
{
Debug.WriteLine($"BitwiseOrCANMsgByte: Invalid byteIndex - {byteIndex}");
return -1;
}
canMsg.FData[byteIndex] |= mask;
return 0;
}
/// <summary>
/// 对CAN报文指定字节执行按位异或(^)操作
/// </summary>
/// <param name="canMsg">CAN消息</param>
/// <param name="byteIndex">字节索引 (0-7 for CAN)</param>
/// <param name="mask">要异或的掩码值 (byte)</param>
/// <returns>操作结果 (0为成功, -1为失败)</returns>
public static int BitwiseXorCANMsgByte(ref TLIBCAN canMsg, int byteIndex, byte mask)
{
if (byteIndex < 0 || byteIndex >= canMsg.FData.Length)
{
Debug.WriteLine($"BitwiseXorCANMsgByte: Invalid byteIndex - {byteIndex}");
return -1;
}
canMsg.FData[byteIndex] ^= mask;
return 0;
}
#endregion
}
}