Files
2026-11-03 11:15:19 +01:00

228 lines
12 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 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-samples</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 badge bar and the status bar under them, and
the dock on the right.</desc>
<media type="image" mime="image/png" src="figures/main-window.png" width="1280" height="800">
<p>One figure of three rows with three signals plotted, a badge for each in the badge
bar, the dock with its readouts and its events block, 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
empty badge bar is working correctly, not failing to connect. For the same reason a start
that has enabled nothing prints no <code>buffer allocated:</code> line on stderr.</p>
<note style="warning">
<p>Over SSH with X11 forwarding the window may never appear, and the cure is
<cmd>udpscope --renderer cairo</cmd>. Two symptoms tell the two halves apart: a
<code>vkCreateSwapchainKHR() ... VK_ERROR_INITIALIZATION_FAILED</code> warning is
GTK's default Vulkan renderer failing to make a swapchain and is what the option's
<code>GSK_RENDERER=cairo</code> answers; a window whose allocation stays zero
(<code>window_button_w=0</code>) means the plot's GL area has no context either, and
that is what its <code>LIBGL_ALWAYS_SOFTWARE=1</code> answers. Both variables are
exported before GTK initialises, because they are read when the renderer and the GL
context are created. <cmd>--renderer gl</cmd> is faster when indirect GL works.</p>
</note>
<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; then, on
the right, the cursors switch, the dock switch and the menu, which holds
<gui>Fit to data</gui>, the <gui>Layout editor</gui>, <gui>Export visible range</gui>,
<gui>Configurations</gui>, <gui>Help</gui>, <gui>Preferences</gui> and
<gui>About</gui>. The trigger button turns trigger mode on and off; the trigger's
settings are in the panel its badge opens.</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 badge bar</title>
<p>The strip under the plot. On the left, one badge for each signal you have switched
on, then a <gui>+</gui>; past six signals they fold into a single <gui>N signals</gui>
badge. On the right, <gui>Trigger</gui>, which names the trigger's state, and <gui>Source</gui>, which is there only when the
source has controls of its own. A badge opens its page in the panel described next;
a signal's badge is also what you drag onto a row.</p>
</item>
<item>
<title>The side panel over the plot</title>
<p>One panel, 360 px wide, slides over the plot's right edge and shows one page at a
time: the trigger, a signal's colour, calibration and rows, the list of signals to
add, the cursors, the measurements, the events, or a source's own controls. It closes
with a second click on the badge that opened it, with <key>Esc</key>, with
<gui>Close</gui>, or with a click on the plot, and it never resizes the plot.</p>
</item>
<item>
<title>The dock</title>
<p>The column on the right, which the dock button in the header bar (<key>s</key>)
shows and hides. Its <gui>Readouts</gui> are a read-only copy of the cursors and of
every measurement; <gui>Edit</gui> beside each heading opens that instrument's full
page. Under them, <gui>Events</gui> lists the captured events, newest first; a click
replays one and <gui>Manage</gui> opens the full list. While the dock is hidden, or the window is narrow and the
dock slides over the plot, the readouts show in a strip under the plot instead, as long as the cursors are on or there is a measurement.</p>
</item>
<item>
<title>The status bar</title>
<p>The last line, under the badge bar — 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 capture looks like: the trigger marker at the edge
and the axis pinned to the event.</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 <gui>Signals</gui> page (the <gui>+</gui> badge, or <key>g</key>). 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 its badge 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> — press <key>m</key>, or <gui>Edit</gui> beside
<gui>Measurements</gui> in the dock. A measurement is a statistic of the visible
window, its value is shown in the dock, 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>
<section id="installing">
<title>Installing this manual</title>
<p>The manual is a help set the desktop viewer reads off disk, so <key>F1</key> opens it only
once a copy sits where <cmd>help:</cmd> resolves. Either of two targets installs it on its own,
without building the application, and each prints where it wrote. Prefer the system-wide one:
it is the copy every viewer can read, and the reason is worth knowing before you pick the
other:</p>
<list>
<item><p>For a system-wide or packaged install:
<cmd>cmake --build build --target install-help</cmd> writes it under the configured
<cmd>CMAKE_INSTALL_PREFIX</cmd>, so point that at <file>/usr</file>
(<cmd>cmake -DCMAKE_INSTALL_PREFIX=/usr ..</cmd>) and wrap the target in
<cmd>sudo</cmd>. A viewer reads its figures as separate files, and its sandbox exposes the
system help directories, so this copy always shows them.</p></item>
<item><p>For your own account, needing no root:
<cmd>cmake --build build --target install-help-user</cmd> writes it under
<file>$XDG_DATA_HOME</file> (default <file>~/.local/share</file>). Be aware that the same
sandbox does <em>not</em> expose the user's data directory: those pages open, but a viewer
such as Yelp shows them without their figures.</p></item>
</list>
</section>
</page>