Feature/source plugins #1

Merged
martino merged 130 commits from feature/source-plugins into main 2026-11-04 07:35:21 +01:00
16 changed files with 180 additions and 113 deletions
Showing only changes of commit 328588a8b9 - Show all commits

No files matched your search

+9 -7
View File
@@ -1277,7 +1277,7 @@ same reason: a frame can arrive between two layout passes, and a hole that empti
the spotlight and the card jump. The card goes under the target, over it, or in the column beside it the spotlight and the card jump. The card goes under the target, over it, or in the column beside it
-- whichever has room -- and only takes the bottom corner when the target *is* the whole content, -- whichever has room -- and only takes the bottom corner when the target *is* the whole content,
which is what happens to the plot step in the documented headless run (a 640x480 Xvfb screen gives which is what happens to the plot step in the documented headless run (a 640x480 Xvfb screen gives
the window its 756x894 minimum, and at that width the split view overlays the side panel instead of the window its 756x894 minimum, and at that width the split view overlays the dock instead of
putting it beside the plot). The probe prints the two rectangles (`spot=`, `card=`) rather than putting it beside the plot). The probe prints the two rectangles (`spot=`, `card=`) rather than
asserting a placement, so that case reads as the geometry it is. asserting a placement, so that case reads as the geometry it is.
@@ -3048,11 +3048,13 @@ now — they are listed so they are not mistaken for anything else:
trigger mode and the block would grey itself under the click that started it. (8) The **dock's event rows carry no trigger mode and the block would grey itself under the click that started it. (8) The **dock's event rows carry no
thumbnails** (the page's do) and show a **hollow marker on the members of the group on screen**, which the page's thumbnails** (the page's do) and show a **hollow marker on the members of the group on screen**, which the page's
rows do not. (9) The dock lists at most 24 events; the page lists them all. rows do not. (9) The dock lists at most 24 events; the page lists them all.
The signal badges, the signal pages and the drag (step 2) are done. Still to come, in the spec's The signal badges, the signal pages and the drag (step 2) are done, and so are the events block in the
order: `USER-GUIDE.md` and the manual's figures (4). The events section in the dock and the `events` dock and the `events` page (the left events pane, its divider and the header's Events toggle are
page are done, and the left events pane, its divider and the header's Events toggle are deleted. Until deleted), the Mallard manual, `USER-GUIDE.md` and the two figures that show the window
the manual is swept, it (which still describes the side panel's tabs, and the cursors, measurements (`main-window.png`, `trigger-capture.png`, regenerated with `tools/make-help-shots.sh`). The
and events as panes of it) still describes the previous layout. manual's `math-editor.png` is the editor's own window and was not regenerated.
The main-window figure shows `'sine' is off: 1 trace left the plots` in the status bar and no sine
badge: the headless enable-all probe that drives the scene ends that way, and the figure records it.
- **A plot holds at most eight signals** (`RowSet::kSlotsPerRow`), because a `Plot` - **A plot holds at most eight signals** (`RowSet::kSlotsPerRow`), because a `Plot`
cannot give up a trace and the slots are therefore created up front. cannot give up a trace and the slots are therefore created up front.
- **One toggle drives both cursor orientations.** The vertical markers and the - **One toggle drives both cursor orientations.** The vertical markers and the
@@ -3187,7 +3189,7 @@ silence timeout and then resumes, which is the EMI case end to end.
- **The tour card can cover its own target, and in the documented headless run it - **The tour card can cover its own target, and in the documented headless run it
does.** The card is placed under, over or beside the hole whenever one of those has does.** The card is placed under, over or beside the hole whenever one of those has
room; when the target covers the whole content -- which is what the plot does at the room; when the target covers the whole content -- which is what the plot does at the
window's 756 px minimum, because the split view overlays the side panel rather than window's 756 px minimum, because the split view overlays the dock rather than
putting it beside the plot -- no placement can avoid it, and the card takes the putting it beside the plot -- no placement can avoid it, and the card takes the
bottom corner. The probe prints both rectangles instead of asserting a placement, bottom corner. The probe prints both rectangles instead of asserting a placement,
so the case reads as a measurement. so the case reads as a measurement.
+45 -22
View File
@@ -6,9 +6,22 @@ what was built and why, and `SPECS.md` is the requirement document.
![the main window](img/main-window.png) ![the main window](img/main-window.png)
*The main window with a source streaming: the signal panel on the right, the plot in the middle, the *The main window with a source streaming: the header bar above (the window control — `2 s` — first on
status line directly under it, and the toolbar above. The window control — `2 s` — is the first thing the left), the plot, the badge bar under it with one badge per signal, the status line at the foot, and
on the left.* the dock on the right with the cursor and measurement readouts and the events block.*
The window is a plot with three things around it:
- the **badge bar** under the plot: a badge for each signal you have switched on, a `+` to add one
(past six they fold into one `N signals` badge), and, on the right, **Trigger** and — only for a
source with controls of its own — **Source**;
- the **side panel**, which a badge opens over the plot's right edge, one page at a time: the trigger,
a signal, the list of signals to add, the cursors, the measurements, the events, or a source's own
controls. A second click on the badge, `Esc`, **Close** or a click on the plot closes it, and it
never resizes the plot;
- the **dock** on the right, which the dock button in the header bar (`s`) shows and hides: read-only
**Readouts** of the cursors and of the measurements, each with an **Edit** button that opens its
page, and an **Events** block.
## 1. Connecting ## 1. Connecting
@@ -30,7 +43,7 @@ Every launch is its own process, so running two scopes side by side is fine.
## 2. The status line ## 2. The status line
Directly under the plot, it reads `● <state> · <rate> · <window>`, and the ⓘ beside it opens the At the foot of the window, under the badge bar, it reads `● <state> · <rate> · <window>`, and the ⓘ beside it opens the
detail: packets, frames, gaps, per-channel sample counts, the buffer's span and its decimation. detail: packets, frames, gaps, per-channel sample counts, the buffer's span and its decimation.
- **The state word is one word** from a fixed set: `live`, `paused`, `armed`, `capturing`, - **The state word is one word** from a fixed set: `live`, `paused`, `armed`, `capturing`,
@@ -44,14 +57,16 @@ detail: packets, frames, gaps, per-channel sample counts, the buffer's span and
## 3. Signals ## 3. Signals
The signal panel lists every signal the CONFIG described, with a switch each. **Signals start The **`+` badge** (or `g`) opens the **Signals** page, which lists what can be added: the signals the
disabled — enabling one is what starts acquiring it**, and a signal nobody enables costs nothing. CONFIG described that are not acquired yet, each with a tick. **Signals start disabled — ticking one
Drag a signal from the panel onto a plot row to add a trace; drag it again to another row to plot the is what starts acquiring it**, and a signal nobody enables costs nothing. Its badge then appears in
same signal twice. The colour is per *signal*, so the same signal is the same colour wherever it the badge bar. Drag the badge onto a plot row to add a trace; drag it again to another row to plot
appears. the same signal twice, or onto another badge to reorder the badges. The colour is per *signal*, so
the same signal is the same colour wherever it appears.
The panel also holds the per-signal calibration: gain and offset, applied at ingest, so the Clicking a signal's badge opens its own page: the colour, **Plot on** buttons for the rows, and
measurements and the export carry the same numbers the plot shows. **Calibrate** — gain and offset, applied at ingest, so the measurements and the export carry the same
numbers the plot shows.
## 4. The window and navigation ## 4. The window and navigation
@@ -83,8 +98,9 @@ should look like.
*Single mode with a capture held: the axis is the event's own `[-pre, +post]`, the trigger marker *Single mode with a capture held: the axis is the event's own `[-pre, +post]`, the trigger marker
sits at the edge, and the status line reads `event held`.* sits at the edge, and the status line reads `event held`.*
The trigger panel has the edge, the pre/post split (as a share of the event span), Normal or Single, The trigger button in the header bar (`t`) turns trigger mode on. The **Trigger** badge opens the
and Arm/Disarm. Selecting a signal for the trigger enables it. trigger page, which has the signal, the condition, the edge, the pre/post split (as a share of the
event span), Normal or Single, and Arm/Disarm. Selecting a signal for the trigger enables it.
- **While a capture fills** the plot keeps drawing live data on the event's clock, so the post side - **While a capture fills** the plot keeps drawing live data on the event's clock, so the post side
fills in view; the axis does not move. fills in view; the axis does not move.
@@ -94,6 +110,10 @@ and Arm/Disarm. Selecting a signal for the trigger enables it.
when you disarm is the picture you keep. when you disarm is the picture you keep.
- The event window is counted in **stream seconds** end to end, so a source whose clock advances in - The event window is counted in **stream seconds** end to end, so a source whose clock advances in
jumps still gets the window it asked for. jumps still gets the window it asked for.
- **Events.** With *record events* on (trigger page), each latch is stored. The dock's **Events** block
lists them newest first and **one click replays** one; **Manage** opens the full list as a page,
where a click selects, a double click replays, and **Compare**, **Accumulate** and **Live** act on
the selection or go back to the stream. The block is dimmed until something is recorded.
## 6. Pause ## 6. Pause
@@ -104,22 +124,24 @@ does not walk it off its snapshot.
## 7. Cursors ## 7. Cursors
The cursors toolbar toggle switches on two instruments per row: The cursors toggle in the header bar (`c`) switches on two instruments per row:
- **vertical** — two times, shared by every row; - **vertical** — two times, shared by every row;
- **horizontal** — two rulers per row; - **horizontal** — two rulers per row;
- **both** — the two together; - **both** — the two together;
- **mix** — the two times, read off each *trace* where they cross it. - **mix** — the two times, read off each *trace* where they cross it.
The pane beside it reports each trace's values at the markers, and **Reset** puts them back at the The dock reports each trace's values at the markers; **Edit** beside **Cursors** opens the page with
window's edges. Values read `--` when a marker is past the newest sample and `partial` when only one the mode and **Reset**, which puts them back at the window's edges. Values read `--` when a marker is past the newest sample and `partial` when only one
marker is over data. marker is over data.
## 8. Measurements ## 8. Measurements
The measurements pane computes statistics of the **visible window** of a signal: average, top, A measurement is a statistic of the **visible window** of a signal: average, top, bottom, min, max,
bottom, min, max, peak to peak, amplitude, pulse duration, period and frequency. `+` adds one, the peak to peak, amplitude, pulse duration, period and frequency. `m`, or **Edit** beside
row's pencil edits it, and **show on plot** draws its result as a ruler (levels) or markers (times). **Measurements** in the dock, opens the page; its `+` adds one, a click on a row (in the page or in
the dock) edits it, and **show on plot** draws its result as a ruler (levels) or markers (times).
The dock shows each measurement's value.
`top` and `bottom` take a *split* as a share of the window's own range — the percentage travels `top` and `bottom` take a *split* as a share of the window's own range — the percentage travels
between signals where a threshold in volts would not. `period` and `frequency` deliberately have no between signals where a threshold in volts would not. `period` and `frequency` deliberately have no
@@ -127,7 +149,7 @@ split: they count rising crossings of the mid level, one edge per cycle, and a s
setting you can only get wrong. setting you can only get wrong.
The values are refreshed on a cadence — at most every 100 ms while the window is scrolling, once when The values are refreshed on a cadence — at most every 100 ms while the window is scrolling, once when
it stops, and once per mode change — so a live view cannot cost you frames. The pane's cost is it stops, and once per mode change — so a live view cannot cost you frames. The cost is
reported in the exit dump with the app's self-check. reported in the exit dump with the app's self-check.
## 9. Math channels ## 9. Math channels
@@ -139,13 +161,14 @@ the square on the right. The orange dot marks the node that carries the channel'
A math channel is derived from the others and is then an ordinary channel: enable it and it is A math channel is derived from the others and is then an ordinary channel: enable it and it is
acquired, plotted, measured and exported like a streamed signal, and another math channel can use it acquired, plotted, measured and exported like a streamed signal, and another math channel can use it
as a source. as a source. The **Signals** page lists them under a `MATH` heading whose `+` creates one; a math
channel's own page has **Edit graph** and **Delete**.
Operations: `channel` (a source), `gain + offset`, `abs`, `sqrt`, `clamp`, `low pass`, `high pass`, Operations: `channel` (a source), `gain + offset`, `abs`, `sqrt`, `clamp`, `low pass`, `high pass`,
`band pass` (biquads, corner in Hz against the stored rate), `sum`, `difference`, `product`, `ratio`. `band pass` (biquads, corner in Hz against the stored rate), `sum`, `difference`, `product`, `ratio`.
- **Click** a node to select it; its parameters appear in the form beside the canvas. - **Click** a node to select it; its parameters appear in the form beside the canvas.
- **Click an output square, then an input square**, to wire them. An input is only offered the nodes - **Drag from an output square to an input square** to wire them. An input is only offered the nodes
above it — the graph is a list walked in order, so a cycle cannot be drawn. above it — the graph is a list walked in order, so a cycle cannot be drawn.
- **Drag** a box to move it. **add node**, **delete node** and **set as output** are below the form. - **Drag** a box to move it. **add node**, **delete node** and **set as output** are below the form.
- The **output is the last node** of a graph you build top to bottom, and the orange dot says which; - The **output is the last node** of a graph you build top to bottom, and the orange dot says which;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 129 KiB

+5 -4
View File
@@ -22,12 +22,13 @@
<title>How to reach it</title> <title>How to reach it</title>
<steps> <steps>
<item> <item>
<p>Press the cursors button in the toolbar, or <key>c</key>.</p> <p>Press the cursors button in the header bar, or <key>c</key>. It switches the cursors on
and off.</p>
</item> </item>
<item> <item>
<p>The readings are in the side panel (a read-only copy) and in the cursors panel, which <p>The readings are in the dock (a read-only copy) and on the <gui>Cursors</gui> page, which
<gui>Edit</gui> beside <gui>Cursors</gui> opens over the plot and which owns a <gui>Edit</gui> beside <gui>Cursors</gui> opens over the plot and which owns the mode
<gui>Reset</gui> button. Drag a marker to move it.</p> and a <gui>Reset</gui> button. Drag a marker to move it.</p>
</item> </item>
<item> <item>
<p>The mode dropdown offers four modes: <gui>vertical</gui> (the shared time pair), <p>The mode dropdown offers four modes: <gui>vertical</gui> (the shared time pair),
Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

After

Width:  |  Height:  |  Size: 129 KiB

+5 -3
View File
@@ -22,10 +22,12 @@
<title>How to reach it</title> <title>How to reach it</title>
<steps> <steps>
<item> <item>
<p>Press the math button in the toolbar, or <key>g</key>.</p> <p>Open the <gui>Signals</gui> page (the <gui>+</gui> badge, or <key>g</key>). Math channels
are listed under a <gui>MATH</gui> heading.</p>
</item> </item>
<item> <item>
<p>The pane's <gui>+</gui> adds a channel, and opening one shows the graph editor: <p>The heading's <gui>+</gui> adds a channel. <gui>Edit graph</gui>, on a channel's page,
shows the graph editor:
nodes as boxes, click a box to select it and edit its parameters beside the canvas.</p> nodes as boxes, click a box to select it and edit its parameters beside the canvas.</p>
</item> </item>
<item> <item>
@@ -53,7 +55,7 @@
<em>above</em> it. A wire drawn right to left re-sorts the list silently so the graph <em>above</em> it. A wire drawn right to left re-sorts the list silently so the graph
stays valid. A cycle is unrepresentable: the connection is refused rather than created, stays valid. A cycle is unrepresentable: the connection is refused rather than created,
and the line beneath the form says why — a loop, or a node asked to read itself.</p></item> and the line beneath the form says why — a loop, or a node asked to read itself.</p></item>
<item><p>A derived channel <em>is</em> a channel. It appears in the signal panel, can be <item><p>A derived channel <em>is</em> a channel. It is listed with the signals, gets a badge once computed, can be
plotted, measured, exported, and used as a source for another math channel.</p></item> plotted, measured, exported, and used as a source for another math channel.</p></item>
<item><p>The math runs on the <em>stored</em> samples — decimated and averaged — so a <item><p>The math runs on the <em>stored</em> samples — decimated and averaged — so a
cutoff you type in Hz means the rate the filter will actually run at. Change the window cutoff you type in Hz means the rate the filter will actually run at. Change the window
+4 -2
View File
@@ -28,10 +28,12 @@
<title>How to reach it</title> <title>How to reach it</title>
<steps> <steps>
<item> <item>
<p>Press <key>m</key>, or <gui>Edit</gui> beside <gui>Measurements</gui> in the side panel.</p> <p>Press <key>m</key>, or <gui>Edit</gui> beside <gui>Measurements</gui> in the dock. Either opens the
<gui>Measurements</gui> page over the plot; the dock itself shows each measurement's value,
and a click on one opens its dialog.</p>
</item> </item>
<item> <item>
<p>The panel's <gui>+</gui> adds one; clicking a row opens the dialog where the signal, <p>The page's <gui>+</gui> adds one; clicking a row opens the dialog where the signal,
the type, the threshold share or shares and the on-plot marks are set, with the type, the threshold share or shares and the on-plot marks are set, with
<gui>Save</gui> and <gui>Delete</gui>.</p> <gui>Save</gui> and <gui>Delete</gui>.</p>
</item> </item>
+46 -27
View File
@@ -4,7 +4,7 @@
<info> <info>
<link type="guide" xref="index#main"/> <link type="guide" xref="index#main"/>
<desc>What udpscope plots, the four parts of the window, and one pass through the <desc>What udpscope plots, the parts of the window, and one pass through the
application from connecting to saving.</desc> application from connecting to saving.</desc>
<credit type="author copyright"> <credit type="author copyright">
<name>Martino Ferrari</name> <name>Martino Ferrari</name>
@@ -34,11 +34,12 @@
<figure> <figure>
<title>The udpscope window</title> <title>The udpscope window</title>
<desc>The header bar above the plots, the side panel on the right, and the status bar <desc>The header bar above the plots, the badge bar and the status bar under them, and
along the bottom.</desc> the dock on the right.</desc>
<media type="image" mime="image/png" src="figures/main-window.png" width="1280" height="800"> <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 <p>One figure of three rows with three signals plotted, a badge for each in the badge
side panel, and the status bar reading <gui>live</gui>.</p> bar, the dock with its readouts and its events block, and the status bar reading
<gui>live</gui>.</p>
</media> </media>
</figure> </figure>
</section> </section>
@@ -55,7 +56,7 @@
<p>The signals arrive <em>disabled</em>. Nothing is acquired until you turn one on in the <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 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. For the same reason a start 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> that has enabled nothing prints no <code>buffer allocated:</code> line on stderr.</p>
<note style="warning"> <note style="warning">
@@ -81,32 +82,48 @@
<terms> <terms>
<item> <item>
<title>The header bar</title> <title>The header bar</title>
<p>Left to right: the time window (<gui>2 s</gui>), the trigger and the pause, the <p>Left to right: the time window (<gui>2 s</gui>), the trigger and the pause; then, on
events, cursors and side-panel switches, and the menu, which holds 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</gui>, <gui>Fit to data</gui>, the <gui>Layout editor</gui>, <gui>Export visible range</gui>,
<gui>Keyboard shortcuts</gui>, <gui>Help</gui> and <gui>About</gui>.</p> <gui>Configurations</gui>, <gui>Help</gui>, <gui>Preferences</gui> and
</item> <gui>About</gui>. The trigger button turns trigger mode on and off; the trigger's
<item> settings are in the panel its badge opens.</p>
<title>The side panel</title>
<p>A read-only copy of the cursors and of the measurements; the <gui>Edit</gui> button
beside each heading opens that instrument's full panel over the plot. The channel
list and the trigger are panels of their own, opened from the badge bar and the
toolbar, where a math channel is a row of the 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. A channel's badge in the badge bar is dragged onto a
plot row.</p>
</item> </item>
<item> <item>
<title>The plot</title> <title>The plot</title>
<p>Up to eight rows, each with its own y axis and up to four traces, all on one shared <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> time axis. Right-click a row for its own menu (fit, add a signal, remove a trace).</p>
</item> </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.</p>
</item>
<item> <item>
<title>The status bar</title> <title>The status bar</title>
<p>Directly above the plot's bottom edge — the state word, the stored sample rate and <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 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 second screenshot below is what a capture looks like: the trigger marker at the edge
axis pinned to the event, and the trigger marker at the edge.</p> and the axis pinned to the event.</p>
</item> </item>
</terms> </terms>
@@ -129,12 +146,12 @@
and port.</p> and port.</p>
</item> </item>
<item> <item>
<p><em>Enable a signal</em> in the <gui>Add a signal</gui> page (the <gui>+</gui> badge). The plot stays empty for the first <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 fraction of a second while the first window fills — the buffer holds only what has
arrived.</p> arrived.</p>
</item> </item>
<item> <item>
<p><em>Drag it onto a row.</em> Drop a second signal on another row, or the same <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 signal again for a second view of it. The colour is per signal, so it is the same one
wherever it appears.</p> wherever it appears.</p>
</item> </item>
@@ -154,8 +171,10 @@
got.</p> got.</p>
</item> </item>
<item> <item>
<p><em>Measure it</em> — the measurements pane computes a statistic of the visible <p><em>Measure it</em> — press <key>m</key>, or <gui>Edit</gui> beside
window, and <gui>show on plot</gui> marks it as a ruler or a pair of markers.</p> <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>
<item> <item>
<p><em>Save the data</em> with <gui>Export visible range</gui>, which writes the <p><em>Save the data</em> with <gui>Export visible range</gui>, which writes the
+1 -1
View File
@@ -22,7 +22,7 @@
<title>How to reach it</title> <title>How to reach it</title>
<steps> <steps>
<item> <item>
<p>Press the pause button in the toolbar, or <key>Space</key>.</p> <p>Press the pause button in the header bar, or <key>Space</key>.</p>
</item> </item>
<item> <item>
<p>Press it again to resume, which rebinds the live ring and puts the window back on <p>Press it again to resume, which rebinds the live ring and puts the window back on
+1 -1
View File
@@ -57,7 +57,7 @@
<list> <list>
<item><p>What a configuration persists: the time window, the rows and each row's slot <item><p>What a configuration persists: the time window, the rows and each row's slot
signals, the calibration, the trace colours, which signals were enabled, the math signals, the calibration, the trace colours, which signals were enabled, the math
channels with their graphs, the measurements pane — and the startup settings: samples channels with their graphs, the measurements — and the startup settings: samples
per signal, relative time and the packet capture's ring size.</p></item> per signal, relative time and the packet capture's ring size.</p></item>
<item><p>Signal identity is the <em>name</em> throughout, because a new CONFIG renumbers <item><p>Signal identity is the <em>name</em> throughout, because a new CONFIG renumbers
the channels.</p></item> the channels.</p></item>
+14 -10
View File
@@ -23,11 +23,15 @@
<title>How to reach it</title> <title>How to reach it</title>
<steps> <steps>
<item> <item>
<p>Open the side panel (<key>s</key>), which lists every signal with a switch.</p> <p>Click the <gui>+</gui> badge in the badge bar, or press <key>g</key>. The
<gui>Signals</gui> page lists what can be added — the signals the source declares that
are not acquired yet, each with a tick that acquires it. Past six acquired signals the
badges fold into one <gui>N signals</gui> badge, and the page then lists every signal.</p>
</item> </item>
<item> <item>
<p>The <gui>Signal list</gui> item in the overflow menu opens the editor where the <p>Once a signal is acquired its badge appears. Click it to open that signal's page: its
unit and the calibration live.</p> colour, <gui>Plot on</gui> buttons for the rows, and <gui>Information</gui> and
<gui>Calibrate</gui>, where the signal's details and its calibration live.</p>
</item> </item>
</steps> </steps>
</section> </section>
@@ -38,7 +42,7 @@
<item><p>Signals start disabled, and enabling one is what starts acquiring it. A trigger <item><p>Signals start disabled, and enabling one is what starts acquiring it. A trigger
on a signal nobody acquires can never fire, so arming a trigger enables its signal for on a signal nobody acquires can never fire, so arming a trigger enables its signal for
you.</p></item> you.</p></item>
<item><p><gui>Calibrate</gui> in a signal's row menu opens the gain and offset it is <item><p><gui>Calibrate</gui> on a signal's page opens the gain and offset it is
<em>currently</em> drawn through, so a trace already scaled by a gain of 2 shows 2 — <em>currently</em> drawn through, so a trace already scaled by a gain of 2 shows 2 —
pressing <gui>Apply</gui> confirms it rather than resetting it. A signal nobody pressing <gui>Apply</gui> confirms it rather than resetting it. A signal nobody
calibrated shows the identity, 1 and 0.</p></item> calibrated shows the identity, 1 and 0.</p></item>
@@ -51,12 +55,12 @@
refuses to put it in a row rather than binding a trace that would read nothing for refuses to put it in a row rather than binding a trace that would read nothing for
ever.</p></item> ever.</p></item>
<item><p>A signal's colour follows the <em>signal</em>, not the slot, so the same signal <item><p>A signal's colour follows the <em>signal</em>, not the slot, so the same signal
on two rows is one colour and the side panel's chip identifies it unambiguously. A on two rows is one colour, and the dot on its badge shows it. A signal on no row gets a
signal on no row gets a grey chip rather than none, so the panel's rows keep their grey dot rather than none.</p></item>
height.</p></item> <item><p><em>Change a signal's colour</em> with <gui>Change colour</gui> on its page; a
<item><p><em>Click a coloured chip to change that signal's colour.</em> A grey chip signal on no row has no trace to colour, so the button is dimmed. The colour is saved
names no trace, so it is not clickable. The colour is saved with the session; with the session; <gui>Default colour</gui> on the same page gives the palette entry
<gui>Default colour</gui> in the signal's ⋯ menu gives the palette entry back.</p></item> back.</p></item>
</list> </list>
</section> </section>
+1 -1
View File
@@ -18,7 +18,7 @@
<section id="reach"> <section id="reach">
<title>How to reach it</title> <title>How to reach it</title>
<p>The bar is always visible under the plot. Click <gui>ⓘ</gui> for the detail popover.</p> <p>The bar is always visible at the foot of the window, under the badge bar. Click <gui>ⓘ</gui> for the detail popover.</p>
</section> </section>
<section id="knowing"> <section id="knowing">
+22 -18
View File
@@ -23,15 +23,16 @@
<title>How to reach it</title> <title>How to reach it</title>
<steps> <steps>
<item> <item>
<p>The trigger button in the toolbar (<key>t</key>) reveals the trigger panel: the <p>Click the <gui>Trigger</gui> badge at the right of the badge bar to open the
signal, the level, the shape, the edge (rising, falling, either), the mode (Normal or trigger page: the signal, the level, the shape, the edge (rising, falling, either), the
Single) and the pre-trigger share.</p> mode (Normal or Single) and the pre-trigger share. The trigger button in the header bar
(<key>t</key>) turns trigger mode on and off; it does not open the page.</p>
</item> </item>
<item> <item>
<p><gui>Arm</gui> starts watching; <key>a</key> arms and disarms from the keyboard. <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 When the page is locked with its edit button — so that it states what the
trigger is set to instead of showing the controls — <gui>Arm/Disarm</gui> is in its 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 heading, and the trigger can be armed or disarmed without unfolding the page. It is
offered only while trigger mode is on, because a trigger that is off has no engine to offered only while trigger mode is on, because a trigger that is off has no engine to
arm.</p> arm.</p>
</item> </item>
@@ -170,29 +171,32 @@
<p><em>Every triggered acquisition is kept.</em> Latches are written to the event cache <p><em>Every triggered acquisition is kept.</em> Latches are written to the event cache
(<file>~/.cache/udpscope/events/&lt;source&gt;/</file>) as a <file>.npy</file> of the (<file>~/.cache/udpscope/events/&lt;source&gt;/</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 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 samples. The <gui>Events</gui> block at the foot of the dock lists them, newest first, one
event-history button, which appears while recording is enabled, and collapsed until you short row each: a marker for the event on screen, its title and its number. It is dimmed
ask for it — lists the last 32 newest first (time, duration, signals, rate), each row with until recording is on, an event is stored or one is being replayed. <gui>Manage</gui>
its own picture beside the numbers.</p> beside its heading opens the <gui>Events</gui> page over the plot, which keeps the last 32
(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 <p>Clicking a row in the dock <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 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 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 replay leaves trigger mode, because a file has no edge to wait for. <gui>Live</gui>, on the
open. Drag the pane's edge to resize it. <gui>Live</gui> goes back to the stream; the <gui>Events</gui> page, goes back to the stream; the status bar names the file until
status bar names the file until you do.</p> you do.</p>
<p>Select two or more events in the list and the two buttons under the header act on them: <p>On the <gui>Events</gui> page, select two or more events in the list and the two buttons
under its header act on them:
<gui>Compare</gui> puts two events in two plots side by side, keeping the layout you have <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 — 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, 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 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 are in both. They need events with the same signals and the same length. On this page a
selects, a <em>double</em> click replays.</p> single click selects and a <em>double</em> click replays.</p>
<p><gui>Record events</gui>, in the trigger panel with the trigger's other options, is <p><gui>Record events</gui>, on the trigger page with the trigger's other options, is
what decides whether anything is kept. It is <em>off by default</em> — nothing is written 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> to disk until you ask — and with it off, and nothing stored, the dock's events block and
the page stay dimmed.</p>
</section> </section>
<section id="search"> <section id="search">
+27 -17
View File
@@ -18,9 +18,9 @@
# * `xdotool search --name udpscope` finds nothing: GTK4 sets no WM_NAME on the X window it # * `xdotool search --name udpscope` finds nothing: GTK4 sets no WM_NAME on the X window it
# creates, so windows are found by their geometry, not their name. # creates, so windows are found by their geometry, not their name.
# #
# Box provenance: the sidebar width is read from the app's own probe dump (`side=NNNx`), so the # Box provenance: the dock's width is read from the app's own probe dump (`side=NNNx`), so the
# side-panel box tracks the real widget; the header and status bands are the table in # dock box tracks the real widget; the header, badge-bar and status bands are the table below,
# `window_boxes` below, each named where it is used, because the dump reports neither. # each named where it is used, because the dump reports none of them.
# #
# Usage: tools/make-help-shots.sh [OUTPUT_DIR] (default help/C/<id>/figures) # Usage: tools/make-help-shots.sh [OUTPUT_DIR] (default help/C/<id>/figures)
set -euo pipefail set -euo pipefail
@@ -41,23 +41,29 @@ done
mkdir -p "$out" mkdir -p "$out"
# --- the window's own geometry, and the boxes it is annotated with ------------- # --- the window's own geometry, and the boxes it is annotated with -------------
# main-window.ui asks for 1280x800, and the sidebar is a fixed 320 px # main-window.ui asks for 1280x800, and the dock is a fixed 280 px (the split view's sidebar,
# (sidebar-width-unit=px, min=max=320). The header bar is the window's titlebar and the status # min=max=280), leaving a 1000 px plot column. The header bar is the window's titlebar, and the
# row sits at the foot of the plot column; neither reports a pixel height, so their bands are # badge bar and the status row sit at the foot of the plot column, the badge bar over the status
# the third measurement -- a pixel scan of a grab, 51 px and 43 px on the current theme -- and # row; none of them reports a pixel height, so their bands are a pixel scan of a grab -- 51 px,
# are refreshed by re-measuring if the styling changes. # 36 px and 43 px on the current theme -- and are refreshed by re-measuring if the styling
# changes. The plot is what is left between the header and the badge bar.
WIN_W=1280 WIN_W=1280
WIN_H=800 WIN_H=800
HEADER_H=51 HEADER_H=51
BADGES_H=36
STATUS_H=43 STATUS_H=43
PLOT_W=952 PLOT_W=1000
PLOT_H=$((WIN_H - HEADER_H - BADGES_H - STATUS_H))
BADGES_Y=$((HEADER_H + PLOT_H))
STATUS_Y=$((BADGES_Y + BADGES_H))
boxes_main="header bar:0:0:$WIN_W:$HEADER_H boxes_main="header bar:0:0:$WIN_W:$HEADER_H
side panel:SIDE_X:$HEADER_H:SIDE_W:706 plot:0:$HEADER_H:$PLOT_W:$PLOT_H
plot:0:$HEADER_H:$PLOT_W:706 badge bar:0:$BADGES_Y:$PLOT_W:$BADGES_H
status bar:0:757:$PLOT_W:$STATUS_H" dock:SIDE_X:$HEADER_H:SIDE_W:$((WIN_H - HEADER_H))
boxes_trigger="event held, axis pinned to the event:0:757:$PLOT_W:$STATUS_H status bar:0:$STATUS_Y:$PLOT_W:$STATUS_H"
the trigger marker at x = 0:0:$HEADER_H:$PLOT_W:706" boxes_trigger="event held, axis pinned to the event:0:$STATUS_Y:$PLOT_W:$STATUS_H
the trigger marker at x = 0:0:$HEADER_H:$PLOT_W:$PLOT_H"
boxes_math="the graph editor:8:8:EW-24:EH-24" boxes_math="the graph editor:8:8:EW-24:EH-24"
display= display=
@@ -88,6 +94,10 @@ export GDK_BACKEND=x11 GSK_RENDERER=cairo LIBGL_ALWAYS_SOFTWARE=1
tmp=$(mktemp -d) tmp=$(mktemp -d)
trap 'cleanup; rm -rf "$tmp"' EXIT trap 'cleanup; rm -rf "$tmp"' EXIT
export XDG_CONFIG_HOME="$tmp/config" XDG_CACHE_HOME="$tmp/cache" XDG_DATA_HOME="$tmp/data" export XDG_CONFIG_HOME="$tmp/config" XDG_CACHE_HOME="$tmp/cache" XDG_DATA_HOME="$tmp/data"
# A first run starts the guided tour 1.5 s in, and a tour card over the plot is not what the figures
# show: say the tour has been offered, the way a second run of the app would find it.
mkdir -p "$XDG_CONFIG_HOME/udpscope"
printf 'tour_seen = true\n' >"$XDG_CONFIG_HOME/udpscope/settings.toml"
python3 "$mock" --port "$port" --rate 10000 --batch 100 >"$tmp/mock.log" 2>&1 & python3 "$mock" --port "$port" --rate 10000 --batch 100 >"$tmp/mock.log" 2>&1 &
mock_pid=$! mock_pid=$!
@@ -136,14 +146,14 @@ stop_app() {
app_pid= app_pid=
} }
side_of_dump() { # LOGFILE -> the sidebar width the app reports, else the table's 320 side_of_dump() { # LOGFILE -> the dock width the app reports, else the table's 280
local s local s
s=$(grep -o 'side=[0-9]*x' "$1" 2>/dev/null | head -1 | grep -o '[0-9]*' || true) s=$(grep -o 'side=[0-9]*x' "$1" 2>/dev/null | head -1 | grep -o '[0-9]*' || true)
echo "${s:-320}" echo "${s:-280}"
} }
# annotate NAME RAW LOG BOXES W H -> the figure, with a numbered box per line of BOXES. # annotate NAME RAW LOG BOXES W H -> the figure, with a numbered box per line of BOXES.
# A box is `label:x:y:w:h`; `SIDE_X`/`SIDE_W` are the sidebar's own numbers, `EW`/`EH` the # A box is `label:x:y:w:h`; `SIDE_X`/`SIDE_W` are the dock's own numbers, `EW`/`EH` the
# grabbed window's width and height. # grabbed window's width and height.
annotate() { annotate() {
local name=$1 raw=$2 log=$3 boxes=$4 win_w=$5 win_h=$6 local name=$1 raw=$2 log=$3 boxes=$4 win_w=$5 win_h=$6