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

+31 -1
View File
@@ -145,11 +145,41 @@ Errors (no device, a rejected connection code, a timeout, the scan socket closin
`[e1608] ...` once per distinct message (an overrun is logged each time it happens); the window shows only that
the source is disconnected (the status popover reads `waiting`, and the panels go insensitive), not why.
The third built-in kind is **Flat UDP**, a receiver for the MARTe2 `UDPSender` datasource: one datagram per
cycle, the signals concatenated in declaration order with no header, no padding and no timestamp, in the
sender's byte order. The datagram describes nothing, so **the signal list in the connection form is the
whole contract and is your responsibility**: one row per signal (a name, a type from `uint8` to `float64`,
and an element count), in the sender's order, including the `Trigger` byte an IndependentThread `UDPSender`
puts first. A row with a count above 1 is a vector, and a "Vector as" drop-down on that row says how to
show it: as **Channels** (the default), where `Wave:float32[16]` becomes 16 scalar channels `Wave[0]` ..
`Wave[15]` of one sample per cycle each, or as a **Waveform**, one channel that receives a block of 16
consecutive samples per cycle (its declared rate is the cycle rate times the count). The waveform is written
`Wave:float32[16]w` in the `signals` text, and the same text is what a session file and `--source-opt
signals=` carry. A list with a waveform row may hold **only waveform rows, all of the same count** (a
scalar or a channels row beside one, or two lengths, would need zero padding or held values, so the form
refuses it and says so), and a list may make **at most 256 channels** (a scalar is one, a channels vector is
`count`, a waveform is one). The form's subtitle shows the channel total and the size the list implies
("6 channels, 13 bytes per datagram"), or the first rule the list breaks; a datagram of any other size is
dropped, counted as stale, and reported once per distinct size on stderr as `[flatudp] ...`. The form also
takes the port (44488, the sender's own default), an optional bind address, an optional multicast group with
the interface to join it on, the byte order, and the sender's **cycle rate in Hz, which is required**: it
sizes the ring and the ingest decimation and spaces the samples within a frame. Time is stamped by the
existing pipeline from arrival and that declared rate (and `--relative-time` gives a counted clock); there is
no timestamp in the stream to prefer. **Loss is never reported** -- with no counter in the datagram, a missed
cycle is indistinguishable from a slow one -- and neither is a changed sender: a list that does not match
reads as "everything dropped". Source-address filtering, detecting the list from the traffic and importing a
MARTe2 `.cfg` are not provided. A list with no waveform row is delivered in frames of about 10 ms
(`round(rate / 100)` cycles, at most 1024; a partial frame is flushed after 100 ms); a list of waveforms
delivers one frame per datagram. The source is connected on the first valid datagram and disconnected after
2 s without one. It is verified against `tools/mock_flatudp.py`, not against a MARTe2 application. Multicast
was verified on a loopback group (`239.255.42.99` joined on `127.0.0.1`, although this machine's `lo` does not
carry the `MULTICAST` flag); a real network, its switches and IGMP were not exercised.
A session file written before kinds existed has no `source_kind`, and is read as UDPS; a UDPS file is
written exactly as before. A kind's capability panels (for instance a source's own controls) appear as
pages of the side stack, and are insensitive rather than hidden while no source is connected.
Planned, each as its own sub-project: a flat UDP kind and ABScope. ABScope has more than one
Planned, as its own sub-project: ABScope. It has more than one
timebase, so it will change the frame and the data path together rather than fit the present single-timebase
frame.