using System; namespace CanSimulator { /// /// CAN 帧格式类型 /// public enum CanFrameFormat { /// 标准帧 (11-bit ID) Standard, /// 扩展帧 (29-bit ID) Extended } /// /// CAN 帧类型 /// public enum CanFrameType { /// 数据帧 Data, /// 远程帧 Remote } /// /// CAN 总线帧数据结构 /// public sealed class CanFrame { /// /// 帧 ID(标准帧 11-bit,扩展帧 29-bit) /// public uint FrameId { get; set; } /// /// 帧格式(标准/扩展) /// public CanFrameFormat Format { get; set; } = CanFrameFormat.Standard; /// /// 帧类型(数据帧/远程帧) /// public CanFrameType Type { get; set; } = CanFrameType.Data; /// /// 数据负载(最大 8 字节,CAN FD 可达 64 字节) /// public byte[] Data { get; set; } = Array.Empty(); /// /// 时间戳 /// public DateTime Timestamp { get; set; } = DateTime.Now; /// /// 发送节点标识 /// public string SourceNodeId { get; set; } = string.Empty; /// /// DLC (Data Length Code) /// public int Dlc => Data.Length; /// /// 将帧 ID 格式化为十六进制字符串 /// public string FrameIdHex => Format == CanFrameFormat.Extended ? $"0x{FrameId:X8}" : $"0x{FrameId:X3}"; /// /// 将数据格式化为十六进制字符串 /// public string DataHex => BitConverter.ToString(Data).Replace("-", " "); /// /// 从十六进制字符串解析帧 ID /// public static uint ParseFrameId(string frameIdStr) { if (string.IsNullOrWhiteSpace(frameIdStr)) throw new ArgumentException("帧 ID 不能为空", nameof(frameIdStr)); if (frameIdStr.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { if (!uint.TryParse(frameIdStr.Substring(2), System.Globalization.NumberStyles.HexNumber, null, out uint id)) throw new ArgumentException($"无法解析帧 ID: {frameIdStr}"); return id; } else { if (!uint.TryParse(frameIdStr, out uint id)) throw new ArgumentException($"无法解析帧 ID: {frameIdStr}"); return id; } } /// /// 从十六进制字符串解析数据 /// public static byte[] ParseData(string dataStr) { if (string.IsNullOrWhiteSpace(dataStr)) return Array.Empty(); try { var parts = dataStr.Split(new[] { ' ', '-', ',' }, StringSplitOptions.RemoveEmptyEntries); var bytes = new byte[parts.Length]; for (int i = 0; i < parts.Length; i++) { bytes[i] = byte.Parse(parts[i], System.Globalization.NumberStyles.HexNumber); } return bytes; } catch (Exception ex) { throw new ArgumentException($"无法解析数据字符串: {dataStr}, 错误: {ex.Message}"); } } public override string ToString() { return $"[{Timestamp:HH:mm:ss.fff}] {FrameIdHex} [{Dlc}] {DataHex} (from {SourceNodeId})"; } } }