Files
MARTe-Integrated-Components/Docs/StreamHub-API.md
T
2026-06-14 14:09:51 +02:00

8.2 KiB
Raw Blame History

StreamHub WebSocket API

StreamHub exposes a single WebSocket server (default port 8090, any URL path). Text frames carry JSON commands/events; binary frames carry data pushes and trigger captures. The Go reference hub (Client/udpstreamer) implements the identical protocol; both the browser SPA and the ImGui client work against either.

For the upstream UDPS wire format (source → hub) see Protocol.md.

All numbers in binary frames are little-endian. All timestamps are Unix wall-clock seconds (float64) — see Time base in StreamHub-Developer.md.


1. Commands (client → hub, JSON text frames)

Every command is a JSON object with a type field.

ping

{"type":"ping"}

Reply (unicast): {"type":"pong"}.

addSource

{"type":"addSource","label":"PSU","addr":"192.168.0.10:44500",
 "multicastGroup":"239.0.0.1","dataPort":44503}
  • addrhost:port of the UDPStreamer control port.
  • multicastGroup / dataPort — optional; if present the hub joins the multicast group for DATA and keeps a TCP control connection for CONNECT/CONFIG.
  • The hub assigns ids s1, s2, … and broadcasts an updated sources event.

removeSource

{"type":"removeSource","id":"s1"}

saveSources

{"type":"saveSources"}

Persists the current dynamically-added source list to the hub's SourcesFile (JSON array of {label,addr,multicastGroup,dataPort}); it is reloaded at startup.

getSources / getConfig / getStats

{"type":"getSources"}
{"type":"getConfig","sourceId":"s1"}
{"type":"getStats"}

Force a broadcast of the corresponding event.

setTrigger

{"type":"setTrigger","signal":"s1:Sine","edge":"rising","threshold":0.0,
 "windowSec":0.1,"prePercent":20,"mode":"normal"}
  • signal — full key src:sig, or src:sig[i] to trigger on element i of a multi-element PACKET signal.
  • edge"rising", "falling" or "both".
  • windowSec — total capture window (clamped to 1e-4 … 10 s). preSec = windowSec * prePercent / 100, postSec = windowSec preSec.
  • mode"normal" (auto-rearm ~200 ms after capture) or "single" (stays TRIGGERED until rearm).

arm / disarm / rearm / trigStop

{"type":"arm"}
{"type":"disarm"}
{"type":"rearm"}
{"type":"trigStop","stopped":true}
  • arm — IDLE → ARMED.
  • disarm — any state → IDLE.
  • rearm — TRIGGERED → ARMED (single mode).
  • trigStop — sets the stopped flag suppressing auto-rearm in normal mode; omit stopped to toggle.

Every transition is broadcast as a triggerState event.

zoom

{"type":"zoom","reqId":17,"t0":1765370000.123,"t1":1765370000.223,
 "n":2400,"signals":"s1:Sine,s2:Wave[0]"}
  • reqId — echoed in the reply; lets the client match request/response.
  • t0/t1 — Unix seconds window.
  • n — target points per signal. Absent or <10 → 2400; n ≤ 0no decimation (raw ring contents).
  • signals — comma-separated full keys; absent → all signals of all sources.
  • The reply is unicast to the requesting client only.

historyZoom

{"type":"historyZoom","reqId":42,"t0":1765360000.0,"t1":1765370000.0,
 "n":2400,"signals":"s1:Sine,s2:Wave"}
  • Reads from disk-backed history instead of the in-memory ring buffer. Identical semantics to zoom but queries the .shist files written by HistoryWriter.
  • reqId, t0/t1, n, signals — same meaning as zoom.
  • If history is not enabled, the reply contains "error":"history not enabled".
  • Reply is unicast (same shape as zoom reply, but "type":"historyZoom").

historyInfo

{"type":"historyInfo"}

Request the hub to send a historyInfo event (unicast). Also sent automatically on client connect.

setMaxPoints

{"type":"setMaxPoints","maxPoints":50000}

Resizes all ring buffers (applied safely inside the push loop; push cursors are reset). Broadcasts maxPointsUpdated.


2. Events (hub → client, JSON text frames)

sources

{"type":"sources","sources":[
  {"id":"s1","label":"PSU","addr":"192.168.0.10:44500","state":"streaming"}]}

Sent on client connect, after add/remove/getSources, and when a source first delivers its CONFIG.

config

