Three kinds of call
Fire-and-forget, blocking query, no round-tripEvery Device method is one of three kinds. The API pages tag each method with a badge; this is what the three mean.
Fire-and-forget
Writes one frame, returns once the bytes are out, no reply.
device.move_rel(100, -50)?; // one frame out, no replyBlocks
Sends a QUERY and waits for the correlated RESP.
let v = device.query_version()?; // waits for the box to replyNo round-trip
Reads state the library already holds; can't fail on the link.
let c = device.counters(); // local snapshot, no networkWhy the queries are async
Queries await a reply, everything else fires and forgetsWith the async feature, the QUERY methods are the async fns, because a query blocks for its correlated RESP. Every other method is fire-and-forget, so it stays synchronous.
Async (you .await it) | Stays sync (no .await) |
|---|---|
query_version, query_health, device_info, caps, query_rate, query_stats, query_locks, query_catch, the option query_* methods, and the clip status query | move_rel, wheel, inject, press, release, force_release, reset, reboot, led, lock, unlock, catch_events, and the clip append / start / stop |
Driving futures without a runtime
futures::executor::block_onblock_on runs one future to completion on the current thread, so you can await a query with no async runtime at all.
use futures::executor::block_on;
let device = Device::find()?.into_async();
let v = block_on(device.query_version())?;
println!("{v}");When the box is silent
Default timeout and QueryTimeoutA query waits DEFAULT_QUERY_TIMEOUT (1 second), then returns Err(Error::QueryTimeout). This applies to both the sync and async queries.
match device.query_health() {
Ok(h) => println!("{h:?}"),
Err(medius::Error::QueryTimeout) => eprintln!("no reply in time"),
Err(e) => return Err(e),
}QueryTimeout means silence; NoReply means a reply arrived but didn't parse. Both are on the Errors page.
Smooth motion
Glide instead of teleportmove_rel applies one delta at once. For a glide rather than a jump, subdivide the move and pace the steps yourself, roughly one per millisecond. There's no move_smooth.
use std::thread::sleep;
use std::time::Duration;
// Glide ~400 counts to the right over 200 steps (~200 ms at 1 kHz).
for _ in 0..200 {
device.move_rel(2, 0)?;
sleep(Duration::from_millis(1));
}The library applies no rate limit. A no-sleep loop floods the 4 Mbaud link; pace your own steps.
Making a click
Press, wait, releaseThere's no one-shot click: press, wait, then release with release so you don't stomp a physical hold.
use std::{thread, time::Duration};
use medius::Button;
device.press(Button::Left)?;
thread::sleep(Duration::from_millis(20));
device.release(Button::Left)?;reset drops every override at once; a held press is re-asserted on reconnect via reapply.