Implemented and fixed many issues
This commit is contained in:
+39
-3
@@ -314,7 +314,7 @@ Hub-side trigger with the web client's semantics (config: signal key
|
||||
```
|
||||
IDLE →[arm]→ ARMED
|
||||
ARMED →[edge crossing]→ COLLECTING (latches trigTime, pre/postSec)
|
||||
COLLECTING →[post window + margin elapsed]→ TRIGGERED (broadcast binary v2 capture)
|
||||
COLLECTING →[every source produced past the window]→ TRIGGERED (broadcast binary v2 capture)
|
||||
TRIGGERED →[auto-rearm (normal, ~200 ms) | rearm (single)]→ ARMED
|
||||
any →[disarm]→ IDLE
|
||||
```
|
||||
@@ -325,6 +325,30 @@ sample of the configured signal. The capture is assembled in the push loop from
|
||||
LTTB-capped at 20 000 points/signal, and broadcast as a binary version-2 frame.
|
||||
A `stopped` flag (`trigStop`) freezes auto-rearm.
|
||||
|
||||
COLLECTING is left on the **data's** clock, not `clock_gettime()`: `trigTime`
|
||||
comes from sample timestamps, and a source that free-runs on its own clock sits
|
||||
seconds away from wall time, so a wall-clock deadline chops exactly that offset
|
||||
off every capture's tail. `UDPSourceSession::ProducerNewestTime()` reports how
|
||||
far a source has produced — counting only signals actually timestamped from a
|
||||
time signal, since PACKET-timed ones (the time array itself included) are
|
||||
stamped on arrival and would just report "now".
|
||||
|
||||
Sources are harvested **one at a time**, each as soon as *it* passes
|
||||
`trigTime + postSec + 0.15 s` (`BeginTriggerCapture` / `HarvestTriggerCapture` /
|
||||
`FinishTriggerCapture`, the frame accumulating across push ticks). Making every
|
||||
source wait for the slowest lets the leaders' rings roll past the pre-trigger
|
||||
region before it is ever read. A 2 s wall-clock watchdog per capture bounds the
|
||||
wait for a source that stopped advancing; it is harvested short, with a warning
|
||||
naming the source and how far it got.
|
||||
|
||||
Because `RingTemporal` only holds ~1 s at 1 MSps, `setTrigger` publishes the
|
||||
requested window and the push loop calls `GrowRingsForTrigger()`: each ring
|
||||
measures its own rate (`Count() / TimeSpan()` — UDPS sources usually report
|
||||
`samplingRate = 0`) and is grown in place to `rate × (window + 0.5 s) × 1.2`,
|
||||
clamped per signal to `RingMaxMB`. `SignalRingBuffer::Grow()` preserves
|
||||
contents *and* `totalWritten`, so live push cursors stay valid. Without this a
|
||||
long window only ever captures its tail.
|
||||
|
||||
### Configuration File (MARTe2 cfg format)
|
||||
|
||||
```
|
||||
@@ -334,9 +358,11 @@ Hub = {
|
||||
PushRate = 30 // push loop Hz
|
||||
MaxPushPoints = 50 // LTTB cap per signal per tick
|
||||
StatsRate = 1 // stats broadcast Hz
|
||||
RingTemporal = 1000000 // ring capacity (points) for multi-element signals
|
||||
RingTemporal = 1000000 // initial ring capacity (points) for multi-element signals
|
||||
RingScalar = 100000 // ring capacity (points) for scalar signals
|
||||
RingMaxMB = 128 // per-signal ceiling when a trigger window grows a ring
|
||||
SourcesFile = "streamhub_sources.json" // dynamic-source persistence
|
||||
AllowedOrigins = "http://127.0.0.1:8099,http://localhost:8099" // see below
|
||||
Sources = {
|
||||
App1 = {
|
||||
Label = "MARTe2 App 1"
|
||||
@@ -358,6 +384,16 @@ Sources added at runtime (`addSource`) get generated ids `s1, s2, …`;
|
||||
`saveSources` persists them to `SourcesFile` (JSON array of
|
||||
`{label, addr, multicastGroup?, dataPort?}`), reloaded at start-up.
|
||||
|
||||
`AllowedOrigins` is a comma/space-separated allowlist of `scheme://host[:port]`
|
||||
values accepted in the WebSocket `Origin` header (max 8 entries, 128 chars
|
||||
each), matching the Go hub's option. Without it the handshake only accepts an
|
||||
`Origin` whose host matches the request `Host` — so a browser that loaded the
|
||||
SPA from a *different* port than the hub (the `run_streamhub.sh` layout, SPA on
|
||||
8099 and hub on 8090) is rejected with 403. Non-browser clients send no `Origin`
|
||||
and are unaffected. This is the CSWSH guard of RFC 6455 §10.2: browsers attach
|
||||
cookies to cross-origin WebSocket handshakes, so `Origin` is the only thing
|
||||
distinguishing a legitimate page from an attacker's.
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
@@ -401,7 +437,7 @@ binary frames carry data push payloads.
|
||||
| `sources` | `sources:[{id, label, addr:"host:port", state}]` | On connect; after add/remove/getSources; on first CONFIG |
|
||||
| `config` | `sourceId`, `publishMode`, `signals:[{name, typeCode, quantType, numDimensions, numRows, numCols, rangeMin, rangeMax, timeMode, samplingRate, timeSignalIdx, unit}]` | After CONFIG received from source |
|
||||
| `stats` | `sources:{id:{state, totalReceived, totalLost, rateHz, rateStdHz, fragsPerCycle, bytesPerCycle, cycleAvgMs, cycleStdMs, cycleMinMs, cycleMaxMs, cycleHistMin, cycleHistMax, cycleHist:[20]}}` | At `StatsRate` Hz |
|
||||
| `triggerState` | `state` (`"idle"`\|`"armed"`\|`"collecting"`\|`"triggered"`), `mode`, `stopped`, `trigTime?` | On any trigger FSM transition |
|
||||
| `triggerState` | `state` (`"idle"`\|`"armed"`\|`"collecting"`\|`"triggered"`), `mode`, `stopped`, `trigTime?`, `preSec?`, `postSec?` | On any trigger FSM transition |
|
||||
| `zoom` | `reqId`, `signals:{"src:sig":{t:[…], v:[…]}}` (`t` printed `%.17g`, `v` `%.9g`) | Unicast reply to `zoom` |
|
||||
| `maxPointsUpdated` | `maxPoints` | After ring buffer resize |
|
||||
| `calibration` | `cal:[{source, signal, scale, offset, unit}]` | On connect; after an accepted `setCalibration`; after a successful `reloadConfig` |
|
||||
|
||||
Reference in New Issue
Block a user