1049 lines
38 KiB
C#
1049 lines
38 KiB
C#
using Common.Attributes;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Diagnostics;
|
||
using System.IO;
|
||
using System.Runtime.InteropServices;
|
||
using System.Text.Json;
|
||
using TSMaster;
|
||
namespace CAN驱动
|
||
{
|
||
[BOBCommand]
|
||
public class 同星驱动类
|
||
{
|
||
|
||
public static event Action ConnectEvent;
|
||
public static event Action DisConnectEvent;
|
||
public static bool ConnectFlag { get; set; } = false;
|
||
|
||
/// <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();
|
||
//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(byte channel, string AMsgName, float sendPeriod = 0)
|
||
//{
|
||
// var find = DBCParse.MsgDatabase[channel].First(s => s.msg_name == AMsgName);
|
||
// find.ACANFD.FIdxChn = 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>
|
||
/// <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}";
|
||
}
|
||
|
||
#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)
|
||
{
|
||
// API文档未明确提供直接获取ESI的字段。
|
||
// 在CANFD协议中,ESI是报文中的一个位,由发送节点根据自身状态设置。
|
||
// TSMaster的TLIBCANFD结构体可能没有直接暴露这个原始位。
|
||
// FFDProperties可能包含相关信息,但具体哪一位是ESI需要查阅更详细的文档。
|
||
// 目前根据结构体字段推测,这可能不准确。
|
||
// 假设ESI信息可能隐含在FFDProperties中,但这种假设通常是错误的。
|
||
// 更可能的是,ESI信息在硬件层面处理,或通过其他方式反映。
|
||
// 因此,当前返回值可能不准确,需要根据实际API文档确认。
|
||
// 这里保留原实现,但加上说明。
|
||
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 类型的掩码进行位操作
|
||
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
|
||
}
|
||
}
|