# RMon UI Specification ## Technology - **Framework**: `egui` + `eframe` (immediate-mode Rust GUI) - **Render backend**: `glow` (OpenGL 2.1+) — chosen for maximum Linux compatibility - **Plotting**: `egui_plot` for interactive panels; custom `egui` painter (line strip primitives) for high-throughput paths (>100k points/frame) - **Async runtime**: `tokio` (runs in a background thread; communicates with egui via `std::sync::mpsc`) - **SSH tunnel management**: spawns system `ssh` subprocess ## Deployment Single binary. On Linux, dynamically links only: - `libGL` (OpenGL driver, always present on any desktop Linux) - `libX11` / `libxcb` (X11, or Wayland via `libwayland-client` with `wayland` feature) - `libc` (glibc, standard on all Linux distributions) On Windows: fully static (links Win32 APIs and ANGLE for OpenGL ES via DirectX). Pre-built agent binaries for all supported architectures are **embedded in the UI binary** at compile time using `include_bytes!`. This allows the UI to deploy the agent without any extra files. ## Layout ``` ┌─────────────────────────────────────────────────────────────────────┐ │ [Connect ▼] [host: myserver] [⏺ Record] [⏹ Stop] [Status: OK] │ ← Toolbar ├────────────────┬────────────────────────────────────────────────────┤ │ Signal Tree │ Plot Panel 1 │ Plot Panel 2 │ │ │ │ │ │ ▼ imu │ [signal A] [signal B] [✕] │ [signal C] [✕] │ │ ▼ accel │ ┌──────────────────────────┐ │ ┌─────────────┐ │ │ accel_x ══╪═►│ time-series plot │ │ │ │ │ │ accel_y │ │ │ │ │ │ │ │ accel_z │ │ ╭─╮ ╭──╮ │ │ │ │ │ │ ▼ gyro │ │ ╯ ╰──╯ ╰─ │ │ │ │ │ │ gyro_x │ │ │ │ └─────────────┘ │ │ gyro_y │ │ ┼────────────────────── │ │ │ │ ▼ temps │ └──────────────────────────┘ │ [+ Add Plot] │ │ inlet │ [cursor A: t=12.3s val=1.2] │ │ │ outlet │ [cursor B: t=15.1s Δt=2.8s] │ │ │ │ [A-B: Δval=-0.3 mean=1.05] │ │ └───────────────┴────────────────────────────────┴───────────────────┘ ``` ## Connection Dialog Shown on startup (or via toolbar "Connect" button) when not connected. Fields: - **SSH Host**: free text, matched against `~/.ssh/config` Host entries (autocomplete offered) - **Agent Port**: numeric, default `7891` - **Agent Config**: path on remote machine, default `~/.rmon/config.toml` On connect: 1. Detect remote arch via `ssh {host} uname -m` 2. Check / upload agent binary (see `docs/architecture.md` connection flow) 3. Start agent if not running 4. Establish port forward 5. Perform protocol handshake 6. Fetch signal list → populate signal tree Connection errors are shown inline with a retry button. ## Signal Tree Panel - Collapsible tree mirroring the `path` field of each `SignalInfo` - Each leaf shows: label, unit, last value (live-updated), colored dot (source status) - **Drag-and-drop**: drag a signal leaf onto a plot panel to add it - **Right-click menu**: "Add to plot 1 / 2 / new plot", "Signal info" (opens info popup), "Start recording", "Stop recording" - **Search/filter bar** at the top of the panel - Recording state shown with red ⏺ icon on the signal leaf ## Plot Panels Any number of plot panels can be open (horizontally tiled by default, resizable/detachable). ### Axes - X axis: time (absolute UTC or relative to a reference point; toggled in toolbar) - Y axis: auto-range by default; can be locked manually - Zoom: scroll wheel (time axis), Ctrl+scroll (Y axis) - Pan: click-drag on the plot ### Signals in a Plot - Each signal rendered as a colored line - Legend at top of plot (click to hide/show individual signals) - Color is auto-assigned, can be changed via right-click on the legend entry - Line style (solid/dashed/dotted) and width configurable per signal ### Cursors - Add cursors via toolbar button or right-click on plot → "Add cursor" - Drag to position; snaps to nearest sample if within threshold - Measurement bar below the plot shows: - Per cursor: timestamp, value for each visible signal - Between two cursors: Δt, Δvalue, mean, min, max over the interval ### Math Signals - Right-click plot → "Add math signal" - Expression editor (simple formula: `a + b`, `a * 2.0`, `a - b`, etc. where `a`, `b` are signal IDs) - Math signals appear in the legend with an `f(x)` icon and can be added to other plots ### High-Throughput Rendering When a signal has more points than pixels in the X direction, the renderer decimates using **min-max downsampling** (preserves peaks/troughs visually). This runs on the CPU in `plot_panel.rs` before passing vertices to egui's painter. ## Toolbar - **Connect / Disconnect** dropdown (shows current host or "Not connected") - **Time range** selector: presets (last 10s / 1min / 10min / 1h) or custom range picker - **Time display** toggle: absolute UTC vs relative - **Record** button: opens signal selection dialog → starts recording for selected signals - **Status indicator**: green = connected, yellow = reconnecting, red = disconnected ## Keyboard Shortcuts | Key | Action | |-----|--------| | `Space` | Pause / resume live scrolling | | `R` | Reset all plot zoom/pan to live view | | `C` | Add cursor to focused plot | | `Del` | Remove selected cursor | | `Ctrl+N` | Add new plot panel | | `Ctrl+W` | Close focused plot panel | | `Ctrl+F` | Focus signal tree search | | `Ctrl+S` | Save current layout to file | ## Session Persistence On clean exit, the UI saves the current session to `~/.config/rmon/last_session.toml`: - Connected host alias - Open plot panels and their signal assignments - Cursor positions - Time range and zoom state On next launch with the same host, it offers to restore the session. ## State Machine (connection) ``` Disconnected │ user clicks Connect ▼ Deploying (copying/verifying agent binary) │ agent ready ▼ Tunneling (SSH port-forward process running) │ port open ▼ Handshaking (TCP open, sent Handshake, awaiting HandshakeAck) │ accepted ▼ Connected (normal operation, DataBatch messages flowing) │ tunnel drops / error ▼ Reconnecting (exponential backoff, max 30s, reuses same tunnel if still up) │ max retries exceeded ▼ Disconnected ``` ## Async / UI Thread Boundary - `tokio` runtime runs in a dedicated OS thread - The egui render loop runs on the main thread (required by most platform window systems) - Communication: `std::sync::mpsc::channel` — the tokio tasks push `UiEvent` variants (DataBatch, SignalList, Status, Error) to the UI; the UI pushes `Command` variants (Subscribe, QueryHistory, StartRecording) to tokio - `eframe::App::update()` drains the incoming event channel each frame before rendering