Skip to main content
从一个 cargo test 里驱动调试探针:连接、烧录固件、复位或暂停目标,并读取它的内存。 调试 Net 是唯一不与 Box 的 9000 端口 API 通信的 Net 类型。它们联系的是 Box 上运行在 8765 端口的调试服务。

句柄

该 Net 保存的记录会在首次使用时取一次,并缓存在句柄上。只要有操作失败,缓存就会被丢弃,因此重新保存过的 Net 会在下一次尝试时被读到,而不需要新建句柄。

方法

RTT 流式传输在同一个句柄上,相关内容见 RTT。

类型

ConnectOptions

Default 把 gdb 设为 true,其余全部关闭,因此 connect() 会启动一个 GDB 服务器。请用 ..Default::default() 构造该结构体,这样以后新增字段时不会破坏您的代码。不带它的结构体字面量从 lager-net 0.10 起无法编译,因为该版本新增了 transport。 transport: Some(Transport::Jtag) 让探针以 JTAG 启动。它需要Box 软件 0.62.0 或更高版本。crate 会先检查调试服务的功能列表中是否有 connect_transport。较旧的 Box 会以 Error::UnsupportedByBox 失败,因为它无论请求如何都会以 SWD 启动。带有自己 OpenOCD 配置的 Net 会沿用该配置的传输方式。 jlink_script 和 openocd_config 会替换保存在 Net 上的脚本,只对本次连接生效。OpenOCD 配置必须是完整的,并且必须选定适配器驱动。

FirmwareKind

FlashOptions

请传入您连接时使用的脚本。没有它时,Box 会使用 Net 保存的脚本;如果也没有,则使用一个临时文件,其中保存的是最近一次连接的 J-Link Net 的脚本。

EraseOptions

FlashReport 和 EraseReport

flash() 及其变体返回一个 FlashReport: erase() 和 erase_range() 返回一个 EraseReport: EraseRange 携带 start、end(含)、length、text 和 source。source 为 "request"、"script" 或 "default"。

方法参考

connect() -> Result<DebugConnection>

用 ConnectOptions::default() 连接。
返回: DebugConnection,携带设备、探针、序列号、后端,以及一个带有已打开端口的 GdbServer。它的 transport 为 "SWD" 或 "JTAG";来自 0.62.0 之前 Box 的结果为 None,这类 Box 总是运行 SWD。在 J-Link 上返回的是 gdb 2331、SWO 2332、telnet 2333 和 RTT telnet 9090。tcl_port 仅 OpenOCD 才有,在 J-Link 上为 None;同理 swo_port 仅 J-Link 才有。

connect_with(opts: &ConnectOptions) -> Result<DebugConnection>

用显式选项连接。
以 JTAG 连接:
halt: true 会先复位目标,再暂停它。在从 QSPI 原地执行(XIP)的器件上,这次复位会再次运行引导程序。要在不复位的情况下让内核停下,请使用 halt()。

disconnect(keep_running: bool) -> Result<()>

断开连接。传 true 会让 gdbserver 继续运行,供外部 GDB 客户端挂接;传 false 则把它拆掉。

reset(halt: bool) -> Result<DebugOutput>

复位目标。halt: true 会让它停在复位向量处。 返回: 一个 DebugOutput,包含探针的 output 行和 backend。

halt() -> Result<DebugOutput>

让内核停在当前位置。halt() 发送 OpenOCD 的裸 halt 命令,因此不会触碰 nRESET。在从 QSPI 原地执行(XIP)的器件上使用它,因为在这类器件上复位会再次运行引导程序。 halt() 需要 Box 软件 0.60.0 或更高版本,以及一个 OpenOCD Net:
  • crate 会先读取调试服务的功能列表。不支持 halt 的 Box 会以 Error::UnsupportedByBox 失败,并且不会有任何操作到达探针。
  • J-Link Net 会以 Error::Box 和 HTTP 400 失败。J-Link 没有原地暂停的原语,因此请改用一个先暂停的 .JLinkScript 来连接。
  • 没有运行中调试器的 Net 会以 Error::Box 和 No debugger connection found 失败。

erase() -> Result<EraseReport>

擦除目标的 Flash:整片擦除,或者在 Box 为该器件系列定义了默认范围的器件上(DA1469x、nRF5340)擦除该默认范围。报告会说明 Box 擦除了哪个范围。
在 J-Link 探针上,或者在 DA1469x 目标上,erase() 会断开调试器连接。 随后的 read_memory() 会以 Error::Box 和 No debugger connection found 失败。flash 会自行重新建立连接,因此”先擦除再烧录”的序列可以正常工作,但”先擦除再读取”不行 —— 请先再调用一次 connect()。在 OpenOCD 探针上配合其他任何目标时,OpenOCD 守护进程在擦除之后仍然在运行。

