Serial/JTAG USB CLI

[English]

brookesia-usb 通过单一串行传输控制 ESP-Brookesia USB service:USB Serial/JTAG 提供的 CDC-ACM 通道,或 UART(通常为板载 USB 转串口桥)。协议版本为 1。

安装

USB CLI 需要 Python 3.9 或更高版本,可从 PyPI 在线安装:

python -m pip install brookesia-usb

安装命令会自动安装 pyserial 依赖。安装完成后可以查看版本和命令帮助:

brookesia-usb --version
brookesia-usb --help

Toolkit 中的 brookesia deploy 会调用本 CLI 安装已构建的 .bpk。

设备和端口

CLI 会自动选择端口并通过 hello 命令验证设备:优先 USB Serial/JTAG,当不存在 Serial/JTAG 端口时回退到 USB 转 UART 桥:

brookesia-usb devices
brookesia-usb status
brookesia-usb --port /dev/ttyACM0 status
brookesia-usb --port /dev/ttyUSB0 --baudrate 921600 status

发现顺序:

  1. 枚举串口。

  2. 若存在**恰好一个** USB Serial/JTAG 候选(Espressif VID/PID 或端口描述匹配),直接使用该端口,不在发现阶段探测;hello 在命令执行时只做一次。

  3. 若存在**多个** USB Serial/JTAG 候选,逐个用 hello 探测,直到有一个回报 serial_jtag 传输。

  4. 若无 USB Serial/JTAG 候选,或其候选全部探测失败,则探测 USB 转 UART 候选(/dev/ttyUSB* 及非 Serial/JTAG 的 ACM 端口),接受 serial_jtag 或 uart 传输。

若只存在一个 USB Serial/JTAG 端口但它并非目标设备(例如 USJ 线缆和 USB 转 UART 桥同时插着),CLI 会选中它并报错;请用 --port 显式指定实际设备所在的端口。

也可以显式指定常用连接参数:

brookesia-usb --port /dev/ttyACM0 --baudrate 115200 --timeout 10 status
brookesia-usb --port /dev/ttyUSB0 --baudrate 921600 --timeout 10 status
  • --port:Serial/JTAG 设备路径(/dev/ttyACM*)或 USB 转 UART 设备路径(/dev/ttyUSB*);省略时自动发现。

  • --baudrate:USB Serial/JTAG 不使用物理波特率,该参数被忽略;UART 传输时必须与设备控制台波特率一致(例如 CONFIG_ESP_CONSOLE_UART_BAUDRATE),默认值为 115200。

  • --timeout:每次读写的超时时间,单位为秒,默认值为 10。

如果存在多个匹配设备,请使用 devices 输出的路径显式指定 --port。单个 Serial/JTAG CDC 配置通常只提供 /dev/ttyACM0,不存在 /dev/ttyACM1 并不表示设备异常。

只引出 USB 转 UART 桥的板子,控制传输与控制台日志共用同一端口。设备会时分复用该端口:空闲时输出控制台日志,控制会话期间日志被抑制。这要求设备固件选择 UART 传输;引出 USB Serial/JTAG 的板子默认仍使用 Serial/JTAG。

控制会话和安全

需要控制会话的命令会发送 hello,检查协议版本 1、设备回报的传输类型(serial_jtag 或 uart)和 exclusive 会话状态,并在退出时发送 goodbye。

设备日志会在控制会话期间被抑制,避免干扰 JSON 响应和文件帧。USB Serial/JTAG 的 CDC 通道同时用于刷写、JTAG 调试和控制台日志;UART 传输则与控制台输出共用端口。请在执行命令前关闭 idf.py monitor、minicom 或其他读取同一串口的程序。

在 UART 传输下,没有 USB Serial/JTAG 的设备会用同一端口完成固件下载、控制台日志和控制会话,但三者不同时进行:刷写运行在应用启动前的 ROM 下载模式,控制会话活动期间日志输出被抑制。

USB 连接属于受信任的物理控制边界,但仍会执行协议、路径、大小、校验和服务参数验证。

查询状态

