<!-- Source: https://medius.k4tech.net/library/requests -->
# Requests

_Asking the box a question and waiting for the answer_

Unlike [fire-and-forget](/native/injection.md#fire-and-forget), the queries are blocking: a question frame out, one answer frame back. They are [`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), each covered below. The [clip handle](/library/clip.md#handle) adds [`query_status`](/library/requests.md#clip-status) and [`query_config`](/library/requests.md#clip-config), also here.

## query_version

_Firmware identity, round-trip_

```text
fn query_version(&self) -> Result<Version>
```

_Blocks_

Returns a [`Version`](/library/types/structs.md#version). The box's [name](/library/options.md#set-name) rides on it, in the `name` field.

#### EXAMPLE

```rust
use medius::Device;

let device = Device::find()?;          // or Device::open("/dev/ttyACM0")?
let v = device.query_version()?;
println!("{v}");                       // fw 3.0.0
println!("proto {}", v.proto_ver);     // proto 3
println!("name {}", v.name);           // Loki
```

> **Note**
>
> [`Device::find()`](/library/connection.md#open) already runs a version query during the handshake; calling `query_version` again just re-reads it.

## query_health

_Is the mouse-to-box-to-PC chain live_

```text
fn query_health(&self) -> Result<Health>
```

_Blocks_

Returns a [`Health`](/library/types/structs.md#health), eight booleans from one status byte. `link_up`, `mouse_attached`, and `clone_configured` must all be true before [injection](/native/injection.md) has anywhere to land.

#### EXAMPLE

```rust
use medius::Device;

let device = Device::find()?;
let h = device.query_health()?;
if h.link_up && h.mouse_attached && h.clone_configured {
    // chain is live, safe to inject
} else {
    eprintln!("not ready: {h:?}");
}
```

## device_info

_USB identity, kind, and product of the clone_

```text
fn device_info(&self) -> Result<DeviceInfo>
```

_Blocks_

Returns a [`DeviceInfo`](/library/types/structs.md#device-info): the `vid`, `pid`, USB version, a [`DeviceKind`](/library/types/enums.md#device-kind), and the `product` string the box read off the real device. The clone sits on the game PC's bus, so this is the only way to see it from the control link. Every field is zero/empty when nothing is cloned. `Display` prints `VVVV:PPPP product`.

#### EXAMPLE

```rust
use medius::{Device, DeviceKind};

let device = Device::find()?;
let d = device.device_info()?;
if d.vid == 0 {
    eprintln!("nothing cloned yet");
} else {
    println!("{d}");                    // 046D:C08B G502
    println!("usb {:#06x}", d.bcd_usb);
    println!("kind={} serial={} bos={}", d.kind, d.has_serial, d.has_bos);
    if d.kind == DeviceKind::Mouse {
        // the clone is a mouse
    }
}
```

## caps

_Feature-detect the whole device_

```text
fn caps(&self) -> Result<Caps>
```

_Blocks_

One query describes the whole cloned device. Returns a [`Caps`](/library/types/structs.md#caps) with a [`mouse`](/library/types/structs.md#mouse-caps) half and a [`keyboard`](/library/types/structs.md#kbd-caps) half, plus the per-class change-driven flags. Use it for feature detection: an [`inject`](/library/inject.md#inject) for a usage the device lacks is a silent no-op, so the counts tell you what is real. A class that is not present reads all-zero; `has_mouse()` and `has_keyboard()` say which are bound.

#### EXAMPLE

```rust
use medius::Device;

let device = Device::find()?;
let caps = device.caps()?;
println!("{} buttons", caps.mouse.n_buttons);
if caps.mouse.has_wheel {
    device.wheel(1)?;
}
if caps.has_keyboard() && caps.keyboard.has_consumer {
    device.press(medius::MediaKey::MUTE)?;
}
```

## query_rate

_Read the live native report rate_

```text
fn query_rate(&self) -> Result<Rate>
```

_Blocks_

Returns a [`Rate`](/library/types/structs.md#rate). `native_hz()` converts the period to a frequency, returning `None` while `native_period_us` is still `0` (not learned yet). `confident` is true once the estimator window is full and the value is trustworthy.

#### EXAMPLE

```rust
use medius::Device;

let device = Device::find()?;
let r = device.query_rate()?;
match r.native_hz() {
    Some(hz) if r.confident => println!("{hz:.0} Hz"),
    Some(hz)                => println!("{hz:.0} Hz (still settling)"),
    None                    => println!("rate not learned yet"),
}
```

## query_stats

_Read the delivery counters_

```text
fn query_stats(&self) -> Result<Stats>
```

_Blocks_

Returns a [`Stats`](/library/types/structs.md#stats). `inject_emits` counts pure-injection reports emitted; a nonzero `tx_drops` or `tx_wedges` is the signal that delivery degraded under load. The narrowed counters saturate, so a maxed field clamps instead of wrapping.

#### EXAMPLE

```rust
use medius::Device;

let device = Device::find()?;
let s = device.query_stats()?;
println!("{} emits", s.inject_emits);
if s.tx_drops > 0 || s.tx_wedges > 0 {
    eprintln!("delivery degraded: {} drops, {} wedges", s.tx_drops, s.tx_wedges);
}
```

## query_locks

_Read the active input locks_

```text
fn query_locks(&self) -> Result<Locks>
```

_Blocks_

Returns a [`Locks`](/library/types/structs.md#locks), the list of inputs currently blocked by [`lock`](/library/lock.md#lock). `entries()` walks them and `is_locked(target, direction)` answers whether one particular lock is set. Read it to confirm a lock landed, or to mirror the box's lock state in a UI.

#### EXAMPLE

```rust
use medius::{Device, Axis, LockDirection};

let device = Device::find()?;
let locks = device.query_locks()?;
if locks.is_locked(Axis::X, LockDirection::Both) {
    println!("horizontal motion is frozen");
}
```

## query_catch

_Read the active catch subscription_

```text
fn query_catch(&self) -> Result<CatchState>
```

_Blocks_

Returns a [`CatchState`](/library/types/structs.md#catch-state): the `mask` currently streaming via [`catch_events`](/library/catch.md#catch-events), plus `dropped`, the box-side count of events shed under back-pressure. Read it after subscribing to confirm the mask took, or to reflect the live catch mask in your own UI.

#### EXAMPLE

```rust
use medius::Device;

let device = Device::find()?;
let c = device.query_catch()?;
if !c.mask.is_empty() {
    println!("catching {:?}, {} dropped", c.mask, c.dropped);
}
```

## query_status (clip)

_Read the buffered-clip ring depth, progress, and playback state_

```text
fn query_status(&self) -> Result<ClipStatus>
```

_Blocks_

On the [`ClipHandle`](/library/clip.md#handle) from [`device.clip()`](/library/clip.md#clip), not `Device` itself. Returns a [`ClipStatus`](/library/types/structs.md#clip-status): `state`, ring `free`, retained `played`/`total`, the drain counters, and the `held` usages. Pace clip top-ups off `free`, and watch `state` for a [`Faulted`](/library/types/enums.md#clip-state) re-sync or for playback reaching `Idle`. Backs [`QUERY(CLIP)`](/native/commands/requests.md#clip).

#### EXAMPLE

```rust
use medius::Device;

let device = Device::find()?;
let clip = device.clip();
let s = clip.query_status()?;
if s.state == medius::ClipState::Faulted { clip.clear()?; }
println!("{} free, {} played", s.free, s.played);
```

## query_config (clip)

_Read the whole clip config back_

```text
fn query_config(&self) -> Result<ClipSettings>
```

_Blocks_

The config view of the same [`QUERY(CLIP)`](/native/commands/requests.md#clip) frame [`query_status`](/library/requests.md#clip-status) reads, also on the [`ClipHandle`](/library/clip.md#handle). Returns a [`ClipSettings`](/library/types/structs.md#clip-settings) with the auto-lock, loop, retain, finalized flag, and [triggers](/library/clip.md#triggers) you set; nothing is write-only, every setting round-trips.

#### EXAMPLE

```rust
use medius::Device;

let device = Device::find()?;
let cfg = device.clip().query_config()?;
println!("{} triggers, loop={}", cfg.triggers.len(), cfg.loop_);
```

## Async queries

_The same queries on AsyncDevice_

```text
async fn query_version(&self) -> Result<Version>
```

```text
async fn query_health(&self) -> Result<Health>
```

```text
async fn device_info(&self) -> Result<DeviceInfo>
```

```text
async fn caps(&self) -> Result<Caps>
```

```text
async fn query_rate(&self) -> Result<Rate>
```

```text
async fn query_stats(&self) -> Result<Stats>
```

```text
async fn query_locks(&self) -> Result<Locks>
```

```text
async fn query_catch(&self) -> Result<CatchState>
```

_Blocks_

```bash
cargo add medius --features async
```

With the `async` feature, `Device::into_async()` yields an [`AsyncDevice`](/library/features/async.md) whose queries are futures; other methods stay synchronous. The crate is runtime-agnostic (no tokio), so drive a future with anything, such as [`futures::executor::block_on`](https://docs.rs/futures/latest/futures/executor/fn.block_on.html).

#### EXAMPLE

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

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