Serial/JTAG USB CLI
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
发现顺序:
枚举串口。
若存在**恰好一个** USB Serial/JTAG 候选(Espressif VID/PID 或端口描述匹配),直接使用该端口,不在发现阶段探测;
hello在命令执行时只做一次。若存在**多个** USB Serial/JTAG 候选,逐个用
hello探测,直到有一个回报serial_jtag传输。若无 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 下载模式(应用未运行),因此不会冲突。