UCAN 协议

UCAN 是基于微控制器的 USB-CAN 适配器所使用的协议,该适配器集成在 Theobroma Systems 的片上系统 (System-on-Modules) 上,也可作为独立的 USB 棒使用。

UCAN 协议被设计为与硬件无关。它的模型与 Linux 在内部表示 CAN 设备的方式非常相似。所有多字节整数都以小端字节序编码。

本文档中提到的所有结构都在 drivers/net/can/usb/ucan.c 中定义。

USB 端点

UCAN 设备使用三个 USB 端点

控制端点

驱动程序在此端点上发送设备管理命令

IN 端点

设备发送 CAN 数据帧和 CAN 错误帧

OUT 端点

驱动程序在 OUT 端点上发送 CAN 数据帧

控制消息

UCAN 设备使用控制管道上的供应商请求进行配置。

为了在单个 USB 设备中支持多个 CAN 接口,所有配置命令都针对 USB 描述符中相应的接口。

驱动程序使用 ucan_ctrl_command_in/outucan_device_request_in 将命令传递给设备。

设置数据包

bmRequestType

方向 | 供应商 | (接口或设备)

bRequest

命令号

wValue

子命令号 (16 位) 或 0 (如果未使用)

wIndex

USB 接口索引 (设备命令为 0)

wLength

  • 主机到设备 - 要传输的字节数

  • 设备到主机 - 要接收的最大字节数。如果设备发送较少字节,则使用常见的 ZLP 语义。

错误处理

设备通过停止管道来指示失败的控制命令。

设备命令

UCAN_DEVICE_GET_FW_STRING

设备到主机;可选

请求设备固件字符串。

接口命令

UCAN_COMMAND_START

主机到设备;强制

启动 CAN 接口。

有效负载格式

ucan_ctl_payload_t.cmd_start

mode

UCAN_MODE_* 的或掩码

UCAN_COMMAND_STOP

主机到设备;强制

停止 CAN 接口

有效负载格式

UCAN_COMMAND_RESET

主机到设备;强制

重置 CAN 控制器 (包括错误计数器)

有效负载格式

UCAN_COMMAND_GET

主机到设备;强制

从设备获取信息

子命令
UCAN_COMMAND_GET_INFO

请求设备信息结构 ucan_ctl_payload_t.device_info

有关详细信息,请参阅 device_info 字段,有关 can_bittiming fields 的说明,请参阅 uapi/linux/can/netlink.h

有效负载格式

ucan_ctl_payload_t.device_info

UCAN_COMMAND_GET_PROTOCOL_VERSION

请求设备协议版本 ucan_ctl_payload_t.protocol_version。当前协议版本为 3。

有效负载格式

ucan_ctl_payload_t.protocol_version

注意

不实现此命令的设备使用旧协议版本 1

UCAN_COMMAND_SET_BITTIMING

主机到设备;强制

通过发送结构 ucan_ctl_payload_t.cmd_set_bittiming 设置位定时 (详情请参阅 struct bittiming)

有效负载格式

ucan_ctl_payload_t.cmd_set_bittiming.

UCAN_SLEEP/WAKE

主机到设备;可选

配置睡眠和唤醒模式。驱动程序尚未支持。

UCAN_FILTER

主机到设备;可选

设置硬件 CAN 过滤器。驱动程序尚未支持。

允许的接口命令

合法设备状态

命令

新设备状态

停止

SET_BITTIMING

停止

停止

START

已启动

已启动

STOP 或 RESET

停止

停止

STOP 或 RESET

停止

已启动

RESTART

已启动

任何

GET

无变化

IN 消息格式

USB IN 端点上的数据包包含一个或多个 ucan_message_in 值。如果多个消息在 USB 数据包中批量处理,则可以使用 len 字段跳转到下一个 ucan_message_in 值(请注意根据实际数据大小对 len 值进行健全性检查)。

len 字段

