Skip to main content
Read what your firmware prints over SEGGER RTT. With the rtt feature you can also write back into its down-channel, so a cargo test can drive an interactive console. There are two paths, and they behave differently.

Interactive sessions

Enabling the feature

The rtt feature implies blocking. For AsyncRttSession, enable rtt and async together. AsyncDebugNet::rtt_interactive() and rtt_interactive_with() open it, and its methods match RttSession, with read, wait_for, write and stop awaited.

Opening a session

The gdbserver must already be running. Calling rtt_interactive() without connecting first fails with Error::Stream and the message No debugger connection found for net 'debug1'. Start one first.

RttOptions

channel selects the channel in both directions. chunk_size applies only to interactive sessions; the one-way HTTP stream ignores it. timeout applies only to the one-way stream.

Methods

Method Reference

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

Whatever up-channel bytes arrive within timeout.
read() waits out the full timeout when the target is idle. In a poll loop use try_read() instead, or every iteration costs the whole timeout.

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

Bytes already received, without waiting. Returns an empty vector when nothing is buffered.

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

Accumulate output until needle appears. Returns: everything up to and including the needle. Bytes after it stay buffered for the next read. An empty needle returns immediately; a miss is Error::Timeout.

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

Write into the target’s RTT down-channel.
Writing needs a firmware-declared down buffer on that channel. defmt-rtt alone provides only the up buffer, and without a down buffer the target silently discards what you write — the call still returns Ok(()). That is a target-side fact, not a transport failure, so the crate has no error to report.

stop() -> Result<()>

Stop cleanly. Consumes the session. Dropping it also stops the session, but stop() surfaces errors rather than swallowing them.

The one-way stream

debug.rtt() and debug.rtt_with(&RttOptions) return an RttStream, which implements std::io::Read. It needs no cargo feature and no Socket.IO, and it yields only the target’s RTT output. On AsyncDebugNet, the same two methods return an AsyncRttStream, which implements tokio::io::AsyncRead.

Examples

Drive a firmware console and assert on the reply

Collect boot output without blocking on an idle target

Notes

  • The box’s RTT telnet port takes a single client. A second session on the same probe and channel is refused with Error::Stream and RTT port 9090 is already in use by another session. Two different channels on one probe are separate ports and can run at once.
  • Bytes are raw. defmt output is compressed binary and must be piped through defmt-print -e <elf>; wait_for only helps against a plain-text console.
  • The connect confirmation timeout is 30 seconds, wider than UART’s 15. The extra time covers a search of RAM for the RTT control block, and a retry of the telnet attach while the gdbserver settles.
  • Sessions carry the gateway bearer token on the Socket.IO handshake, so a gated box works with no extra setup.
  • Requires box software 0.35.0 or newer. An older box gives Error::UnsupportedByBox.