A high-performance, scope-grade oscilloscope application in Rust, built on Bevy with a GPU digital-phosphor rendering pipeline and a modular acquisition-backend architecture. The first supported instrument is the OWON VDS1022 / VDS1022I USB oscilloscope, with a deterministic simulated backend for development and testing; SDR and other sources are on the roadmap.

.nwc capture files (zstd), import the vendor app's .cap recordings,
and export as WAV (16-bit PCM at the acquisition rate — an XY capture
is directly replayable oscilloscope music), CSV, raw i8, or a PNG of
the display.NEOWON_SCRIPT), including plot-texture screenshots
with regions of interest — the same mechanism the test suite uses.neowon-mcp server lets LLM clients (Claude, etc.) drive the scope and
see its display via PNG screenshots.assets/shaders/user/, pick it
live, hit Reload to iterate (kaleidoscope, signal-driven ripple, and a
heavy-CRT warp ship as examples).
Waterfall + 3D spectrogram terrain + the crt-warp user shader on a chirp.
A Lissajous figure with history as depth (viz xytime).
Oscilloscope Quake (--demo): E1M1, drawn by an audio waveform in XY mode.
| Instrument | Status |
|---|---|
| OWON VDS1022 / VDS1022I | Working, hardware-verified (25 MHz, 2 ch, 100 MS/s) |
| OWON VDS2052 | Untested; the driver's register-table design should make it a small port |
| RTL-SDR, Flipper Zero | Planned (see PLAN.md) |
The protocol implementation was ported from the community
OWON-VDS1022 Python reference
and the decompiled vendor app, then verified against real hardware —
including a few places where this repo's findings correct the reference
(see docs/protocol-vds1022.md).
Requires stable Rust (edition 2024; 1.95+).
cargo build --release
macOS: works out of the box (pure-Rust USB via nusb; no driver).
Linux: install Bevy's system deps (libasound2-dev libudev-dev on
Debian/Ubuntu) and install the shipped udev rules:
sudo cp scripts/99-vds1022.rules /etc/udev/rules.d/
sudo udevadm control --reload # then replug the scope
They grant USB access and stop the kernel's usb_serial_simple driver
from claiming the scope's interface (which otherwise makes
claim_interface fail with EBUSY). If a session is already wedged:
echo <bus>-<port>:1.0 | sudo tee /sys/bus/usb/drivers/usb_serial_simple/unbind (see
docs/protocol-vds1022.md).
Windows: untested; contributions welcome.
The VDS1022 needs an FPGA bitstream uploaded at every cold start. The
OWON bitstreams are vendored in 3rdparty/fw/ (see its
README for provenance — they are OWON's, not covered by this repo's
license), so a repo checkout works out of the box. neowon looks in
$NEOWON_FPGA_DIR, ./fwr, ./3rdparty/fw, then
../OWON-VDS1022/fwr.
cargo run --release -p neowon-app # real hardware
cargo run --release -p neowon-app -- --sim # simulated backend
cargo run --release -p neowon-app -- --demo # Oscilloscope Quake (see below)
Only one process may use the scope at a time — close the vendor app first.
--demo plays back the Oscilloscope Quake stereo WAVs from
lofibucket.com
in XY mode (left = X, right = Y) on a green CRT. Fetch the files first:
scripts/fetch-demo.sh
cargo run -p neowon-cli -- # `neowon` binary
probe | dump | stream | smoke | autoset
neowon smoke verifies the whole stack against the scope's own 1 kHz
probe-compensation signal.
Set NEOWON_SCRIPT=path.txt to drive the app from a plain-text action list
(stimulus selection, every control, screenshots, exports…). The full
grammar is documented at the top of crates/neowon-app/src/script.rs.
Set NEOWON_CONTROL=<port> and the app serves a line-oriented control
API on 127.0.0.1:<port>: any script action per line (acked with JSON),
plus get status / get config / get measure queries returning
structured JSON. Every external transport builds on this.
neowon-mcp is an MCP stdio server
over that socket, so an LLM client (Claude Code, Claude Desktop, …) can
drive the scope: configure channels/triggers, read the 18 automatic
measurements with statistics, run any script action, and take PNG
screenshots of the display returned as images the model can see.
# zero-setup demo: the server spawns the simulator itself
claude mcp add neowon -- ./target/release/neowon-mcp --spawn-sim
# or attach to a running app (real hardware or sim)
NEOWON_CONTROL=7777 cargo run --release -p neowon-app &
claude mcp add neowon -- ./target/release/neowon-mcp --connect 127.0.0.1:7777
cargo test # unit + virtual testbench
cargo test -p neowon-app --test ui_pixels -- --ignored # render geometry (opens a window)
cargo test -p neowon-app --test ui_layout -- --ignored # layout invariants
cargo test -p neowon-app --test capture_flows -- --ignored # capture/session flows
cargo test -p neowon-mcp --test mcp_e2e -- --ignored # MCP end-to-end
cargo run -p neowon-vds1022 --example trigtest # trigger matrix (needs hardware)
cargo test -p neowon-app --test shaders # naga-validate all WGSL
| Crate | Role |
|---|---|
neowon-core | Engine-free shared types, WAV I/O |
neowon-backend | Backend trait, config model, supervisor thread |
neowon-sim | Deterministic signal engine / virtual testbench source |
neowon-vds1022 | VDS1022 USB driver (nusb), protocol constants |
neowon-dsp | Measurements, statistics, FFT, math — the CPU oracle |
neowon-cli | Headless bring-up and debugging tool |
neowon-app | Bevy application: GPU pipeline, UI, scripting, control socket |
neowon-mcp | MCP server exposing the running scope to LLM clients |
PLAN.md holds the roadmap and phase status;
docs/protocol-vds1022.md records every hardware-verified protocol fact.
See CONTRIBUTING.md.
Licensed under either of Apache License 2.0 or MIT license at your option. The demo WAVs and FPGA bitstreams are third-party content and are not covered.
42 commits
Rust
97.5%
WGSL
2.4%
A high-performance, scope-grade oscilloscope application in Rust, built on Bevy with a GPU digital-phosphor rendering pipeline and a modular acquisition-backend architecture. The first supported instrument is the OWON VDS1022 / VDS1022I USB oscilloscope, with a deterministic simulated backend for development and testing; SDR and other sources are on the roadmap.

