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 { /// /// 同星CAN驱动类 /// [ATSCommand] [DeviceCategory("CAN卡驱动")] public class CAN { public static event Action ConnectEvent; public static event Action DisConnectEvent; public static bool ConnectFlag { get; set; } = false; /// /// 用于接收CAN报文的队列 /// private static readonly Queue _receivedMessages = new Queue(); private static readonly object _lock = new object(); // 线程安全锁 /// /// 初始化CAN驱动 /// /// /// /// [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)); } } /// /// 释放CAN驱动 /// [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; } /// /// 连接 /// /// 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; } /// /// 断开 /// /// 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; } /// /// 加载DBC /// /// /// /// /// [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; } /// /// 卸载DBC /// /// /// [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); } } /// /// 开始记录日志 /// /// /// public static int StartLogging(string filePath) { return TsMasterApi.tsapp_start_logging(Path.GetFullPath(filePath)); } /// /// 结束记录日志 /// /// public static int StopLogging() { return TsMasterApi.tsapp_stop_logging(); } /// /// 弹出通道映射窗口 /// /// /// [Browsable(false)] public static int ShowChannelMappingWindow(bool isWait = false) { return TsMasterApi.tsapp_show_tsmaster_window("Hardware", isWait); } #region 信号值获取方法 /// /// 获取信号值 (基于DBC) /// /// 通道 /// 消息名称 /// 信号名称 /// 信号值 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; } /// /// 获取信号值 (基于DBC) - 带返回值 /// /// 通道 /// 消息名称 /// 信号名称 /// 输出信号值 /// TSMaster API 返回值 [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 为未找到定义的错误码 } } /// /// 获取信号值 (基于已有的CANFD报文对象) - 已优化,无需用户传入 TLIBCANFD /// 此方法保留用于高级场景,但通常不推荐外部直接使用 /// /// CANFD报文对象 /// 消息名称 /// 信号名称 /// 输出信号值 /// TSMaster API 返回值 [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 信号值设置方法 /// /// 设置信号值 (基于DBC) /// /// 通道 /// 消息名称 /// 信号名称 /// 信号值 /// 是否立即发送 /// 发送周期 (ms),0表示单次发送 /// /// 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; } /// /// 设置信号值 (基于DBC) - 仅发送报文 /// /// 通道 /// 消息名称 /// 发送周期 (ms),0表示单次发送 /// 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 报文发送方法 /// /// 发送自定义报文 (基于 TLIBCANFD 对象) - 已优化,内部使用,外部不直接暴露 /// /// CANFD报文对象 /// [Browsable(false)] public static int SetMsg(TLIBCANFD msg) { return TsMasterApi.tsapp_transmit_canfd_async(ref msg); } /// /// 设置报文数据 (在DBC缓存中) /// /// 通道 /// 报文ID /// 报文数据数组 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}"); } } /// /// 发送自定义报文 /// /// 通道 /// 报文ID /// 是否为发送帧 /// 是否为扩展帧 /// 是否为远程帧 /// 数据长度 /// 数据数组 /// 是否为FD帧 /// 是否为BRS /// 是否更新DBC数据库 /// 发送周期 (ms) /// 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; } /// /// 添加循环发送报文 /// /// 通道 /// 消息名称 /// 发送周期 (ms) /// 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); } /// /// 清除循环发送的报文 /// /// public static int DeleteCyclicMsgs() { return TsMasterApi.tsapp_delete_cyclic_msgs(); } #endregion #region 接收报文和信号值方法 (新增) /// /// 符合 TCANFDQueueEvent_Win32 委托签名的回调方法 /// /// 对象句柄 /// 接收到的 CANFD 报文 private static void OnCanFdMessageReceived(ref int AObj, ref TLIBCANFD AData) { // 将接收到的报文加入队列 lock (_lock) { // 为防止队列无限增长,可以添加一个简单的大小限制 if (_receivedMessages.Count < 10000) // 例如,限制队列最大10000个报文 { _receivedMessages.Enqueue(AData); } // 可选:记录队列溢出 else { Debug.WriteLine("接收队列已满,丢弃新报文。"); } } } /// /// 注册接收报文的监听器 (需要在连接前调用) /// /// public static int RegisterReceiveListener() { return RegisterListener(OnCanFdMessageReceived); } /// /// 尝试获取一个接收到的CANFD报文 /// /// 输出报文对象 /// 如果队列不为空则返回true,否则返回false public static bool TryGetReceivedMessage(out TLIBCANFD receivedMsg) { lock (_lock) { if (_receivedMessages.Count > 0) { receivedMsg = _receivedMessages.Dequeue(); return true; } else { receivedMsg = new TLIBCANFD(); // 返回默认值 return false; } } } /// /// 获取接收队列中的报文数量 /// /// public static int GetReceivedMessageCount() { lock (_lock) { return _receivedMessages.Count; } } /// /// 清空接收队列 /// public static void ClearReceivedMessages() { lock (_lock) { _receivedMessages.Clear(); } } /// /// 从接收到的报文中解析信号值 (基于DBC) /// /// 接收到的报文 /// 消息名称 /// 信号名称 /// 信号值 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; } /// /// 从接收到的报文中解析信号值 (基于DBC) - 便捷方法 /// 该方法会先尝试获取一个报文,然后解析信号值 /// /// 期望的通道 (用于过滤) /// 期望的报文ID (用于过滤, 0 表示不过滤) /// 消息名称 /// 信号名称 /// 信号值,如果获取失败则返回 NaN public static double GetSignalValueFromReceivedMessage(byte channel, uint expectedID, string AMsgName, string ASgnName) { var value = double.NaN; // 创建一个临时队列来存放不符合条件的报文 var tempQueue = new Queue(); 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 /// /// 获取错误提示 /// /// 错误代码 /// 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转换相关方法 /// /// CANFD转CAN /// 注意:如果CANFD报文长度超过8字节,转换时会截断数据。 /// /// CANFD消息 /// CAN消息 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; } /// /// CAN转CANFD /// /// CAN消息 /// CANFD消息 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报文属性获取方法 /// /// 获取CANFD报文内容 /// /// CANFD消息 /// 报文数据数组,长度为FDLC指定的长度 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; } /// /// 获取CANFD报文时间戳 (微秒) /// /// CANFD消息 /// 时间戳 (微秒) public static ulong GetCANFDMsgTimestamp(ref TLIBCANFD canfdMsg) { return canfdMsg.FTimeUS; } /// /// 获取CANFD报文数据长度 (DLC) /// /// CANFD消息 /// 数据长度 (DLC) public static byte GetCANFDMsgDataLength(ref TLIBCANFD canfdMsg) { return canfdMsg.FDLC; } /// /// 获取CANFD报文是否为错误帧 /// /// CANFD消息 /// 是否为错误帧 public static bool GetCANFDMsgIsError(ref TLIBCANFD canfdMsg) { return canfdMsg.FIsError; } /// /// 获取CANFD报文通道 /// /// CANFD消息 /// 通道号 public static byte GetCANFDMsgChannel(ref TLIBCANFD canfdMsg) { return canfdMsg.FIdxChn; } /// /// 获取CANFD报文FD相关属性 (具体含义需参考TSMaster文档) /// /// CANFD消息 /// FD属性 public static uint GetCANFDMsgFDProperties(ref TLIBCANFD canfdMsg) { return canfdMsg.FFDProperties; } /// /// 获取CANFD报文基础属性 (具体含义需参考TSMaster文档) /// /// CANFD消息 /// 基础属性 public static uint GetCANFDMsgProperties(ref TLIBCANFD canfdMsg) { return canfdMsg.FProperties; } /// /// 获取CANFD报文标识符 (ID) /// /// CANFD消息 /// 标识符 (ID) public static uint GetCANFDMsgIdentifier(ref TLIBCANFD canfdMsg) { return (uint)canfdMsg.FIdentifier; } /// /// 获取CANFD报文是否为FD帧 /// /// CANFD消息 /// 是否为FD帧 public static bool GetCANFDMsgIsFD(ref TLIBCANFD canfdMsg) { return canfdMsg.FIsFD; } /// /// 获取CANFD报文是否为远程帧 /// /// CANFD消息 /// 是否为远程帧 public static bool GetCANFDMsgIsRemote(ref TLIBCANFD canfdMsg) { return canfdMsg.FIsRemote; } /// /// 获取CANFD报文是否为扩展帧 /// /// CANFD消息 /// 是否为扩展帧 public static bool GetCANFDMsgIsExt(ref TLIBCANFD canfdMsg) { return canfdMsg.FIsExt; } /// /// 获取CANFD报文是否为BRS (Bit Rate Switch) /// /// CANFD消息 /// 是否为BRS public static bool GetCANFDMsgIsBRS(ref TLIBCANFD canfdMsg) { return canfdMsg.FIsBRS; } /// /// 获取CANFD报文是否为发送帧 /// /// CANFD消息 /// 是否为发送帧 public static bool GetCANFDMsgIsTx(ref TLIBCANFD canfdMsg) { return canfdMsg.FIsTx; } /// /// 获取CANFD报文是否为ESI (Error State Indicator) /// 注意:此API接口可能无法直接从TLIBCANFD结构获取ESI值。 /// ESI通常由总线决定,接收时反映发送节点的错误状态。 /// 当前实现返回FFDProperties的最低位,但这可能不准确。 /// 实际使用中可能需要通过其他方式或API获取。 /// /// CANFD消息 /// 是否为ESI (当前实现仅供参考) public static bool GetCANFDMsgIsESI(ref TLIBCANFD canfdMsg) { return (canfdMsg.FFDProperties & 0x01) != 0; // 警告:此实现可能不正确 } #endregion #region CANFD报文设置方法 /// /// 设置CANFD报文内容 /// /// CANFD消息 /// 要设置的数据 /// 设置结果 (0为成功) 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; } /// /// 设置CANFD报文时间戳 (微秒) /// 注意:此时间戳通常由硬件/驱动在接收时设置,发送时设置可能无效或有特殊用途。 /// /// CANFD消息 /// 时间戳 (微秒) /// 设置结果 (0为成功) public static int SetCANFDMsgTimestamp(ref TLIBCANFD canfdMsg, ulong timestamp) { canfdMsg.FTimeUS = timestamp; return 0; } /// /// 设置CANFD报文数据长度 (DLC) /// /// CANFD消息 /// 数据长度 (DLC) /// 设置结果 (0为成功) public static int SetCANFDMsgDataLength(ref TLIBCANFD canfdMsg, byte length) { if (length > canfdMsg.FData.Length) return -1; // 错误代码,长度超出数组大小 canfdMsg.FDLC = length; return 0; } /// /// 设置CANFD报文是否为错误帧 /// /// CANFD消息 /// 是否为错误帧 /// 设置结果 (0为成功) public static int SetCANFDMsgIsError(ref TLIBCANFD canfdMsg, bool isError) { canfdMsg.FIsError = isError; return 0; } /// /// 设置CANFD报文通道 /// /// CANFD消息 /// 通道号 /// 设置结果 (0为成功) public static int SetCANFDMsgChannel(ref TLIBCANFD canfdMsg, byte channel) { canfdMsg.FIdxChn = channel; return 0; } /// /// 设置CANFD报文FD相关属性 /// /// CANFD消息 /// FD属性 /// 设置结果 (0为成功) public static int SetCANFDMsgFDProperties(ref TLIBCANFD canfdMsg, uint fdProperties) { canfdMsg.FFDProperties = (byte)fdProperties; return 0; } /// /// 设置CANFD报文基础属性 /// /// CANFD消息 /// 基础属性 /// 设置结果 (0为成功) public static int SetCANFDMsgProperties(ref TLIBCANFD canfdMsg, uint properties) { canfdMsg.FProperties = (byte)properties; return 0; } /// /// 设置CANFD报文标识符 (ID) /// /// CANFD消息 /// 标识符 (ID) /// 设置结果 (0为成功) public static int SetCANFDMsgIdentifier(ref TLIBCANFD canfdMsg, uint identifier) { canfdMsg.FIdentifier = (int)identifier; return 0; } /// /// 设置CANFD报文是否为FD帧 /// /// CANFD消息 /// 是否为FD帧 /// 设置结果 (0为成功) public static int SetCANFDMsgIsFD(ref TLIBCANFD canfdMsg, bool isFD) { canfdMsg.FIsFD = isFD; return 0; } /// /// 设置CANFD报文是否为远程帧 /// /// CANFD消息 /// 是否为远程帧 /// 设置结果 (0为成功) public static int SetCANFDMsgIsRemote(ref TLIBCANFD canfdMsg, bool isRemote) { canfdMsg.FIsRemote = isRemote; return 0; } /// /// 设置CANFD报文是否为扩展帧 /// /// CANFD消息 /// 是否为扩展帧 /// 设置结果 (0为成功) public static int SetCANFDMsgIsExt(ref TLIBCANFD canfdMsg, bool isExt) { canfdMsg.FIsExt = isExt; return 0; } /// /// 设置CANFD报文是否为BRS (Bit Rate Switch) /// /// CANFD消息 /// 是否为BRS /// 设置结果 (0为成功) public static int SetCANFDMsgIsBRS(ref TLIBCANFD canfdMsg, bool isBRS) { canfdMsg.FIsBRS = isBRS; return 0; } /// /// 设置CANFD报文是否为发送帧 /// /// CANFD消息 /// 是否为发送帧 /// 设置结果 (0为成功) public static int SetCANFDMsgIsTx(ref TLIBCANFD canfdMsg, bool isTx) { canfdMsg.FIsTx = isTx; return 0; } /// /// 设置CANFD报文是否为ESI (Error State Indicator) /// 注意:此API接口可能无法直接设置TLIBCANFD结构中的ESI值。 /// ESI通常由硬件根据发送节点的错误状态自动设置。 /// 当前实现通过操作FFDProperties的最低位来模拟,但这可能无效或不正确。 /// 实际使用中可能无法或不应通过这种方式设置。 /// /// CANFD消息 /// 是否为ESI (当前实现仅供参考,可能无效) /// 设置结果 (0为成功) 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 /// /// 获取CANFD报文指定字节的指定位的值 (0 或 1) /// /// CANFD消息 /// 字节索引 (0-63 for CANFD) /// 位索引 (0-7) /// 位的值 (0 或 1),如果索引无效则返回 -1 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; } /// /// 设置CANFD报文指定字节的指定位的值 /// /// CANFD消息 /// 字节索引 (0-63 for CANFD) /// 位索引 (0-7) /// 要设置的值 (0 或 1) /// 操作结果 (0为成功, -1为失败) 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; } /// /// 对CANFD报文指定字节执行按位与(&)操作 /// /// CANFD消息 /// 字节索引 (0-63 for CANFD) /// 要与的掩码值 (byte) /// 操作结果 (0为成功, -1为失败) 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; } /// /// 对CANFD报文指定字节执行按位或(|)操作 /// /// CANFD消息 /// 字节索引 (0-63 for CANFD) /// 要或的掩码值 (byte) /// 操作结果 (0为成功, -1为失败) 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; } /// /// 对CANFD报文指定字节执行按位异或(^)操作 /// /// CANFD消息 /// 字节索引 (0-63 for CANFD) /// 要异或的掩码值 (byte) /// 操作结果 (0为成功, -1为失败) 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添加位操作方法) /// /// 获取CAN报文指定字节的指定位的值 (0 或 1) /// /// CAN消息 /// 字节索引 (0-7 for CAN) /// 位索引 (0-7) /// 位的值 (0 或 1),如果索引无效则返回 -1 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; } /// /// 设置CAN报文指定字节的指定位的值 /// /// CAN消息 /// 字节索引 (0-7 for CAN) /// 位索引 (0-7) /// 要设置的值 (0 或 1) /// 操作结果 (0为成功, -1为失败) 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; } /// /// 对CAN报文指定字节执行按位与(&)操作 /// /// CAN消息 /// 字节索引 (0-7 for CAN) /// 要与的掩码值 (byte) /// 操作结果 (0为成功, -1为失败) 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; } /// /// 对CAN报文指定字节执行按位或(|)操作 /// /// CAN消息 /// 字节索引 (0-7 for CAN) /// 要或的掩码值 (byte) /// 操作结果 (0为成功, -1为失败) 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; } /// /// 对CAN报文指定字节执行按位异或(^)操作 /// /// CAN消息 /// 字节索引 (0-7 for CAN) /// 要异或的掩码值 (byte) /// 操作结果 (0为成功, -1为失败) 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 } }