erase_range(start: u64, size: u64) -> Result<EraseReport>

从 start 开始,只擦除 size 个字节的 Flash。
erase_range() 需要 Box 软件 0.50.0 或更高版本。较旧的 Box 会忽略该范围并整片擦除。因此 crate 会先读取调试服务的功能列表,并在擦除任何内容之前以 Error::UnsupportedByBox 失败。对于超出该器件可擦除范围的请求,Box 会以 HTTP 400 拒绝。

flash(firmware_path) -> Result<FlashReport>

烧录一个文件,按扩展名推断类型:.hex、.elf 或 .bin。无法识别的扩展名会得到 Error::Config。 什么也没有写入的烧录会以 Error::FlashFailed 失败,该错误携带 Box 的判定行和后端的输出。Box 软件 0.51.0 及更高版本会报告这一点。较旧的 Box 不报告判定,programmed 为 None。
.bin 会被烧录到 0x08000000,也就是 STM32 的应用基地址。在其他任何系列上这个地址都是错的,而该调用仍然返回 Ok。这一点在 nRF5340 上验证过:flash() 烧录 .bin 报告成功,而 0x0 处的 Flash 仍然是擦除状态。这是一个静默的错误结果,而不是一个错误。在非 STM32 目标上,请用 flash_bin() 并给出正确的基地址。

flash_bin(firmware_path, address: u32) -> Result<FlashReport>

在显式的基地址上烧录原始二进制文件。对于应用不是从 0x08000000 开始的任何目标,这都是正确的调用。

flash_bytes(contents: &[u8], kind: FirmwareKind, address: Option<u32>) -> Result<FlashReport>

烧录您手上已有的字节,不必先把它们写成文件。address 只对 FirmwareKind::Bin 有用,默认是 0x08000000。

read_memory(address: u64, length: usize) -> Result<Vec<u8>>

从目标的 address 处开始读取 length 个字节。
需要有存活的连接:没有连接时它会以 Error::Box 和 No debugger connection found 失败。在使用 DA1469x 目标的 J-Link Net 上,Box 会在读取之前先复位并暂停目标。其他目标以及 OpenOCD Net 读取时不会复位。

read_memory_no_reset(address: u64, length: usize) -> Result<Vec<u8>>

读取目标内存,但不做 read_memory() 在 J-Link DA1469x 目标上事先进行的复位和暂停。正在运行的目标会继续运行。早于这个选项的 Box 会忽略它,并按 read_memory() 的方式读取。

info()、status()、info_probed() 和 status_probed()

info() 报告设备、架构、探针、序列号和后端,以及连接是否存活。status() 报告 gdbserver:是否有一个处于活动状态、它的 pid,以及探针序列号。两者都不需要先连接。
从 Box 软件 0.44.0 起,两者都携带两个字段。较旧的 Box 会把它们留为 None。 在 info() 和 status() 的结果中,除非 Box 已经知道挂接失败,否则 target_attached 为 None。info_probed() 和 status_probed() 会读取目标来确定它,大约要多花一秒。

示例

烧录并校验

让运行中的目标停下并检查它

为交互式会话保留一个 gdbserver

受支持的硬件

说明

  • 超时预算按操作区分,与 CLI 一致:
    • connect 30 秒
    • flash 180 秒
    • erase 120 秒
    • 内存读取 30 秒
    • reset、halt、info、status 和 disconnect 为 10 秒
  • Net 解析要求 debug 角色。存在但角色不同的 Net 会给出 net 'adc1' exists but is not a debug net。不存在的名称会给出 debug net 'nosuch' not found on this box。
  • 调试服务不使用 9000 端口 API 的那套成功信封格式。200 表示成功;其他任何状态码都是错误,并携带该服务给出的信息。
  • 另一个操作占用探针的时间可能超过 Box 的等待时长。这时 Box 会应答 HTTP 503,crate 返回 Error::ProbeBusy。请等另一个操作完成后重试。
  • 配置了 allow_destructive: false 的 Net 会以 HTTP 403 拒绝 erase() 和 flash(),crate 将其返回为 Error::SafetyRefused。请参阅 客户端与 Box。
  • Box 级调用 debug_service_health()、debug_service_health_detailed() 和 debug_service_status() 读取调试服务的版本和功能、运行状态和警告,以及它跟踪的每个连接。
  • 对于类型化 API 没有覆盖的寄存器访问、内存写入和其他 GDB 数据包,请使用 debug_tunnel()。crate 的 debug_tunnel 示例演示了做法。
  • 异步方面的说明:AsyncDebugNet 提供这里的全部功能,包括 RTT。