Medius - Rust LibraryCalls & input

Three kinds of call

Fire-and-forget, blocking query, no round-trip

Every 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.

EXAMPLE
device.move_rel(100, -50)?; // one frame out, no reply

Blocks

Sends a QUERY and waits for the correlated RESP.

EXAMPLE
let v = device.query_version()?; // waits for the box to reply

No round-trip

Reads state the library already holds; can't fail on the link.

EXAMPLE
let c = device.counters(); // local snapshot, no network

Why the queries are async

Queries await a reply, everything else fires and forgets

With 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.

METHOD SPLIT
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 querymove_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_on

block_on runs one future to completion on the current thread, so you can await a query with no async runtime at all.

EXAMPLE
use futures::executor::block_on;

let device = Device::find()?.into_async();
let v = block_on(device.query_version())?;
println!("{v}");

Inside an async main, .await the same future instead; it runs unchanged under tokio, async-std, or smol.

When the box is silent

Default timeout and QueryTimeout

A query waits DEFAULT_QUERY_TIMEOUT (1 second), then returns Err(Error::QueryTimeout). This applies to both the sync and async queries.

EXAMPLE
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 teleport

move_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.

EXAMPLE
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, release

There's no one-shot click: press, wait, then release with release so you don't stomp a physical hold.

EXAMPLE
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.