.nwc capture files (zstd), import the vendor app's .cap recordings,
and export as WAV (16-bit PCM at the acquisition rate — an XY capture
is directly replayable oscilloscope music), CSV, raw i8, or a PNG of
the display.NEOWON_SCRIPT), including plot-texture screenshots
with regions of interest — the same mechanism the test suite uses.neowon-mcp server lets LLM clients (Claude, etc.) drive the scope and
see its display via PNG screenshots.assets/shaders/user/, pick it
live, hit Reload to iterate (kaleidoscope, signal-driven ripple, and a
heavy-CRT warp ship as examples).
Waterfall + 3D spectrogram terrain + the crt-warp user shader on a chirp.
A Lissajous figure with history as depth (viz xytime).
Oscilloscope Quake (--demo): E1M1, drawn by an audio waveform in XY mode.
| Instrument | Status |
|---|---|
| OWON VDS1022 / VDS1022I | Working, hardware-verified (25 MHz, 2 ch, 100 MS/s) |
| OWON VDS2052 | Untested; the driver's register-table design should make it a small port |
| RTL-SDR, Flipper Zero | Planned (see PLAN.md) |
The protocol implementation was ported from the community
OWON-VDS1022 Python reference
and the decompiled vendor app, then verified against real hardware —
including a few places where this repo's findings correct the reference
(see docs/protocol-vds1022.md).
Requires stable Rust (edition 2024; 1.95+).
cargo build --release
macOS: works out of the box (pure-Rust USB via nusb; no driver).
Linux: install Bevy's system deps (libasound2-dev libudev-dev on
Debian/Ubuntu) and install the shipped udev rules:
sudo cp scripts/99-vds1022.rules /etc/udev/rules.d/
sudo udevadm control --reload # then replug the scope
They grant USB access and stop the kernel's usb_serial_simple driver
from claiming the scope's interface (which otherwise makes
claim_interface fail with EBUSY). If a session is already wedged:
echo <bus>-<port>:1.0 | sudo tee /sys/bus/usb/drivers/usb_serial_simple/unbind (see
docs/protocol-vds1022.md).
Windows: untested; contributions welcome.
The VDS1022 needs an FPGA bitstream uploaded at every cold start. The
OWON bitstreams are vendored in 3rdparty/fw/ (see its
README for provenance — they are OWON's, not covered by this repo's
license), so a repo checkout works out of the box. neowon looks in
$NEOWON_FPGA_DIR, ./fwr, ./3rdparty/fw, then
../OWON-VDS1022/fwr.
cargo run --release -p neowon-app # real hardware
cargo run --release -p neowon-app -- --sim # simulated backend
cargo run --release -p neowon-app -- --demo # Oscilloscope Quake (see below)
Only one process may use the scope at a time — close the vendor app first.
--demo plays back the Oscilloscope Quake stereo WAVs from
lofibucket.com
in XY mode (left = X, right = Y) on a green CRT. Fetch the files first:
scripts/fetch-demo.sh
cargo run -p neowon-cli -- # `neowon` binary
probe | dump | stream | smoke | autoset
neowon smoke verifies the whole stack against the scope's own 1 kHz
probe-compensation signal.
Set NEOWON_SCRIPT=path.txt to drive the app from a plain-text action list
(stimulus selection, every control, screenshots, exports…). The full
grammar is documented at the top of crates/neowon-app/src/script.rs.
Set NEOWON_CONTROL=<port> and the app serves a line-oriented control
API on 127.0.0.1:<port>: any script action per line (acked with JSON),
plus get status / get config / get measure queries returning
structured JSON. Every external transport builds on this.
neowon-mcp is an MCP stdio server
over that socket, so an LLM client (Claude Code, Claude Desktop, …) can
drive the scope: configure channels/triggers, read the 18 automatic
measurements with statistics, run any script action, and take PNG
screenshots of the display returned as images the model can see.
# zero-setup demo: the server spawns the simulator itself
claude mcp add neowon -- ./target/release/neowon-mcp --spawn-sim
# or attach to a running app (real hardware or sim)
NEOWON_CONTROL=7777 cargo run --release -p neowon-app &
claude mcp add neowon -- ./target/release/neowon-mcp --connect 127.0.0.1:7777
cargo test # unit + virtual testbench
cargo test -p neowon-app --test ui_pixels -- --ignored # render geometry (opens a window)
cargo test -p neowon-app --test ui_layout -- --ignored # layout invariants
cargo test -p neowon-app --test capture_flows -- --ignored # capture/session flows
cargo test -p neowon-mcp --test mcp_e2e -- --ignored # MCP end-to-end
cargo run -p neowon-vds1022 --example trigtest # trigger matrix (needs hardware)
cargo test -p neowon-app --test shaders # naga-validate all WGSL
| Crate | Role |
|---|---|
neowon-core | Engine-free shared types, WAV I/O |
neowon-backend | Backend trait, config model, supervisor thread |
neowon-sim | Deterministic signal engine / virtual testbench source |
neowon-vds1022 | VDS1022 USB driver (nusb), protocol constants |
neowon-dsp | Measurements, statistics, FFT, math — the CPU oracle |
neowon-cli | Headless bring-up and debugging tool |
neowon-app | Bevy application: GPU pipeline, UI, scripting, control socket |
neowon-mcp | MCP server exposing the running scope to LLM clients |
PLAN.md holds the roadmap and phase status;
docs/protocol-vds1022.md records every hardware-verified protocol fact.
See CONTRIBUTING.md.
Licensed under either of Apache License 2.0 or MIT license at your option. The demo WAVs and FPGA bitstreams are third-party content and are not covered.
42 commits
Rust
97.5%
WGSL
2.4%