Transports
SiFi Bridge communicates over two independent channels, and each can run over a different transport:
- The control channel carries commands in and responses out — the request/response model you use in the REPL. This is a pull interface: you send a command, you get one JSON response back.
- The data channel carries the asynchronous DataPacket stream out — the live samples as they arrive from the device.
Choosing transports lets you, for example, drive SiFi Bridge programmatically from another machine while fanning the data stream out to a separate processing host.
The control channel is bidirectional and synchronous (command → response). The data channel is outbound and asynchronous (a continuous stream). buffer pull rides the control channel — it is a command with a response — even though it returns sample data. The live stream rides the data channel.
Control channel (commands & responses)
Every command — connect, start, buffer pull, … — is sent on the control channel and answered with a single JSON response on the same channel. This is the REPL model.
stdin / stdout (default)
By default SiFi Bridge reads commands from stdin (one command per line) and writes responses to stdout. This is what you get when you launch sifibridge and type at the > prompt, and it is also the simplest way to drive it from a parent process via pipes.
TCP (--tcp-in)
sifibridge --tcp-in 127.0.0.1:5000
Binds a TCP listener so commands are sent over a socket — useful for remote control or driving SiFi Bridge from another process/host without managing a child process's stdin. When --tcp-in is set it replaces stdin: commands are no longer read from stdin, and each command's response is sent back on the same socket.
You must provide the host:port to bind — there is no default.
Data channel (the DataPacket stream)
The live stream can be sent to several outputs at once — e.g. --tcp-out and --lsl together — so you can deliver data to multiple consumers simultaneously. The --tcp-out and --udp-out transports each require an explicit host:port (there are no default ports); --lsl takes no address, since LSL handles discovery itself.
stdout (default)
DataPackets are emitted to stdout (i.e., terminal output) as JSON. In the default stdin/stdout REPL they are interleaved with command responses on the same stream; with --tcp-in responses go to the socket instead, so stdout then carries only data packets.
Disable the stdout data stream with --no-stdout-data. This is useful when you route the stream elsewhere (--tcp-out/--udp-out/--lsl) and want stdout kept clean, or when you work exclusively through the buffering service — making SiFi Bridge effectively a pure REPL:
sifibridge --no-stdout-data
Combine --no-stdout-data with a data transport to get the best of both: a clean stdin/stdout REPL for commands and responses, with the DataPacket stream routed somewhere else. For example, keep typing commands at the prompt while a separate consumer reads the stream over TCP:
sifibridge --no-stdout-data --tcp-out 0.0.0.0:12345
TCP (--tcp-out)
sifibridge --tcp-out 0.0.0.0:12345
SiFi Bridge acts as a TCP server: it binds the provided address and waits for subscribers to connect. The address is therefore a local bind address (e.g. 0.0.0.0:8080 for all interfaces, or a specific LAN IP), not a remote host. TCP is reliable and ordered — prefer it when you cannot tolerate dropped packets and a little extra latency/buffering is acceptable.
UDP (--udp-out)
sifibridge --udp-out 192.168.1.100:12345
Sends DataPackets to a UDP endpoint. Unlike --tcp-out, the address here is the remote destination to send to (the subscriber's host:port), not a local bind address. UDP is fire-and-forget — lowest latency and overhead, but packets may be dropped or reordered. Prefer it for real-time visualization or feedback where the freshest sample matters more than completeness.
Lab Streaming Layer (--lsl)
sifibridge --lsl
Publishes the data stream over Lab Streaming Layer (LSL) for integration with LSL-aware acquisition and synchronization tooling. Unlike the network transports, --lsl takes no address — LSL handles its own discovery, so consumers find the streams by name or type rather than connecting to a host:port.
LSL support is a compile-time feature. If the binary was built without it, --lsl logs LSL feature not enabled and does nothing.
Stream layout
SiFi Bridge publishes one LSL outlet per channel group, per device — not a single combined stream. A device with every sensor enabled surfaces as the following outlets:
| Sensor | Outlets | LSL stream type | Channels per outlet |
|---|---|---|---|
| ECG | <device>:ecg | ECG | 1 |
| EMG | <device>:emg | EMG | 1 (BioPoint) / 8 (SiFiBand armband) |
| EDA | <device>:eda | EDA | 1 |
| IMU | <device>:ax, :ay, :az, :qw, :qx, :qy, :qz | IMU | 1 each (7 outlets) |
| PPG | <device>:ir, :r, :g, :b | PPG | 1 each (4 outlets) |
| Temperature | <device>:temperature | Temperature | 1 |
So a fully-enabled device yields 15 outlets (IMU and PPG are split into one single-channel outlet per axis/wavelength; the 8-channel SiFiBand armband is the one exception, carried as a single 8-channel emg outlet).
- Stream name follows
<device name>:<channel>, where<device name>is the device's current (possibly renamed) name — e.g.my_bp:ecg,my_bp:ax,my_bp:ir. source_idis the device's BLE MAC address, which lets LSL consumers recognise and automatically reconnect to the same physical device across restarts.- Channel format is
float32. Note this is narrower than thef64used by the buffers and the JSON DataPacket — samples are downcast to 32-bit floats on the LSL path. - Nominal sample rate is taken from the device configuration (the sensor's
fs; for PPG, the effective--sps ÷ --avgrate).
Dynamic reconfiguration
Outlets are created lazily on the first packet of each type and rebuilt automatically when the device configuration changes. Changing a sampling rate updates the affected stream's nominal rate; disabling a sensor drops its outlet; enabling one adds it — without restarting SiFi Bridge.
Multiple devices
Each connected device gets its own independent set of outlets, distinguished by the <device name>: prefix and its unique source_id. Streaming several devices at once therefore produces several parallel stream sets.
SiFi Bridge pushes samples to LSL without forwarding the device-side timestamps, so each sample is stamped by LSL using the host clock at the moment it is pushed. Because BLE delivers samples in bursts, expect push-time jitter on the LSL timestamps. For exact device timing, use the DataPacket timestamps (over another transport) or a buffered export instead.
Choosing a data transport
| Transport | Reliability | Latency | Use when |
|---|---|---|---|
| stdout | Reliable (local pipe) | Low | Local processing in a parent process; quick inspection. |
TCP (--tcp-out) | Reliable, ordered | Low–moderate | Networked consumers that must not drop samples. |
UDP (--udp-out) | Best-effort | Lowest | Real-time feedback/visualization tolerant of loss. |
LSL (--lsl) | Per LSL | Per LSL | Multi-device sync and the LSL ecosystem. |
See the Invocation options reference for the full flag list, and Data output for the packet format carried over every data transport.