UCAN 协议

UCAN 是基于微控制器的 USB-CAN 适配器使用的协议,该适配器集成在 Theobroma Systems 的片上系统模块上,并且也可以作为独立的 USB 棒使用。

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

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

USB 端点

UCAN 设备使用三个 USB 端点

CONTROL 端点

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

IN 端点

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

OUT 端点

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

CONTROL 消息

UCAN 设备使用控制管道上的 vendor request 进行配置。

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

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

Setup Packet

bmRequestType

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

bRequest

命令编号

wValue

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

wIndex

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

wLength

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

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

错误处理

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

设备命令

UCAN_DEVICE_GET_FW_STRING

Dev2Host;可选

请求设备固件字符串。

接口命令

UCAN_COMMAND_START

Host2Dev;强制

启动 CAN 接口。

Payload 格式

ucan_ctl_payload_t.cmd_start

mode

UCAN_MODE_* 的掩码

UCAN_COMMAND_STOP

Host2Dev;强制

停止 CAN 接口

Payload 格式

UCAN_COMMAND_RESET

Host2Dev;强制

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

Payload 格式

UCAN_COMMAND_GET

Host2Dev;强制

从设备获取信息

子命令
UCAN_COMMAND_GET_INFO

请求设备信息结构 ucan_ctl_payload_t.device_info

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

Payload 格式

ucan_ctl_payload_t.device_info

UCAN_COMMAND_GET_PROTOCOL_VERSION

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

Payload 格式

ucan_ctl_payload_t.protocol_version

注意

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

UCAN_COMMAND_SET_BITTIMING

Host2Dev;强制

通过发送结构 ucan_ctl_payload_t.cmd_set_bittiming 设置 bittiming (有关详细信息,请参见 struct bittiming)

Payload 格式

ucan_ctl_payload_t.cmd_set_bittiming.

UCAN_SLEEP/WAKE

Host2Dev;可选

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

UCAN_FILTER

Host2Dev;可选

设置硬件 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 + payload)。

UCAN_IN_TX_COMPLETE

subtype

CAN 设备已将消息发送到 CAN 总线。 它使用元组 <echo-ids, flags> 的列表进行回复。

echo-id 从 (从先前的 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 启动。 为用户空间过滤这些消息由驱动程序完成。

总线 OFF

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

  • 总线 OFF 由错误帧指示 (请参见 uapi/linux/can/error.h)

  • 总线 OFF 恢复由 UCAN_COMMAND_RESTART 启动

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

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

  • 在总线 OFF 期间,来自主机的传输请求会立即完成,而成功位保持未设置状态。

示例对话

  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