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})";
}
}
}