Repository navigation
Library
Kaled Corona edited this page Sep 1, 2026
·
1 revision
Two verbs carry everything. Named accessors are one line over them.
use bose_connect::api::Anc;
use bose_connect::catalog::{BATTERY, VOLUME};
use bose_connect::codec::Level;
use bose_connect::device::Device;
use bose_connect::transport::{connect, Address};
use std::time::Duration;
let addr: Address = "AA:BB:CC:00:00:01".parse()?;
let (_channel, session) = connect(addr, Duration::from_secs(4))?;
let mut dev = Device::open(session)?;
// By name, or straight from the catalog — the same code path.
let cells = dev.battery()?;
let vol = dev.get(&VOLUME)?;
dev.set(&VOLUME, 8)?;
match dev.noise_cancelling()? {
Anc::Named(a) if a.accepts(Level::Low) => dev.set_level(Level::Low)?,
Anc::Named(_) => {}
Anc::Graded(a) => println!("cancelling {} of {}", a.cancelling(), a.top()),
}One direction, each knowing only the one below:
transport bytes
session bytes → records, one exchange
wire records ↔ payloads
codec payloads ↔ values
catalog which value lives where, and how well we know it
surface which of those this device answers
device get / set — the only two verbs
api names for the verbs
Transport is a trait, so the protocol can be driven from recorded traffic
instead of a socket. src/fixtures.rs holds three devices across two generations
as data, which is how the tests cover both without either device present. Build
with --features mock to use them from your own tests.
A request gets a reply, a refusal, or nothing at all, and the three are different:
| behaviour | Error |
|---|---|
| a value | — |
04 + 03 / 04
|
Refused, or Absent if the surface knew already |
| silence | Silent |
Reading silence as "busy" invites a retry loop against an opcode that will never answer; reading it as "unsupported" throws away the refusal codes, which are the only signal for whether a function is worth probing further.