GSUSB 设备协议栈
本文档描述 XRUSB 的 GSUSB(Linux gs_usb) 设备类实现:LibXR::USB::GsUsbClass<CanChNum>。
该设备类面向 Linux/SocketCAN 生态的 USB-to-CAN 使用方式,采用 Vendor Interface + Bulk IN/OUT 的传输模型,实现 gs_usb 协议常用控制面与数据面。
支持能力:
- 经典 CAN(Classic CAN):最大 8 字节数据
- CAN FD(可选):最大 64 字节数据区,DLC 映射遵循 FD 表
- TX echo:回送
echo_id,用于主机侧 TX buffer 跟踪 - 可选时间戳字段:
timestamp_us(4 字节)追加在 wire frame 末尾,数值来自LibXR::Timebase::GetMicroseconds()的低 32 位 - 多通道:通道数由模板参数
CanChNum编译期固定
1. 类与构造方式
GsUsbClass<CanChNum> 中 CanChNum 为编译期固定的 CAN 通道数(1..255),通道号对外以 uint8_t 表示。构造时需提供 等于 CanChNum 数量的通道对象指针列表。
该类同时兼容 Classic CAN 与 FDCAN(启用 FD 能力),通过不同构造函数区分。
1.1 Classic CAN 构造
GsUsbClass(std::initializer_list<LibXR::CAN*> cans,
Endpoint::EPNumber data_in_ep_num = EP1,
Endpoint::EPNumber data_out_ep_num = EP2,
size_t rx_queue_size = 32,
size_t echo_queue_size = 32,
LibXR::GPIO* identify_gpio = nullptr,
std::initializer_list<LibXR::GPIO*> termination_gpios = {},
LibXR::Database* database = nullptr);
要点:
cans:Classic CAN 指针列表,数量必须等于CanChNum- 默认端点号为 EP1(IN)/EP2(OUT):用于兼容部分旧版内核/驱动对端点布局的约束
- Linux
gs_usb驱动通常会通过 VID:PID 白名单匹配设备,并要求匹配到bInterfaceNumber == 0的 USB interface(建议将该类放在配置中的第一个 interface)
1.2 FDCAN 构造(启用 FD)
GsUsbClass(std::initializer_list<LibXR::FDCAN*> fd_cans,
Endpoint::EPNumber data_in_ep_num = EP_AUTO,
Endpoint::EPNumber data_out_ep_num = EP_AUTO,
size_t rx_queue_size = 32,
size_t echo_queue_size = 32,
LibXR::GPIO* identify_gpio = nullptr,
std::initializer_list<LibXR::GPIO*> termination_gpios = {},
LibXR::Database* database = nullptr);
要点:
fd_cans:FDCAN 指针列表,数量必须等于CanChNum- 若驱动对端点号没有限制,可用
EP_AUTO让端点自动分配 - FD 能力是否真正可用,取决于设备端是否启用 FD 支持、以及主机侧是否通过控制面将对应通道置为 FD 模式
2. USB 接口与端点
2.1 接口描述符
GsUsbClass 暴露 1 个接口,不使用 IAD。接口的 class/subclass/protocol 固定为 0xFF/0xFF/0xFF(Vendor Specific),端点数为 2。
2.2 Bulk 端点
- Bulk OUT:Host → Device(主机下发 CAN/FD 帧,同时携带
echo_id用于 TX echo) - Bulk IN:Device → Host(设备上报 RX 帧/错误帧,以及 TX echo 回包)
端点最大传输长度由底层 Endpoint 实现决定;配置时以 UINT16_MAX 作为上限。
3. gs_usb wire format(数据面)
所有 Bulk 数据帧都以固定 12 字节头开头(小端):
struct WireHeader {
uint32_t echo_id; // Echo ID
uint32_t can_id; // CAN ID (with flags)
uint8_t can_dlc; // DLC
uint8_t channel; // Channel index
uint8_t flags; // GS_CAN_FLAG_*
uint8_t reserved;
}
约定:
- 设备上报 RX 帧时使用
ECHO_ID_RX = 0xFFFFFFFF - 主机下发帧若
echo_id != 0xFFFFFFFF,设备会在发送路径中生成对应的 TX echo 事件回送给主机
负载与长度:
- Classic CAN:payload 固定 8 字节
- CAN FD:payload 固定 64 字节
- 可选时间戳:若该通道启用时间戳,则在 payload 后追加 4 字节
timestamp_us(微秒,低 32 位)
总长度:
- Classic:
12 + 8(或12 + 8 + 4) - FD:
12 + 64(或12 + 64 + 4)