{"type":"config","sourceId":"s1","publishMode":0,"signals":[
  {"name":"Sine","typeCode":10,"quantType":0,"numDimensions":0,
   "numRows":1,"numCols":1,"rangeMin":-1.0,"rangeMax":1.0,
   "timeMode":0,"samplingRate":5000000.0,"timeSignalIdx":-1,"unit":"V"}]}

Field semantics follow the UDPS signal descriptor (Protocol.md). numElements = numRows × numCols.

stats

Sent at StatsRate Hz (default 1 Hz):

{"type":"stats","sources":{"s1":{
  "state":"streaming","totalReceived":1234,"totalLost":0,
  "rateHz":100.1,"rateStdHz":0.3,
  "fragsPerCycle":3.0,"bytesPerCycle":4200.0,
  "cycleAvgMs":10.0,"cycleStdMs":0.1,"cycleMinMs":9.8,"cycleMaxMs":10.4,
  "cycleHistMin":9.8,"cycleHistMax":10.4,"cycleHist":[0,1,5,"…(20 bins)"]}}}

triggerState

{"type":"triggerState","state":"triggered","mode":"normal",
 "stopped":false,"trigTime":1765370000.1234567}

stateidle | armed | collecting | triggered; trigTime present once a trigger has fired.

zoom (reply)

{"type":"zoom","reqId":17,"signals":{
  "s1:Sine":{"t":[1765370000.1230000,"…"],"v":[0.123456789,"…"]}}}

t is serialised with %.17g (full float64 precision — required for µs windows at Unix-epoch magnitudes), v with %.9g.

historyInfo

Sent on client connect (if history is enabled) and on historyInfo command:

{"type":"historyInfo","enabled":true,"durationHours":1.0,"decimation":10,
 "signals":{
   "scalar:Sine1":{"t0":1765360000.0,"t1":1765370000.0,"count":360000,"capacity":360000},
   "scalar:Sine2":{"t0":1765360000.0,"t1":1765370000.0,"count":360000,"capacity":360000}}}
  • enabledtrue if the +History config block is present and valid.
  • durationHours — configured history duration.
  • decimation — samples-to-disk decimation factor (1 = every sample).
  • signals — per-signal metadata keyed by "sourceId:signalName":
    • t0/t1 — oldest/newest timestamp stored on disk (Unix seconds).
    • count — number of valid entries currently in the circular file.
    • capacity — total capacity of the circular file.

historyZoom (reply)

Same shape as zoom reply, but "type":"historyZoom":

{"type":"historyZoom","reqId":42,"signals":{
  "s1:Sine":{"t":[1765360000.1230000,"…"],"v":[0.123456789,"…"]}}}

If history is not enabled: {"type":"historyZoom","error":"history not enabled"}.

maxPointsUpdated

{"type":"maxPointsUpdated","maxPoints":50000}

3. Binary frames (hub → client)

The first byte of every binary WS frame is a version discriminator.

Version 1 — data push

Sent at PushRate Hz per source. Contains only the samples that are new since the previous push (per-signal cursors hub-side), LTTB-decimated to at most MaxPushPoints (default 50) per signal.

[1]   version = 1
[1]   sourceIdLen (L)
[L]   sourceId (UTF-8, no NUL)
[4]   numSignals (uint32)

per signal:
  [2]   keyLen (uint16) (K)
  [K]   key = signal name; "name[i]" per element for multi-element PACKET signals
  [4]   pairCount (uint32) (N)
  [N×8] t (float64, Unix seconds)
  [N×8] v (float64, physical units)

Clients must append samples verbatim — there is no overlap between pushes.

Version 2 — trigger capture

Broadcast once per capture (FSM COLLECTING → TRIGGERED). Contains all signals over [trigTime preSec, trigTime + postSec], each LTTB-decimated to ≤ 20 000 points.

[1]   version = 2
[8]   trigTime (float64, Unix seconds)
[8]   preSec   (float64)
[8]   postSec  (float64)
[4]   numSignals (uint32)

per signal:
  [2]   keyLen (uint16) (K)
  [K]   fullKey = "src:sig" (UTF-8)
  [4]   pairCount (uint32) (N)
  [N×8] t (float64, Unix seconds)
  [N×8] v (float64)

4. Limits

Limit Value
Concurrent WS clients 16
UDPS source sessions 32
Max received WS payload 64 KiB
Max sent WS payload 4 MiB