Skip to content

Library

Kaled Corona edited this page Sep 1, 2026 · 1 revision

Using bose-connect as a library

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()),
}

Layers

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.

Three answers, not two

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.

Clone this wiki locally