libwing 1.0.5

A library for communicationg with the Behringer Wing Digital Mixer
Documentation
# libwing — Agent Guide

## What is this?

Rust library for discovering and controlling Behringer Wing digital mixing consoles over TCP/UDP. Published on crates.io as `libwing`. See SPEC.md for the full specification.

## Build & Run

```bash
cargo build                          # build library
cargo build --all-targets            # build library + all example tools
cargo build --example wingprop       # build a specific tool
cargo build --release                # optimized build
cargo test                           # run tests (requires no live hardware)
cargo doc --open                     # generate and view docs
```

The library produces both an `rlib` (Rust) and `cdylib` (C FFI shared library).

## Source Layout

```
src/
  lib.rs          — Public exports, Error enum, WingResponse enum
  console.rs      — WingConsole: connection, protocol encode/decode, read/write, meters, discovery
  node.rs         — WingNodeDef, WingNodeData, NodeType, NodeUnit — data model + serialization
  ffi.rs          — C FFI bindings (extern "C" functions, opaque handle types)
  propmap.rs      — Auto-generated: ~78k property name→def mappings (lazy_static HashMap)
  empty-propmap.rs — Stub propmap for smaller binaries when name lookups aren't needed
  propmap.jsonl   — JSON Lines reference of all property mappings

tools/
  wingprop.rs     — CLI: get/set individual properties
  wingmon.rs      — CLI: real-time property change monitor
  wingschema.rs   — CLI: regenerate propmap.rs + propmap.jsonl from a live device
  wingmeters.rs   — GUI: real-time channel meter display (eframe)
  utils.rs        — Shared helpers for CLI tools

libwing.h         — C API header
Discovery.md      — UDP discovery protocol notes
Wing-Remote-Protocols.pdf — Official Behringer protocol spec
```

## Property Map & Schema Generation

The Wing's native protocol only deals with numeric property IDs. To map human-readable names (like `/ch/1/fader`) to IDs, the library embeds a large static HashMap in `propmap.rs` — about 78k entries adding ~1MB to the binary and using a few MB of RAM when loaded. It's lazily initialized on first access (a few ms on a modern CPU).

If you don't need name lookups and want a smaller binary, copy `empty-propmap.rs` over `propmap.rs`. Note this will break some utility program functionality. You can also use `empty-propmap.rs` to recover if `propmap.rs` gets corrupted.

**The included `propmap.rs` was generated from a Wing Compact running firmware 3.0.5.**

### The dynamic nature of Wing properties

The Wing's property tree is **dynamic** — child nodes change depending on parent values. For example, if FX1 has type "NONE", `/fx/1` has only a few children. But loading an effect (e.g. setting type to "EXTERNAL") causes new properties like `/fx/1/trim` to appear.

The key dynamic property is `mdl` (model), found on FX slots, GATE slots, EQ slots, etc. Any node subtree containing a `mdl` StringEnum property will have different children depending on which model is selected.

### How wingschema handles dynamic properties

When `wingschema` encounters a `mdl` StringEnum, it:

1. Iterates through **every possible `mdl` value** in the enum
2. **Writes each value to the live device** (via `set_string`) to make those child properties appear
3. Queries the resulting child node schema for that model
4. Repeats for the next model value

This means running `wingschema` **destructively modifies your mixer's configuration**. The tool warns about this and requires typing "yes" to continue. You must save a snapshot beforehand and restore it after.

Only properties with a `mdl` StringEnum are known to be dynamic. If other dynamic properties are discovered, `wingschema` would need updating.

### Dynamic property paths in the propmap

Because of this `mdl` cycling, the property map contains paths for **all** possible models, even though only one model's properties exist on the device at any given time:
- `/fx/1/Chorus/rate` — properties specific to the Chorus FX model
- `/fx/1/Delay/time` — properties specific to the Delay FX model
- etc.

### Regenerating the propmap

Run `wingschema` against a live Wing device. It outputs two files:
- `propmap.rs` — copy to `src/` to update the library's built-in mapping
- `propmap.jsonl` — JSON Lines reference file for human inspection

## Key Concepts

- **Property tree**: The Wing exposes all parameters as a tree of nodes, each with a numeric ID and a path name (e.g. `/ch/1/fader`). The `propmap` maps names to IDs at compile time.
- **Blocking reads**: `read()` and `read_meters()` block until data arrives. Designed to be called from dedicated threads.
- **Unsolicited data**: The Wing pushes property changes whenever someone touches the physical mixer or another client writes a value. Your `read()` loop will see these interleaved with responses to your own requests.
- **Keep-alive**: Connections die if not kept alive. Call `keep_alive()` every ~7s for data, `keep_alive_meters()` every ~3s for meters.
- **Thread safety**: `WingConsole` is `Clone` and uses `Arc<Mutex>` internally. Separate threads for reading data, reading meters, and writing is the expected pattern.

## Protocol Quick Reference

The Wing supports 3 protocols: Native (binary), OSC, and Discovery. **libwing implements Native and Discovery only.** All three are documented in `Wing-Remote-Protocols.pdf` (by Patrick-Gilles Maillot, checked into this repo).

- TCP port 2222, binary protocol
- `0xdf` = message boundary / escape prefix; `0xde` = escape byte for literal `0xdf` in data
- `0xd1` = initial handshake byte sent on connect
- Property IDs are 32-bit integers encoded with the escape mechanism
- Discovery: UDP broadcast `"WING?"` to `255.255.255.255:2222`, response is CSV: `WING,ip,name,model,serial,firmware`

## Editing Guidelines

- `propmap.rs` is auto-generated by `wingschema` — don't edit by hand
- `ffi.rs` must stay in sync with `libwing.h` — update both together
- The protocol encoding/decoding in `console.rs` is subtle (escape sequences, channel state machine) — read carefully before modifying