Medius - Rust LibraryConnection

Choosing a port

When more than one box is plugged in

find grabs the first match. With more than one box, find_medius lists every match as a PortInfo (path, vid, pid) without opening, then open the chosen one.

EXAMPLE
use medius::{Device, find_medius};

let ports = find_medius();
for port in &ports {
    println!("{} (vid={:#06x} pid={:#06x})", port.path, port.vid, port.pid);
}

// open a chosen one (here, the first):
let port = ports.first().ok_or(medius::Error::NotFound)?;
let dev = Device::open(&port.path)?;

Threading and Clone

Share one connection across threads

Device is Send + Sync and clones cheaply (an Arc inside), so one connection serves any number of threads; a clone doesn't reopen the port.

EXAMPLE
use std::thread;

let worker = device.clone();
let handle = thread::spawn(move || {
    worker.move_rel(10, 0)
});
handle.join().unwrap()?;

Running queries concurrently

join and cloning across tasks

AsyncDevice clones the same way, so hand a clone to another task and await both queries together with futures::future::join.

EXAMPLE
let (v, h) = futures::future::join(
    device.query_version(),
    device.query_health(),
).await;
let v = v?;
let h = h?;
println!("{v}, link_up={}", h.link_up);

Only the queries need .await; mutators stay synchronous on either handle.

Keepalive and holds

Holding injected input past the silence window

The box clears every injected input and pending move once no frame arrives for its silence window.

A Device holds your overrides past that itself: a background thread (medius-keepalive) sends a QUERY(HEALTH) every DEFAULT_KEEPALIVE_CADENCE (500 ms) while anything is held. There's no keepalive() to call.

StateBehavior
Override heldKeepalive thread runs; the health reply is dropped.
IdleNo override held, so the thread sends nothing.
EXAMPLE
device.press(Button::Left)?;

// No further calls. The keepalive thread sends QUERY(HEALTH) on its own,
// so the hold survives well past the 1000 ms silence window.
std::thread::sleep(std::time::Duration::from_secs(5));

device.reset()?;

An override is the box holding an input down or up itself, set by press or force_release; the library keeps a copy. After a dropped link, reapply and reconnect restore it.

Releasing the device

Drop it; no close() call

There's no close: dropping the last Arc-backed handle runs its Drop and tears the connection down.

StepWhat drop does
SignalSets the stop flag the reader and keepalive threads watch.
JoinWaits for both threads to exit, so none are left running.
CloseReleases the serial port as the transport drops.

To return the box to passthrough at once, call reset before drop.

EXAMPLE
// back to passthrough now, not after the silence window:
device.reset()?;   // box returns to passthrough immediately
drop(device);      // tears down threads and closes the port