Three pages opened in nothing in Yelp -- overview (twice), math, trigger -- while every check passed. They are exactly the pages whose <figure> had a sentence for a <title> and no <desc>: a Mallard <figure> is title?, desc?, media, and the page is refused without the description. The idiomatic shape, as the shipped sets on this machine write it, moves the sentence into <desc> and leaves the <title> a name. Note trigger-capture.png is referenced from both overview and trigger, which is why those two pages are the ones that were noticed. The gap was in the check, not in its reach: tools/check_help.sh ran links/media/orphans/ids and an HTML render, and all four are silent about a page that is well linked, well parsed and unrenderable. `yelp-check validate` is the one that would have caught it, and it cannot run here: it generates the RelaxNG schema with xsltproc, but the schema includes the base grammar over the network and this machine's libxml cannot fetch. So the structural rules this project has actually needed are checked with xmllint's XPath, offline, each written after a page needed it. One trap, paid for while writing it: a Mallard page declares xmlns="http://projectmallard.org/1.0/", XPath 1.0 has no default namespace, so `//figure` matches nothing and every rule passes -- the first version of this check reported "ok" for the very defect it was written for. Every expression uses local-name() for that reason, and the script says so where the next reader will be. Verified: on the committed pages the rules exit 1 and name the three figures, which is the failing-before case kept as the regression test; on the fixed pages all five rules pass and yelp-build renders all 15; make -C build test-help goes from red to green.
171 lines
7.9 KiB
Plaintext
171 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</title>
|
|
<desc>The header bar above the plots, the side panel on the right, and the status bar
|
|
along the bottom.</desc>
|
|
<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</title>
|
|
<desc>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.</desc>
|
|
<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>
|