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 bumps the reference count and 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 live Device holds your overrides past that on its own: a background thread (medius-keepalive) sends a QUERY(HEALTH) every DEFAULT_KEEPALIVE_CADENCE (500 ms) while anything is held, so a press survives. 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 tears the connection down. Its Drop stops the threads and closes the port.

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.

For immediate hand-off call reset before drop.

EXAMPLE
// hand the mouse back right now, not a second from now:
device.reset()?;   // box returns to passthrough immediately
drop(device);      // tears down threads and closes the port