flatudp: the signal-row editor form with a per-row Vector as drop-down, its probe line, README and architecture notes

Multicast was verified on a loopback group (239.255.42.99 on 127.0.0.1); a real network was not exercised.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino FerrariandClaude Opus 4.6 committed 2026-11-02 01:23:51 +01:00
1 parent e3bc1f72f3
commit d955baf612
6 files changed
+385 -20

No files matched your search

+27
View File
@@ -61,6 +61,33 @@ What feeds `Acquisition` is a `DataSource`, one of the registered *kinds*.
only through `post()`. `Acquisition::on_event` ignores the detail string and does nothing for `Error`,
so the source also writes each new error to stderr as `[e1608] ...` (once per distinct message, not per
retry); that line is where a user sees why a connection failed.
- **The flat UDP kind is three files and no thread.** `flatudp_signals` is the `signals` string codec,
the validity rules and the decoders, with no GTK and no sockets (the probe round-trips it);
`flatudp_source` is `FlatUdpSettings` plus the `DataSource`; `flatudp_kind` is the form, a signal-row
editor (a name, a type, a count and, while the count is above 1, a "Vector as" drop-down per row). The
datagram has no description, so a list that is wrong is invisible except as dropped datagrams: the size
check is the only defence, and it is why a wrong-size datagram is counted (`stale`) and reported once per
size.
- A vector row is shown one of two ways, chosen per row (`Row::wave`, the `w` suffix in the text). As
**channels** it is `count` scalar channels of one sample per cycle, so the list batches like an
all-scalar one. As a **waveform** it is one channel with `rows = count` and
`sampling_rate = rate * count`, one datagram per `Frame` (`num_samples = 1`). The two cannot share a
list because the model spans a frame by its largest element block and `Frame::value` is 0 past a scalar's
one value: a scalar beside a vector block would be zero-padded, so `problem()` demands that a list with a
waveform row be waveform rows of one count, and the form shows that message in the subtitle. The channel
total is capped at 256.
- Its frames are **fixed-size blocks** like the E-1608's for the same reason (`build_stamps` warns when the
sample count varies): `round(rate / 100)` datagrams for a list with no waveform row, a partial block
flushed after 100 ms. `rate` is required because `sampling_rate = 0` makes the model size the ring and
the ingest decimation for 1 kHz; there is no time-base switch, since `acquisition.cpp` has no stamping
path that ignores the declared cadence.
- `Disconnected` after 2 s without a *valid* datagram (wrong-size ones do not refresh the clock); it resets
`Acquisition`'s per-session state, so the next datagram re-anchors rather than reading as a gap, and the
history survives (`CONFIG` is sent once, from the first `poll()`).
- The form's row editor removes a row from inside its own button's `clicked` emission (GTK keeps the emitter
alive to the end of the emission, and the handler copies the form and the row out of its context first);
every handler tests `Form::alive`, which the groups' `destroy` clears, because the chooser may have
destroyed the sibling widgets the handlers reach by raw pointer.
### Data path