The help was 14 Pango-markup `.txt` bodies in a second GResource, drawn into a paged `GtkWindow` built in `help_window.cpp`. That made F1 a viewer of ours with no search index, no cross-references and no translation, and it kept the manual in the *binary* when every other desktop application's is a document on disk. It is now a real Mallard set: help/C/org.udpscope.app/ index.page + 14 topic pages + figures/*.png and `show_help()` hands `help:org.udpscope.app` to whatever the desktop registered for the `help:` scheme -- Yelp on GNOME -- through a `GtkUriLauncher`, reporting a launch failure with a `GtkAlertDialog` rather than a click that silently does nothing. The paged window's builder, the page table and `help_self_check()`'s markup validation are gone with the resource. The document identifier is the desktop file's own basename (its desktop-file id), derived in CMakeLists from `data/org.udpscope.app.desktop.in`, so the same string is the `.desktop` name, the GApplication id and the install directory at once. The set is installed by a new `install()` rule to `<datadir>/help/C/org.udpscope.app/` -- where the freedesktop Help System Specification's `help:` URI resolves `help:<id>` -- so the manual is read from a datadir by another process even though the binary has no install step. `UDPSCOPE_HELP_NAME` and `UDPSCOPE_HELP_DIR` are compiled in from that one place. The 14 pages were migrated fact for fact, but restructured the Mallard way: a `<desc>` per page (what a search result shows), `<steps>` for procedures, `<terms>` for option lists, `<gui>`/`<key>`/`<keyseq>` for interface words and keys, `<note>` for the asides, and a topic graph via `<link type="guide" xref="index#main"/>`. The figures are annotated screenshots produced by `tools/make-help-shots.sh`, which drives the app headlessly against `tools/mock_udpstreamer.py` and draws the boxes with ImageMagick; the side panel's box is measured from the app's own `side=NNNx` dump reading, the header and status bands come from a documented table, and a crop whose standard deviation is 0 fails the script. `cmake --build build --target test-help` checks the set the way `test-ui` checks the `.ui` files: `yelp-check`'s offline subcommands (links, media, orphans, ids) and a `yelp-build html` render. `yelp-check validate` is deliberately absent -- it fetches the Mallard RelaxNG schema over the network and fails offline for that reason, not for a fault in the pages. The `[help]` probe reading changes with the resource it was written for. `parsed == pages` over in-binary markup cannot exist now, so `help_self_check()` scans `UDPSCOPE_HELP_DIR` and the line reads `topics=14 index=1 figures=3`; `topics=0 index=0` is the manual missing from the tree, which is the finding the old count named. Verified: clean build with the documented three warnings (the help bundle's `-Woverlength-strings` is gone, so the baseline moves from four to three); test-ui 14/14; test-help clean (the four subcommands and 15 pages rendered); a temp-prefix install lands 15 `.page` files and 3 figures at `share/help/C/org.udpscope.app/`; the headless run reads `[help] topics=14 index=1 figures=3 dir=...` with 0 Gtk-CRITICAL. Yelp's own window could not be exercised on this box -- it starts under Xvfb, activates its portals and never maps, the same WebKit/portal limitation that stops a grab -- so its rendering and its search index are unverified here; the content pipeline was (`yelp-build` renders the whole set). Docs: the manual's build/install/open story in `build-and-run.md` and README; the warning baseline in `verification.md`/CLAUDE.md; the help bullets in `invariants-gtk-and-chrome.md`; the `[help]` line in `probe-readings.md`.
170 lines
7.9 KiB
Plaintext
170 lines
7.9 KiB
Plaintext
<page xmlns="http://projectmallard.org/1.0/"
|
|
type="topic" style="task"
|
|
id="overview">
|
|
|
|
<info>
|
|
<link type="guide" xref="index#main"/>
|
|
<desc>What udpscope plots, the four parts of the window, and one pass through the
|
|
application from connecting to saving.</desc>
|
|
<credit type="author copyright">
|
|
<name>Martino Ferrari</name>
|
|
</credit>
|
|
</info>
|
|
|
|
<title>Overview</title>
|
|
|
|
<section id="what">
|
|
<title>What udpscope is</title>
|
|
<p>udpscope plots a live UDPStreamer source. One window holds up to eight rows of plots,
|
|
each with up to four traces, and every row shares one time axis, so the whole figure
|
|
scrolls together. Acquisition runs on its own thread and writes a ring buffer sized from
|
|
<cmd>--buffer-mb</cmd>; the drawing thread reads whatever that ring holds when a frame
|
|
starts, which is why a trace never makes the window stutter.</p>
|
|
|
|
<p>The stream is the clock. Every interval you read on screen is measured between
|
|
timestamps the source sent, never your machine's, so a stalled source freezes the view
|
|
instead of scrolling it — and a source whose clock steps still gets the window you asked
|
|
for.</p>
|
|
|
|
<p>The time axis is <em>relative to now</em>. While streaming it is a fixed
|
|
<code>[-window .. 0]</code> with the newest sample at 0, so x reads as an age:
|
|
<code>-1.5s</code> is a sample a second and a half old. In trigger mode 0 is the event's
|
|
edge instead, and a paused view keeps the ages it was frozen with. The source's own clock
|
|
is still there when you need it — an export writes it as a second column.</p>
|
|
|
|
<figure>
|
|
<title>The udpscope window on a live source: the header bar above the plots, the side
|
|
panel on the right, and the status bar along the bottom.</title>
|
|
<media type="image" mime="image/png" src="figures/main-window.png" width="1280" height="800">
|
|
<p>One figure of three rows with four signals enabled, the Measure tab open in the
|
|
side panel, and the status bar reading <gui>live</gui>.</p>
|
|
</media>
|
|
</figure>
|
|
</section>
|
|
|
|
<section id="reach">
|
|
<title>How to reach it</title>
|
|
<p>Start the app with a source
|
|
(<cmd>udpscope --server 127.0.0.1 --port 8000</cmd>), or start it with no
|
|
<cmd>--server</cmd> and pick one from the chooser, which lists the sessions you have
|
|
opened before. A unicast source serves one client at a time: if a second viewer connects,
|
|
they take turns and the status bar says so. To watch one source from several instances,
|
|
use <cmd>--multicast</cmd> with the group and <cmd>--interface</cmd> with the local
|
|
address.</p>
|
|
|
|
<p>The signals arrive <em>disabled</em>. Nothing is acquired until you turn one on in the
|
|
signal list, and enabling is what starts acquisition — so a freshly opened scope with an
|
|
idle side panel is working correctly, not failing to connect.</p>
|
|
|
|
<note style="tip">
|
|
<p>See <link xref="source">Choosing a source</link> for the chooser and the multicast
|
|
options in full.</p>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="window">
|
|
<title>The window</title>
|
|
<terms>
|
|
<item>
|
|
<title>The header bar</title>
|
|
<p>Left to right: the time window (<gui>2 s</gui>), the trigger and the pause, the
|
|
events, cursors and side-panel switches, and the menu, which holds
|
|
<gui>Fit to data</gui>, the <gui>Layout editor</gui>, <gui>Export</gui>,
|
|
<gui>Keyboard shortcuts</gui>, <gui>Help</gui> and <gui>About</gui>.</p>
|
|
</item>
|
|
<item>
|
|
<title>The side panel</title>
|
|
<p>Two tabs. <gui>Measure</gui> holds the cursors readout and the measurements
|
|
derived from it; <gui>Signals</gui> holds the trigger and the channel list, where a
|
|
math channel is a row of that one list under a <gui>MATH</gui> heading whose
|
|
<gui>+</gui> creates one. One row per channel: its colour, an enable switch, its name
|
|
and its unit. Channels are dragged from here onto a plot row.</p>
|
|
</item>
|
|
<item>
|
|
<title>The plot</title>
|
|
<p>Up to eight rows, each with its own y axis and up to four traces, all on one shared
|
|
time axis. Right-click a row for its own menu (fit, add a signal, remove a trace).</p>
|
|
</item>
|
|
<item>
|
|
<title>The status bar</title>
|
|
<p>Directly above the plot's bottom edge — the state word, the stored sample rate and
|
|
the window, and the ⓘ beside it for packets, gaps and the buffer's own figures. The
|
|
second screenshot below is what a held capture looks like: <gui>event held</gui>, the
|
|
axis pinned to the event, and the trigger marker at the edge.</p>
|
|
</item>
|
|
</terms>
|
|
|
|
<figure>
|
|
<title>A held capture: the trigger has latched, the state reads
|
|
<gui>event held</gui>, and the axis is pinned to the event rather than to the live
|
|
edge.</title>
|
|
<media type="image" mime="image/png" src="figures/trigger-capture.png" width="1280" height="800">
|
|
<p>The trigger marker sits at x = 0 and the pre-trigger share of the window is drawn
|
|
to its left.</p>
|
|
</media>
|
|
</figure>
|
|
</section>
|
|
|
|
<section id="first">
|
|
<title>The first five minutes</title>
|
|
<steps>
|
|
<item>
|
|
<p><em>Connect.</em> With no <cmd>--server</cmd>, pick a stored session or type a host
|
|
and port.</p>
|
|
</item>
|
|
<item>
|
|
<p><em>Enable a signal</em> in the signal list. The plot stays empty for the first
|
|
fraction of a second while the first window fills — the buffer holds only what has
|
|
arrived.</p>
|
|
</item>
|
|
<item>
|
|
<p><em>Drag it onto a row.</em> Drop a second signal on another row, or the same
|
|
signal again for a second view of it. The colour is per signal, so it is the same one
|
|
wherever it appears.</p>
|
|
</item>
|
|
<item>
|
|
<p><em>Set the window</em> with the control in the header bar: type a number, pick a
|
|
unit, or step a decade. The trigger's event window is a share of this span, so a
|
|
window change moves it.</p>
|
|
</item>
|
|
<item>
|
|
<p><em>Pause</em> (<key>space</key>) to look at a still picture; the producer keeps
|
|
filling the buffer behind it, and resuming shows what arrived meanwhile rather than a
|
|
hole.</p>
|
|
</item>
|
|
<item>
|
|
<p><em>Arm the trigger</em> (<key>a</key>) and wait for a latch: the view freezes on
|
|
one event, and you can zoom in on it. Disarming mid-capture keeps what the capture
|
|
got.</p>
|
|
</item>
|
|
<item>
|
|
<p><em>Measure it</em> — the measurements pane computes a statistic of the visible
|
|
window, and <gui>show on plot</gui> marks it as a ruler or a pair of markers.</p>
|
|
</item>
|
|
<item>
|
|
<p><em>Save the data</em> with <gui>Export visible range</gui>, which writes the
|
|
plotted signals over the window at the stored rate to <file>.npy</file>,
|
|
<file>.csv</file> or <file>.mf3</file> (MDF 3.30).</p>
|
|
</item>
|
|
</steps>
|
|
</section>
|
|
|
|
<section id="knowing">
|
|
<title>Worth knowing</title>
|
|
<list>
|
|
<item><p>A signal nobody enables costs nothing — no buffer, no socket work, no
|
|
measurements.</p></item>
|
|
<item><p>The window remembers itself. Rows, traces, the time window, calibration, which
|
|
signals were enabled, the math channels with their graphs, and the measurements are
|
|
written per host and port, and reloaded the next time you open that source.</p></item>
|
|
<item><p>A very wide window on a fast stream is drawn from averaged groups of samples,
|
|
so the rate in the status bar falls: that is the anti-alias filter, not a fault —
|
|
striding would fold a fast signal back as a slow one, which looks entirely plausible on
|
|
screen.</p></item>
|
|
<item><p>Every instrument the app computed — the trigger marker, the measurement marks
|
|
— is locked to the pointer's reach. The cursors are yours to drag; those are not.</p></item>
|
|
</list>
|
|
</section>
|
|
|
|
</page>
|