Skip to main content
读取您的固件通过 SEGGER RTT 打印的内容。启用 rtt feature 之后,您还可以往它的下行通道写入,于是一个 cargo test 就能驱动一个交互式控制台。 有两条路径,它们的行为并不相同。

交互式会话

启用该 feature

rtt feature 隐含启用 blocking。要使用 AsyncRttSession,请同时启用 rtt 和 async。AsyncDebugNet::rtt_interactive() 和 rtt_interactive_with() 会打开它,它的方法与 RttSession 相同,其中 read、wait_for、write 和 stop 需要 .await。

打开一个会话

gdbserver 必须已经在运行。 没有先连接就调用 rtt_interactive() 会以 Error::Stream 失败,信息是 No debugger connection found for net 'debug1'. Start one first。

RttOptions

channel 同时决定两个方向上的通道。chunk_size 只对交互式会话有效;单向的 HTTP 流会忽略它。timeout 只对单向流有效。

方法

方法参考

read(timeout: Duration) -> Result<Vec<u8>>

在 timeout 时间内到达的上行通道字节,有多少给多少。
目标空闲时,read() 会把整个超时时间等满。在轮询循环里请改用 try_read(),否则每一轮迭代都要花掉整个超时时长。

try_read() -> Result<Vec<u8>>

已经收到的字节,不等待。没有缓冲内容时返回空 vector。

wait_for(needle: &[u8], timeout: Duration) -> Result<Vec<u8>>

不断累积输出,直到出现 needle。 返回: 直到该标记为止、并且包含该标记的全部内容。标记之后的字节会继续留在缓冲区里,供下一次读取。空标记会立即返回;没找到则是 Error::Timeout。

write(data: &[u8]) -> Result<()> 和 write_str(s: &str) -> Result<()>

写入目标的 RTT 下行通道。
写入要求固件在该通道上声明了下行缓冲区。仅有 defmt-rtt 只提供上行缓冲区,而在没有下行缓冲区时,目标会静默丢弃您写入的内容 —— 该调用仍然返回 Ok(())。这是目标侧的事实,而不是传输失败,所以该 crate 没有错误可以报告。

stop() -> Result<()>

干净地停止。它会消耗掉该会话。把会话 drop 掉同样会停止它,但 stop() 会把错误暴露出来,而不是吞掉。

单向流

debug.rtt() 和 debug.rtt_with(&RttOptions) 返回一个 RttStream,它实现了 std::io::Read。它不需要任何 cargo feature,也不需要 Socket.IO,并且只产出目标的 RTT 输出。 在 AsyncDebugNet 上,这两个方法返回一个 AsyncRttStream,它实现了 tokio::io::AsyncRead。

示例

驱动固件控制台并对回复做断言

在目标空闲时收集启动输出而不被阻塞

说明

  • Box 的 RTT telnet 端口只接受一个客户端。 在同一个探针和同一个通道上开第二个会话,会被以 Error::Stream 和 RTT port 9090 is already in use by another session 拒绝。同一个探针上的两个不同通道属于不同端口,可以同时运行。
  • 字节是原始的。defmt 输出是压缩的二进制,必须经 defmt-print -e <elf> 管道处理;wait_for 只在纯文本控制台上才帮得上忙。
  • 连接确认的超时是 30 秒,比 UART 的 15 秒更宽。多出来的时间用于在 RAM 中搜索 RTT 控制块,以及在 gdbserver 稳定下来的过程中重试 telnet 挂接。
  • 会话会在 Socket.IO 握手时带上网关 bearer 令牌,因此受网关保护的 Box 无需额外配置即可使用。
  • 需要 Box 软件 0.35.0 或更高版本。更旧的 Box 会给出 Error::UnsupportedByBox。