Skip to main content

nucleus_trace/
lib.rs

1//! The Nucleus trace backend.
2//!
3//! Wires the [`nucleus_itm`] decoder to a WebSocket fan-out so editor/browser
4//! dashboards can subscribe to live, structured trace events:
5//!
6//! ```text
7//! OpenOCD (SWO) ──▶ source ──▶ Decoder ──▶ Translator ──▶ JSON ──▶ WebSocket :7878
8//! ```
9//!
10//! [`translate`] assigns meaning (port 0 = logs, ports 1–7 = typed variables),
11//! [`server`] owns the pipeline and client fan-out, and [`source`] supplies the
12//! bytes (OpenOCD TCP trace port or a captured-file replay). [`run_blocking`] is
13//! the synchronous entry point the CLI calls.
14
15pub mod server;
16pub mod source;
17pub mod translate;
18
19pub use server::TraceServer;
20pub use source::Source;
21pub use translate::{TraceEvent, Translator, VarType, VariableMap};
22
23/// The default WebSocket port (per the README/architecture).
24pub const DEFAULT_WS_PORT: u16 = 7878;
25
26/// Options for [`run_blocking`].
27pub struct TraceOptions {
28    /// Address to bind the WebSocket server on, e.g. `127.0.0.1:7878`.
29    pub ws_addr: String,
30    /// Where SWO bytes come from.
31    pub source: Source,
32    /// Optional OpenOCD telnet setup: `(telnet_addr, trace_port, cpu_hz, swo_hz)`.
33    pub openocd: Option<(String, u16, u32, u32)>,
34    /// Port → variable map from `[[trace.variables]]`.
35    pub variables: VariableMap,
36}
37
38/// Run the trace daemon to completion (until the source ends), blocking on a
39/// fresh Tokio runtime so the caller stays synchronous.
40pub fn run_blocking(opts: TraceOptions) -> std::io::Result<()> {
41    let runtime = tokio::runtime::Builder::new_multi_thread()
42        .enable_all()
43        .build()?;
44    runtime.block_on(async move {
45        let server = TraceServer::new(opts.variables);
46        let (addr, _accept) = server.serve_ws(&opts.ws_addr).await?;
47        eprintln!("nucleus trace: streaming events on ws://{addr}");
48
49        if let Some((telnet, port, cpu, swo)) = &opts.openocd {
50            if let Err(err) = source::openocd_enable(telnet, *port, *cpu, *swo).await {
51                eprintln!("nucleus trace: warning: OpenOCD setup failed ({err}); continuing");
52            }
53        }
54
55        let reader = opts.source.open().await?;
56        eprintln!("nucleus trace: reading SWO from source…");
57        server.run_source(reader).await?;
58        eprintln!("nucleus trace: source ended");
59        Ok(())
60    })
61}