Medius - Rust LibraryDiscovery

Discovery

Find and open one box out of several

With more than one box plugged in, find just opens the first match. These calls enumerate every box and open a specific one by a stable identity, or by the kind of device it clones.

See also: connecting, choosing a port, and the box handshake.

list

Enumerate every connected box
fn list() -> Vec<BoxInfo>

Blocks

Opens each connected box in turn, handshakes, reads its Version (with the box MAC and name) and cloned DeviceInfo, then closes it, returning one BoxInfo per box. Use it to show a picker, or to choose a box yourself.

EXAMPLE
use medius::Device;

for b in Device::list() {
    // id() is the box MAC hex; name() is its readable label; b.device displays as "VVVV:PPPP product".
    println!("{}  {}  {}  {}", b.id(), b.name(), b.device, b.port.path);
}

open_by_id

Open the box with a given identity
fn open_by_id(id: &str) -> Result<Device>

Blocks

Opens the box whose identity matches id: either the device MAC hex (from Version::mac_hex) or the CH343 serial. Returns Error::NotFound when no connected box matches.

EXAMPLE
use medius::Device;

// the MAC hex printed by Device::list(), stable across replugs:
let device = Device::open_by_id("123456789abc")?;

find_mouse_box

Open the first box cloning a mouse
fn find_mouse_box() -> Result<Device>

Blocks

Opens the first box whose clone's DeviceKind is a mouse. Handy when one box clones a mouse and another a keyboard: it grabs the right one without naming an id. Returns Error::NotFound if no connected box matches.

EXAMPLE
use medius::Device;

let mouse_box = Device::find_mouse_box()?;
mouse_box.move_rel(10, 0)?;

find_keyboard_box

Open the first box cloning a keyboard
fn find_keyboard_box() -> Result<Device>

Blocks

The keyboard counterpart of find_mouse_box: opens the first box whose clone is a keyboard.

EXAMPLE
use medius::{Device, Key};

let kbd_box = Device::find_keyboard_box()?;
kbd_box.press(Key::A)?;

find_where

Open the first box matching a predicate
fn find_where(pred: impl Fn(&BoxInfo) -> bool) -> Result<Device>

Blocks

The general form the find_*_box helpers build on: opens the first box whose BoxInfo satisfies pred. Match on any field, e.g. a specific vendor id or product string. Returns Error::NotFound when none match.

EXAMPLE
use medius::Device;

// the box cloning a Logitech device:
let device = Device::find_where(|b| b.device.vid == 0x046D)?;

BoxInfo

One discovered box

One entry from Device::list (and the valuefind_where's predicate sees): the box's control port, firmware version, and the device it clones.

FieldTypeMeaning
portPortInfoThe control port (path + CH343 serial).
versionVersionThe firmware version, with the box MAC and name.
deviceDeviceInfoThe device it clones.
MethodReturnsMeaning
id()StringThe box identity: the MAC hex, as passed to open_by_id.
name()&strThe box's human-readable name (from version.name), a display label rather than an opener key.
serial()Option<&str>The CH343 adapter's serial, when it has one.

Identity & reconnect

The same physical box, across replugs

A box has a stable identity: the device chip's base MAC (from Version::mac_hex) and the CH343 adapter's serial. Serial-port paths renumber when you replug, but the identity does not, so open_by_id re-finds the same box every time.

Opening a box anchors reconnect to that identity. An automatic reconnect re-finds the same physical box even if the ports renumbered, and never adopts a different box that happens to be plugged in.

The readable partner to that MAC is the box's name (from Version::name), a display label for telling boxes apart, not an opener key.

On AsyncDevice

The same discovery, awaitable device_info
fn AsyncDevice::list() -> Vec<BoxInfo>
fn AsyncDevice::open_by_id(id: &str) -> Result<AsyncDevice>
fn AsyncDevice::find_mouse_box() -> Result<AsyncDevice>
fn AsyncDevice::find_keyboard_box() -> Result<AsyncDevice>

Blocks

AsyncDevice mirrors the discovery constructors; they block on the per-box handshake, like their Device counterparts. The reply-reading device_info query is the awaitable part.

use medius::AsyncDevice;

let device = AsyncDevice::find_mouse_box()?; // blocks on the handshake
let info = futures::executor::block_on(device.device_info())?; // awaits the reply