<!-- Source: https://medius.k4tech.net/library/guides/calls -->
# Three kinds of call

_Fire-and-forget, blocking query, no round-trip_

Every [`Device`](/library/connection.md) method is one of three kinds. The [API pages](/library.md) 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

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

_Blocks_

Sends a [`QUERY`](/native/commands/requests.md#requests) and waits for the correlated [`RESP`](/native/commands/requests.md#resp).

#### EXAMPLE

```rust
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

```rust
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`](/library/features/async.md) feature, the [`QUERY`](/native/commands/requests.md#requests) methods are the `async fn`s, because a query blocks for its correlated [`RESP`](/native/commands/requests.md#resp). Every other method is [fire-and-forget](/native/injection.md#fire-and-forget), so it stays synchronous.

#### METHOD SPLIT

| Async (you `.await` it) | Stays sync (no `.await`) |
| --- | --- |
| [`query_version`](/library/requests.md#version), [`query_health`](/library/requests.md#health), [`device_info`](/library/requests.md#device-info), [`caps`](/library/requests.md#caps), [`query_rate`](/library/requests.md#query-rate), [`query_stats`](/library/requests.md#query-stats), [`query_locks`](/library/requests.md#query-locks), [`query_catch`](/library/requests.md#query-catch), the option `query_*` methods, and the clip [`status`](/library/requests.md#clip-status) query | [`move_rel`](/library/move.md#move-rel), [`wheel`](/library/move.md#wheel), [`inject`](/library/inject.md#inject), [`press`](/library/inject.md#inject), [`release`](/library/inject.md#inject), [`force_release`](/library/inject.md#inject), [`reset`](/library/admin.md#reset), [`reboot`](/library/admin.md#reboot), [`led`](/library/led.md#led), [`lock`](/library/lock.md#lock), [`unlock`](/library/lock.md#unlock), [`catch_events`](/library/catch.md#catch-events), and the clip [`append`](/library/clip.md#handle) / [`start`](/library/clip.md#handle) / [`stop`](/library/clip.md#handle) |

## Driving futures without a runtime

_futures::executor::block_on_

[`block_on`](https://docs.rs/futures/latest/futures/executor/fn.block_on.html) runs one future to completion on the current thread, so you can await a query with no async runtime at all.

#### EXAMPLE

```rust
use futures::executor::block_on;

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

> **Note**
>
> Inside an async `main`, `.await` the same future instead; it runs unchanged under [`tokio`](https://tokio.rs), [`async-std`](https://crates.io/crates/async-std), or [`smol`](https://crates.io/crates/smol).

## When the box is silent

_Default timeout and QueryTimeout_

A query waits [`DEFAULT_QUERY_TIMEOUT`](/library/connection.md#zero-config) (1 second), then returns `Err(Error::QueryTimeout)`. This applies to both the sync and async queries.

#### EXAMPLE

```rust
match device.query_health() {
    Ok(h) => println!("{h:?}"),
    Err(medius::Error::QueryTimeout) => eprintln!("no reply in time"),
    Err(e) => return Err(e),
}
```

> **Note**
>
> `QueryTimeout` means silence; `NoReply` means a reply arrived but didn't parse. Both are on the [Errors](/library/types/errors.md) page.

## Smooth motion

_Glide instead of teleport_

[`move_rel`](/library/move.md#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

```rust
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));
}
```

> **Warning**
>
> 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`](/library/inject.md#inject), wait, then release with [`release`](/library/inject.md#inject) so you don't stomp a physical hold.

#### EXAMPLE

```rust
use std::{thread, time::Duration};
use medius::Button;

device.press(Button::Left)?;
thread::sleep(Duration::from_millis(20));
device.release(Button::Left)?;
```

[`reset`](/library/admin.md#reset) drops every override at once; a held press is re-asserted on reconnect via [`reapply`](/library/lifecycle.md#reapply).
