- Rust 99.6%
- Python 0.4%
- ed_panel.rs: pure-logic panel — EdPanelSnapshot read from the SimServer (point_rate, clients, ring fill, playback/light-engine state) and FaultKnobs mapping GUI knobs onto the server's Faults (4 tests). - app.rs: 'Ether Dream' section in the side panel when the fake DAC is running: live point rate, client count, ring fill bar, played points; fault knobs (drop after N replies, truncate reply, reply/data delay, duplicate replies) applied to the server on change. - main.rs: the Ether Dream net thread hands the GUI an Arc<SimServer> clone over a one-shot channel; IDN mode leaves it unused. - EdSource::server() now returns Arc<SimServer>; dead accessors removed. |
||
|---|---|---|
| crates/laser-dac | ||
| docs | ||
| scripts | ||
| tools/univsim | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
univsim — universal laser DAC simulator
One GUI binary that emulates a laser DAC over two protocols, selectable at launch:
| mode | transport | who connects |
|---|---|---|
--mode idn |
UDP 7256 on 0.0.0.0 (default; the standard 7255 is left to a real OpenIDN stack — the server auto-increments if the port is taken) |
OpenIDN / ShowNet senders (laser-opt --out-dac idn, ShowCanvas, liberа-shownet) |
--mode etherdream |
TCP 7765 + UDP 7654 beacon (1/s) | Ether Dream clients (dac.py, talk3.py, nannou/ld1 visualisers) |
Both modes feed the same rendering pipeline: the IDN simulator's GUI (winit + egui),
its 5-second persistence buffer (30/60/90 ms afterglow), PPS counter, underrun meter.
The Ether Dream points arrive as synthetic IDN Wave chunks, so nothing in the
renderer is protocol-specific.
Build
cargo build --release # -> target/release/univsim
./target/release/univsim --list-profiles
Needs X11 libs (libX11, libxcb, …) for the GUI; headless runs work under Xvfb.
Run
Everything has a default — the usual case is just:
univsim
which starts an Ether Dream DAC: TCP 0.0.0.0:7765, beacon on UDP 0.0.0.0:7654
(reaches clients on this machine; use --broadcast-target 255.255.255.255:7654
for clients on the LAN), firmware profile ed1-j4cdac (the ring size the classic
j4c clients hard-code).
univsim --mode idn # OpenIDN senders, UDP 0.0.0.0:7256
Profiles: ed1-j4cdac (1799, default), ed2-r331 (3899), ed3 (4095), ed4 (8191)
— --profile ed2-r331, --list-profiles. --bind, --broadcast-target,
--broadcast-interval-ms, --no-broadcast override the defaults.
Docs
docs/DEVBOOK_UNIVSIM.md — the working devbook (protocol findings, phase log, ports).
The master copy lives in the Obsidian vault; the repo copy is kept in sync.
Layout
crates/laser-dac/ vendorised laser-dac (the DAC abstraction + emulated Helios IDN
firmware and Ether Dream firmware; from ModulaserApp/laser-dac-rs)
tools/univsim/ the simulator binary (IDN server + GUI + Ether Dream source)
tools/univsim/src/ed_source.rs is the Ether Dream adapter: it drains the emulated
firmware's played points and republishes them as GUI events, rescaling to the stock
Ether Dream convention (+32767 = +1.0, Y up, 16-bit colours, blank = r=g=b=0).
Tests
cargo test -p univsim -- --test-threads=1
20 tests, 3 of them over real TCP sockets against the emulated Ether Dream firmware (streaming paced on buffer fullness, stream clock vs wall time, connect/disconnect).
Verified against real clients
talk3.py (j4c DAC client, 2011 lineage, Python 3) drives univsim end to end:
broadcast discovery, prepare → data → begin, 30 kpps streaming, and the square is
drawn with the expected colours on the expected sides (top red, right green,
bottom blue, left white).
Known issues
leaddrifts very negative in Ether Dream mode: the GUI anchors its playback clock at stream start, while the emulated DAC has already consumed minutes of stream. Needs re-anchoring on the first chunk (phase 5 in the devbook).
License
MIT — see LICENSE. crates/laser-dac is vendored from
ModulaserApp/laser-dac-rs (MIT).