每个 ucan_message_in 都必须与 4 字节边界对齐 (相对于数据缓冲区的起始位置)。这意味着多个 ucan_message_in 值之间可能存在填充字节

+----------------------------+ < 0
|                            |
|   struct ucan_message_in   |
|                            |
+----------------------------+ < len
          [padding]
+----------------------------+ < round_up(len, 4)
|                            |
|   struct ucan_message_in   |
|                            |
+----------------------------+
            [...]

type 字段

type 字段指定消息的类型。

UCAN_IN_RX

subtype

从 CAN 总线接收的数据 (ID + 有效负载)。

UCAN_IN_TX_COMPLETE

subtype

CAN 设备已向 CAN 总线发送消息。它返回一个 <echo-ids, flags> 元组列表。

echo-id 从 (echo 来自先前 UCAN_OUT_TX 消息的 id) 识别帧。该标志指示传输的结果。其中,设置的位 0 表示成功。所有其他位都保留并设置为零。

流控制

接收 CAN 消息时,USB 缓冲区上没有流控制。驱动程序必须足够快地处理入站消息,以避免丢弃。如果设备缓冲区溢出,则会发送相应的错误帧报告此情况 (请参阅 CAN 错误处理)

OUT 消息格式

USB OUT 端点上的数据包包含一个或多个 struct ucan_message_out 值。如果将多个消息批量处理到一个数据包中,则设备使用 len 字段跳转到下一个 ucan_message_out 值。每个 ucan_message_out 都必须与 4 个字节对齐 (相对于数据缓冲区的起始位置)。该机制与 len 字段 中描述的相同。

+----------------------------+ < 0
|                            |
|   struct ucan_message_out  |
|                            |
+----------------------------+ < len
          [padding]
+----------------------------+ < round_up(len, 4)
|                            |
|   struct ucan_message_out  |
|                            |
+----------------------------+
            [...]

type 字段

在协议版本 3 中,仅定义了 UCAN_OUT_TX,其他仅由旧设备 (协议版本 1) 使用。

UCAN_OUT_TX

subtype

要在 CAN_IN_TX_COMPLETE 消息中回复的 echo id

发送 CAN 帧。(参数:id, data)

流控制

当设备出站缓冲区已满时,它会在 OUT 管道上开始发送 NAK,直到有更多缓冲区可用。当不完整的 OUT 数据包达到某个阈值时,驱动程序会停止队列。

CAN 错误处理

如果启用了错误报告,则设备会将错误编码到 CAN 错误帧中(请参阅 uapi/linux/can/error.h),并使用 IN 端点发送。驱动程序会更新其错误统计信息并将其转发。

尽管 UCAN 设备可以完全禁止错误帧,但在 Linux 中,驱动程序始终对其感兴趣。因此,设备始终以设置的 UCAN_MODE_BERR_REPORT 启动。驱动程序会为用户空间过滤这些消息。

总线关闭

  • 设备不会自动从总线关闭中恢复。

  • 总线关闭通过错误帧指示 (请参阅 uapi/linux/can/error.h)

  • 总线关闭恢复由 UCAN_COMMAND_RESTART 启动

  • 总线关闭恢复完成后,设备会发送一个错误帧,指示它处于 ERROR-ACTIVE 状态。

  • 在总线关闭期间,设备不发送任何帧。

  • 在总线关闭期间,来自主机的传输请求会立即完成,并且未设置成功位。

示例对话

  1. 设备已连接到 USB

  2. 主机发送命令 UCAN_COMMAND_RESET,子命令 0

  3. 主机发送命令 UCAN_COMMAND_GET,子命令 UCAN_COMMAND_GET_INFO

  4. 设备发送 UCAN_IN_DEVICE_INFO

  5. 主机发送命令 UCAN_OUT_SET_BITTIMING

  6. 主机发送命令 UCAN_COMMAND_START,子命令 0,模式 UCAN_MODE_BERR_REPORT