查询 USB service、传输状态和控制会话状态:

brookesia-usb status
brookesia-usb --port /dev/ttyACM0 status

设备未连接或 USB service 未启动时,命令会输出错误并返回非零状态。

调用服务函数

call 命令调用设备上已注册的 Brookesia service 函数。参数必须是 JSON object,参数名称和类型必须符合服务 schema:

brookesia-usb call Manager GetServiceNames '{}'
brookesia-usb call Manager GetServiceSchema '{"Name":"Storage"}'
brookesia-usb call SystemCore GetSystemInfo '{}'
brookesia-usb call Storage FSStat '{"Path":"/littlefs"}'
brookesia-usb call Storage FSList '{"Path":"/littlefs"}'

可以先通过 Manager.GetServiceNames 和 Manager.GetServiceSchema 查询可调用的 service 与函数。ServiceManager 会在设备侧校验必选参数、默认值、未知参数和参数类型。

需要 RawBuffer 参数的函数不能通过 JSON 接口调用,因为主机指针无法直接用于设备内存。文件和软件包数据应分别使用 put 和 install 命令。为避免递归调用,不能通过该接口调用 Usb service 自身。

上传文件

将本地文件上传到设备配置的上传根目录下。默认上传根目录为 /littlefs/usb,远程路径必须是相对路径:

brookesia-usb put ./logs/session.bin logs/session.bin
brookesia-usb put ./config/device.json config/device.json --overwrite

默认不会覆盖已有文件,只有显式指定 --overwrite 才会替换目标文件。绝对路径、包含 .. 的路径、符号链接逃逸和上传根目录之外的路径都会被拒绝。

CLI 会计算文件大小和 SHA-256 摘要,通过 CRC 保护的二进制帧传输文件,并在每个数据帧后等待设备确认。默认单帧 payload 不超过 16 KiB,默认单次传输最大为 8 MiB;具体限制由设备 Kconfig 配置决定。

设备会先将数据写入临时文件,只有在大小和 SHA-256 校验成功后,才会提交到目标路径。传输过程中断时,临时文件会被清理。

安装 BPK 应用

将完整的 BPK 运行时应用包发送到设备并安装:

brookesia-usb install ./build/my_app.bpk

软件包会先写入 USB 临时目录,再由 System Core 执行 manifest 校验、ZIP 路径安全检查、暂存、替换和回滚流程。主机不能直接选择设备上的应用安装目录。

如果连接中断或返回结果不明确,CLI 不会自动重试安装。重新执行前请先使用 brookesia-usb status 检查设备状态。

终止传输

根据 request ID 终止活动传输:

brookesia-usb abort 42

abort 是紧急命令,不会建立新的控制会话。request 42 正在活动时,设备会删除临时文件并返回 aborted;未知 request ID 会返回设备错误并以非零状态退出。

错误和故障排查

命令成功时返回 0,传输、协议、参数校验或设备错误时返回 1。常见错误码包括:

  • invalid_command:JSON 格式错误或操作不支持。

  • busy:已有控制会话或传输正在进行。

  • bad_frame:帧 CRC、类型或序列错误。

  • size_mismatch / hash_mismatch:声明的文件元数据与实际数据不一致。

  • path_denied:路径不安全或未显式允许覆盖。

  • storage_full:无法创建或写入临时存储。

  • install_failed:System Core 拒绝或未能安装软件包。

  • timeout / aborted:超时或传输被取消。

如果找不到设备,请先检查 USB 数据线和系统设备列表:

ls /dev/ttyACM* /dev/ttyUSB*
brookesia-usb devices

确认没有其他程序占用同一串口后,再使用 --port 显式指定设备路径。

UART 传输的额外检查:

  • hello 超时或返回无效数据:--baudrate 与设备控制台波特率不一致。对齐后重试。

  • 端口被占用:关闭 idf.py monitor、minicom 或其他读取同一端口的程序。控制会话与控制台不能同时读取 UART。

  • 固件下载与 BPK 安装天然分时:刷写使用 ROM 下载模式(应用未运行),因此不会冲突。