Stream firmware log output, and drive an RTT console from a test
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.
[dev-dependencies]lager = { package = "lager-net", version = "0.9", features = ["rtt"] }
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.
use lager::{LagerBox, RttOptions};use std::time::Duration;let lager = LagerBox::from_env()?;let dbg = lager.debug("debug1");dbg.connect()?; // required first, see belowlet mut rtt = dbg.rtt_interactive()?;
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.
pub struct RttOptions { pub channel: u32, // default 0 pub search_addr: Option<u64>, // RAM start for the control-block search pub search_size: Option<u64>, // size of the RAM region to search pub chunk_size: Option<u64>, // box-side read chunk, J-Link only pub timeout: Option<f64>, // close the one-way stream after this many seconds}
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.
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.
let banner = rtt.wait_for(b"boot complete", Duration::from_secs(10))?;
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.
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.
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.