1225 lines
45 KiB
C#
1225 lines
45 KiB
C#
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
|
||
}
|
||
} |