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`.
156 lines
7.8 KiB
Plaintext
156 lines
7.8 KiB
Plaintext
<page xmlns="http://projectmallard.org/1.0/"
|
|
type="topic" style="task"
|
|
id="trigger">
|
|
|
|
<info>
|
|
<link type="guide" xref="index#viewing"/>
|
|
<link type="seealso" xref="pause"/>
|
|
<desc>The trigger's four shapes, arming and hold-off, the event cache with its replay,
|
|
compare and accumulate, and searching the buffer for a condition.</desc>
|
|
<credit type="author copyright">
|
|
<name>Martino Ferrari</name>
|
|
</credit>
|
|
</info>
|
|
|
|
<title>Trigger</title>
|
|
|
|
<p>The trigger watches one signal for a condition and captures a window around it. The
|
|
<gui>Shape</gui> dropdown chooses what counts as an event; the arming, hold-off, pre/post
|
|
window and Normal/Single mode are the same for all four shapes. The captured window is
|
|
frozen on screen until you re-arm.</p>
|
|
|
|
<section id="reach">
|
|
<title>How to reach it</title>
|
|
<steps>
|
|
<item>
|
|
<p>The trigger button in the toolbar (<key>t</key>) reveals the trigger panel: the
|
|
signal, the level, the shape, the edge (rising, falling, either), the mode (Normal or
|
|
Single) and the pre-trigger share.</p>
|
|
</item>
|
|
<item>
|
|
<p><gui>Arm</gui> starts watching; <key>a</key> arms and disarms from the keyboard.
|
|
When the pane is locked with its <gui>[edit]</gui> button — so that it states what the
|
|
trigger is set to instead of showing the controls — <gui>Arm/Disarm</gui> is in its
|
|
heading, and the trigger can be armed or disarmed without unfolding the panel. It is
|
|
offered only while trigger mode is on, because a trigger that is off has no engine to
|
|
arm.</p>
|
|
</item>
|
|
<item>
|
|
<p><gui>Search the buffer</gui> is at the foot of the same panel.</p>
|
|
</item>
|
|
</steps>
|
|
|
|
<figure>
|
|
<title>A held capture: <gui>event held</gui> in the status bar, the axis pinned to the
|
|
event, and the trigger marker at x = 0.</title>
|
|
<media type="image" mime="image/png" src="figures/trigger-capture.png" width="1280" height="800">
|
|
<p>The pre-trigger share is drawn to the left of the marker.</p>
|
|
</media>
|
|
</figure>
|
|
</section>
|
|
|
|
<section id="shapes">
|
|
<title>The four shapes</title>
|
|
<terms>
|
|
<item>
|
|
<title>Edge</title>
|
|
<p>A crossing of the level in the chosen direction, the classic behaviour.</p>
|
|
</item>
|
|
<item>
|
|
<title>Pulse width</title>
|
|
<p>A crossing and its return, qualified by how long the excursion lasted: less than,
|
|
greater than, within or outside a pair of widths; the event is timed at the closing
|
|
edge.</p>
|
|
</item>
|
|
<item>
|
|
<title>Window</title>
|
|
<p>The signal entering or leaving a band between two levels; the panel keeps the two
|
|
levels at least one increment apart, because a zero-width band is not a band: the
|
|
condition becomes an exact float-equality test against the level, which an ordinary
|
|
signal never satisfies and a signal sitting at the level satisfies on every
|
|
transition.</p>
|
|
</item>
|
|
<item>
|
|
<title>Dropout</title>
|
|
<p>The absence of a crossing for longer than a timeout; one event per outage, re-arms
|
|
when a crossing returns.</p>
|
|
</item>
|
|
</terms>
|
|
|
|
<p>The shape's own rows are the only ones shown; the rest are hidden, so the panel never
|
|
offers a pulse width to a window trigger.</p>
|
|
</section>
|
|
|
|
<section id="cache">
|
|
<title>The event cache, replay and compare</title>
|
|
<p><em>Every triggered acquisition is kept.</em> Latches are written to the event cache
|
|
(<file>~/.cache/udpscope/events/<source>/</file>) as a <file>.npy</file> of the
|
|
event, a <file>.txt</file> of what it was, and a <file>.bmp</file> picture drawn from the
|
|
samples. The <gui>Events</gui> pane on the left — opened from the toolbar's
|
|
event-history button, which appears while recording is enabled, and collapsed until you
|
|
ask for it — lists the last 32 newest first (time, duration, signals, rate), each row with
|
|
its own picture beside the numbers.</p>
|
|
|
|
<p>Clicking a row <em>replays</em> it: the stored event is loaded exactly like an exported
|
|
file, <em>without changing the layout</em> — the rows, the colours, the window, the
|
|
cursors and the measurements stay where they are and read the stored data instead. A
|
|
replay leaves trigger mode, because a file has no edge to wait for, and the pane stays
|
|
open. Drag the pane's edge to resize it. <gui>Live</gui> goes back to the stream; the
|
|
status bar names the file until you do.</p>
|
|
|
|
<p>Select two or more events in the list and the two buttons under the header act on them:
|
|
<gui>Compare</gui> puts two events in two plots side by side, keeping the layout you have
|
|
— one plot per event, the axes synchronised, so zooming a row in one zooms the same row in
|
|
the other — and <gui>Accumulate</gui> overlays up to four of them in the same traces,
|
|
translucent, so where they agree the trace is brighter. Your own traces stay where they
|
|
are in both. They need events with the same signals and the same length. A single click
|
|
selects, a <em>double</em> click replays.</p>
|
|
|
|
<p><gui>Record events</gui>, in the trigger panel with the trigger's other options, is
|
|
what decides whether anything is kept. It is <em>off by default</em> — nothing is written
|
|
to disk until you ask — and with it off the history button goes with it.</p>
|
|
</section>
|
|
|
|
<section id="search">
|
|
<title>Search the buffer</title>
|
|
<p><gui>Search the buffer</gui> runs the same condition over the whole retained ring and
|
|
lists every place it holds. The arrows step through hits; each step pauses on the hit,
|
|
centred, exactly as the Pause button does. Up to 16 hits in the visible window are marked
|
|
on every row; when there are more the panel says how many and suggests zooming in. The
|
|
search uses the trigger's own condition, set in one place, so a hit is by construction an
|
|
instant the trigger would have fired.</p>
|
|
</section>
|
|
|
|
<section id="knowing">
|
|
<title>Worth knowing</title>
|
|
<list>
|
|
<item><p>Arming <em>enables</em> the signal if it was off, because a trigger on a signal
|
|
nobody acquires can never fire.</p></item>
|
|
<item><p>The pre-trigger share is a share of the <em>display window</em>, not of the
|
|
ring. A 2 s window at 50% captures 1 s before the edge and 1 s after.</p></item>
|
|
<item><p>There are four display states, and the status bar names each: <gui>armed</gui>
|
|
(watching, nothing drawn yet), <gui>capturing</gui> (the edge was accepted and the post
|
|
window is filling <em>in view</em>, with the marker at x = 0), <gui>event held</gui>
|
|
(the frozen capture) and <gui>disarmed</gui>. A held capture is never quietly replaced
|
|
by live data.</p></item>
|
|
<item><p>The first edge after arming is only accepted once the history reaches back a
|
|
full pre-trigger window, so a capture may legitimately be shorter than you asked for.
|
|
The axis is pinned to what the capture actually got.</p></item>
|
|
<item><p>Disarming <em>during</em> a capture publishes what the capture got to, so the
|
|
picture on screen at that moment stays on screen. No event fired, so the event count
|
|
does not move.</p></item>
|
|
<item><p>The trigger reads the <em>stored</em> signal — decimated and averaged — not the
|
|
wire signal. A spike narrower than one decimation group is filtered away rather than
|
|
triggering on data the buffer does not contain.</p></item>
|
|
</list>
|
|
</section>
|
|
|
|
<section id="example">
|
|
<title>Example</title>
|
|
<p>A 1 Hz sine, level 0, rising, 2 s window at 50%, Single. The capture spans
|
|
<code>[-1.000 .. 1.000]</code> with <code>n=20001</code> samples at 10 kS/s — the span
|
|
times the real rate, plus one — and the marker sits at x = 0 throughout.</p>
|
|
</section>
|
|
|
|
</page>
|