Medius - BindingsAPI index

API index

Every C function, linked to what it does

The whole medius_* surface from medius.h, grouped. The semantics live in the Rust library (the medius crate) and the Native API. Structs, enums, and constants are on Types & errors; streams on Streams.

Most calls are fire-and-forget: they return once the frame is queued, without waiting on the box. The queries, plus open / find, block for the box's reply.

Every fallible call returns a MediusStatus (MEDIUS_STATUS_OK is 0) and writes its result through an out-param; medius_last_error_message() gives the last failure's text on the calling thread.

CALLING CONVENTION
MediusDevice *dev = NULL;
if (medius_device_find(&dev) != MEDIUS_STATUS_OK) {
    char buf[256];
    medius_last_error_message(buf, sizeof buf);   /* why it failed */
    return 1;
}
MediusVersion v;
medius_device_query_version(dev, &v);             /* result written to &v */
medius_device_free(dev);

Opaque handles (MediusDevice, MediusEventStream, MediusInputStream, MediusTimeline, MediusLogStream, MediusMockBox) are yours to free, each with its own *_free.

Catch events and log lines are fixed-size structs, so there's nothing to free per event. A MediusTrafficEvent holds its payload in an inline bytes[MEDIUS_MAX_TRAFFIC_BYTES] array, not a pointer, so a copied event stays valid and owns nothing.

Connecting & lifecycle

Open, share, and release the link

See Connection and Lifecycle.

FunctionDoes
medius_device_open(const char *path, MediusDevice **out)Open a serial path and handshake.
medius_device_find(MediusDevice **out)Open the first box found by USB id.
medius_device_clone(const MediusDevice *dev)Another handle to the same link (ref-counted); returns MediusDevice *. Null in → null out.
medius_device_free(MediusDevice *dev)Free a handle; joins the reader/keepalive threads when the last clone drops. Null is a no-op.
medius_find_ports(MediusPortInfo *out, uintptr_t cap, uintptr_t *out_total)List present ports into out (up to cap); writes total to *out_total, returns the number written. See MediusPortInfo.

Discovery

Enumerate boxes and open one by identity

Pick a box out of several by a stable identity (device MAC or CH343 serial), or by the kind of device it clones. See Discovery.

FunctionDoes
medius_list(MediusBoxInfo *out, uintptr_t cap, uintptr_t *out_total)Enumerate every connected box into out (up to cap): opens, handshakes, and reads each one's version + cloned-device info. Writes the total to *out_total, returns the number written. See MediusBoxInfo.
medius_device_open_by_id(const char *id, MediusDevice **out)Open the box whose identity matches id (device MAC hex or CH343 serial) and handshake.
medius_device_find_mouse_box(MediusDevice **out)Open the first box whose clone is a mouse.
medius_device_find_keyboard_box(MediusDevice **out)Open the first box whose clone is a keyboard.

Movement

Relative cursor and wheel

See Move. +x right, +y down. Build the axis struct with the motion helpers.

FunctionDoes
medius_device_move_rel(MediusDevice *dev, int16_t dx, int16_t dy)Nudge the cursor by a signed 16-bit delta.
medius_device_wheel(MediusDevice *dev, int16_t delta)Scroll the wheel.
medius_device_move_rel_now(MediusDevice *dev, int16_t dx, int16_t dy)The same, bypassing movement riding.
medius_device_wheel_now(MediusDevice *dev, int16_t delta)Scroll, bypassing movement riding.
medius_device_flush_motion(MediusDevice *dev)Emit the motion riding is holding, now.
medius_device_discard_motion(MediusDevice *dev)Drop the motion riding is holding.
medius_device_move_axis(MediusDevice *dev, MediusMotion motion, MediusMoveTiming timing, MediusPendingMotion pending)Drive one axis from a medius_motion_cursor(...) or medius_motion_wheel(...).

Inject

Drive any usage: button, key, or media

One verb set over a MediusUsage (button, key, or media). Build it with the input helpers; see Inject, the injection model, and the id spaces on Usage IDs.

FunctionDoes
medius_device_inject(MediusDevice *dev, MediusUsage input, MediusAction action)Apply a MediusAction to a usage.
medius_device_press(MediusDevice *dev, MediusUsage input)Hold the usage down (MEDIUS_ACTION_PRESS).
medius_device_soft_release(MediusDevice *dev, MediusUsage input)Release, unless the user is physically holding it.
medius_device_force_release(MediusDevice *dev, MediusUsage input)Release even against a physical hold.

A MediusKey or MediusMediaKey is a raw HID usage.

Locks

Weigh the user's own input

See Lock. A MediusLockTarget picks an axis or usage, dir takes a MediusDirection constant and what a MediusBlanket one; anything else is MEDIUS_STATUS_ERR_INVALID_ARG and no frame goes out. Read the entries back with medius_locks_scale_of and medius_locks_is_locked.

FunctionDoes
medius_device_scale(MediusDevice *dev, MediusLockTarget target, uint8_t dir, uint8_t scale)Keep scale percent of an axis or usage on one direction: MEDIUS_LOCK_SCALE_BLOCK (0), _PASS (100), up to _MAX (255).
medius_device_scale_all(MediusDevice *dev, uint8_t what, uint8_t dir, uint8_t scale)The same over a whole class (aim, wheel, buttons, keys, or media).
medius_device_lock(MediusDevice *dev, MediusLockTarget target, uint8_t dir)Block an axis or usage on a direction: scale 0.
medius_device_unlock(MediusDevice *dev, MediusLockTarget target, uint8_t dir)Back to passing untouched: scale 100.
medius_device_lock_all(MediusDevice *dev, uint8_t what, uint8_t dir)Blanket block a whole class.
medius_device_unlock_all(MediusDevice *dev, uint8_t what, uint8_t dir)Release a blanket block.

A scale auto-clears; it isn't permanent. The keepalive holds it for you. MEDIUS_DIRECTION_WITH and _AGAINST need a live bearing, set with medius_device_set_bearing; the refusal rules for them are on MediusDirection.

LED, admin & options

Status light, resets, persistent settings
FunctionDoes
medius_device_led(MediusDevice *dev, MediusLedTarget target, MediusLedMode mode, uint8_t level)Drive the status LED. See LED.
medius_device_reset(MediusDevice *dev)Clear all overrides. See Admin.
medius_device_reapply(MediusDevice *dev)Re-send the active settings.
medius_device_reconnect(MediusDevice *dev)Force a reconnect to the mouse.
medius_device_reboot(MediusDevice *dev, MediusRebootTarget target)Reboot a chip to run or download mode.
medius_device_allow_imperfect_clones(MediusDevice *dev, bool allow)Opt in to cloning over-capacity devices. See Options.
medius_device_set_movement_riding(MediusDevice *dev, bool enabled, uint32_t window_ms)Set movement riding; enabled == false clears the window (rounded to whole ms).
medius_device_set_bearing(MediusDevice *dev, uint16_t window_ms, uint8_t mode)Set what MEDIUS_DIRECTION_WITH / _AGAINST are measured against; window_ms == 0 turns it off.
medius_device_set_emit_pace(MediusDevice *dev, uint8_t mode, uint16_t hz, uint16_t force_hz)Pick what paces injected motion (hz is the target rate for FIXED) and what rate the clone advertises (force_hz, 0 = the device's own). See Options.
medius_device_set_name(MediusDevice *dev, const char *name)Set the box's human-readable name (1 to 32 printable ASCII). See Name.
medius_device_clear_name(MediusDevice *dev)Clear the name, back to the synthesized default. Read it back on MediusVersion.name.

Queries

Read box state; each blocks for one reply

See Requests. Each blocks for the box's reply, writes a struct documented on Types & errors, and returns MEDIUS_STATUS_ERR_QUERY_TIMEOUT if no reply arrives.

FunctionWrites to *out
medius_device_query_version(dev, MediusVersion *out)MediusVersion: protocol + firmware version.
medius_device_query_health(dev, MediusHealth *out)MediusHealth: link, mouse, clone, injection flags.
medius_device_device_info(dev, MediusDeviceInfo *out)MediusDeviceInfo: the cloned device's USB identity, kind, and product.
medius_device_caps(dev, MediusCaps *out)MediusCaps: mouse/keyboard capabilities.
medius_device_query_rate(dev, MediusRate *out)MediusRate: native report rate and poll period.
medius_device_query_stats(dev, MediusStats *out)MediusStats: box-side telemetry.
medius_device_query_locks(dev, MediusLocks *out)MediusLocks: every weighed direction (entry list).
medius_device_query_bearing(dev, MediusBearing *out)MediusBearing: the bearing window and geometry.
medius_device_query_catch(dev, MediusCatchState *out)MediusCatchState: the accepted subscription entries with their per-entry drops, the box-wide drop count, and the inter-chip clock estimate.
medius_device_query_imperfect(dev, MediusImperfectStatus *out)MediusImperfectStatus: imperfect-clone state.
medius_device_query_movement_riding(dev, bool *out_enabled, uint32_t *out_window_ms)Whether riding is on, and the window in ms (0 when off).
medius_device_query_emit_pace(dev, MediusEmitPaceStatus *out)MediusEmitPaceStatus: pacing mode, rate in effect, and the rate the clone advertises.
medius_device_counters(dev, MediusCountersSnapshot *out)MediusCountersSnapshot: host-side wire counters.

Firmware update

Write either chip over the open connection

See Firmware update. Staging blocks for the whole transfer; a refusal returns MEDIUS_STATUS_ERR_UPDATE.

FunctionDoes
medius_device_firmware_info(dev, MediusFirmwareInfo *out)Both chips' versions, the slot each runs, and what is staged.
medius_device_stage_firmware(dev, target, image, len, progress, user)Write len bytes into target's spare slot (0 = device chip, 1 = host chip). Inert until activated; progress may be NULL.
medius_device_activate_firmware(dev)Commit every staged image and reboot into it. Blocks while the host chip reboots and comes back.
medius_device_abort_update(dev, target)Throw a staged or in-flight transfer away.
typedef void (*MediusUpdateProgress)(void *user, size_t sent, size_t total);

Streams

Subscribe to live input and logs

Consuming events is on Streams, the catch feature on Catch, and logs on Logs & counters.

medius_device_catch_events takes an array of MediusCatchFilter entries, built by the filter helpers. The box's table holds 32; asking for more, or for an entry it cannot honour, fails the call.

MediusStatus medius_device_catch_events(MediusDevice *dev,
                                        const MediusCatchFilter *filters,
                                        uintptr_t n_filters,
                                        MediusEventStream **out);

MediusStatus medius_device_input_events(MediusDevice *dev,
                                        const MediusCatchFilter *filters,
                                        uintptr_t n_filters,
                                        MediusInputStream **out);
FunctionDoes
medius_device_catch_events(dev, const MediusCatchFilter *filters, uintptr_t n_filters, MediusEventStream **out)Subscribe to the addressed input and traffic classes; each element becomes one table entry.
medius_event_stream_clone(const MediusEventStream *stream)Another handle to the same subscription. Null in → null out.
medius_event_stream_free(MediusEventStream *stream)Free a handle; the subscription ends with the last one.
medius_event_stream_recv(stream, MediusCatchEvent *out)Block for the next event; MEDIUS_STATUS_ERR_DISCONNECTED on close.
medius_event_stream_try_recv(stream, MediusCatchEvent *out)Next buffered event; returns false if none (never blocks).
medius_event_stream_recv_timeout(stream, uint64_t timeout_ms, MediusCatchEvent *out)Block up to timeout_ms; false on timeout or close.
medius_event_stream_dropped(stream)Events dropped because the consumer fell behind.
medius_device_input_events(dev, const MediusCatchFilter *filters, uintptr_t n_filters, MediusInputStream **out)Subscribe to decoded press/release edges. Every filter must name an input class and cover both edges. See Decoded input.
medius_input_stream_recv / _try_recv / _recv_timeout(stream, …, MediusInputEvent *out)Pull the next MediusInputEvent (block / non-block / timed).
medius_input_stream_held(stream, MediusClass class_, MediusUsage *out, uintptr_t cap)Write that class's held usages into out; returns how many there are.
medius_input_stream_dropped(stream) / medius_input_stream_free(stream)Events lost behind a slow consumer / release the handle. There is no input-stream clone.
medius_timeline_new() / _free(t)Open / release a timeline that maps box stamps onto your own clock.
medius_timeline_observe(t, const MediusCatchEvent *ev, uint64_t now_ns, MediusStamped *out)Place one event on the caller's monotonic scale, unwrapped past the 32-bit rollover.
medius_timeline_reset(t, MediusClockDomain domain) / _samples(t, domain)Forget a rebooted chip's rollover count and floor / how many events that domain has fed in.
medius_device_logs(MediusDevice *dev, MediusLogStream **out)Open the device log-line stream.
medius_log_stream_clone / medius_log_stream_freeClone / free a log-stream handle.
medius_log_stream_recv / try_recv / recv_timeout(stream, …, MediusLogLine *out)Pull the next MediusLogLine (block / non-block / timed).

Catch filters

Name one subscription entry, then narrow it

Pure constructors for a MediusCatchFilter: a base names what to observe, a modifier returns a narrowed copy. No device, no wire traffic. See Catch.

FunctionAddresses
medius_catch_filter_watch(MediusUsage usage)One momentary usage: a button, key, or media usage. The same thing medius_device_lock takes.
medius_catch_filter_watch_axis(MediusAxis axis)One relative MediusAxis.
medius_catch_filter_watch_class(MediusClass class_)Every usage in one momentary class.
medius_catch_filter_watch_axes()Every relative axis: X, Y, and the wheel.
medius_catch_filter_all_input(MediusCatchFilter *out)Writes the four input-class filters to out[0..4]: buttons, keys, media, axes. The whole of what medius_device_input_events can report.
medius_catch_filter_traffic(MediusCatchClass class_, uint16_t id)One traffic address: an endpoint, an interface, or a control endpoint number.
medius_catch_filter_traffic_class(MediusCatchClass class_)Every id within one traffic class.
medius_catch_filter_everything()Every class, every id, both directions, whole packets. One table entry, not an expansion.
MODIFIERS
FunctionReturns a copy of f
medius_catch_filter_with_direction(f, uint8_t direction)Restricted to one direction, sign, or edge.
medius_catch_filter_with_capture(f, uint8_t bytes)Keeping only the first bytes of each packet; 0 keeps the whole one. Traffic classes only.
medius_catch_filter_on_press(f) / _on_release(f)Restricted to the press / release edge.
medius_catch_filter_inbound(f) / _outbound(f)Restricted to traffic from the device to the PC / from the PC to the device.

medius_catch_filter_everything includes MEDIUS_CATCH_CLASS_VENDOR_BULK, which can saturate the control link on its own. Pair it with medius_catch_filter_with_capture unless you mean to trace bulk in full.

EXAMPLE
/* the wheel, scrolled up only */
MediusCatchFilter up = medius_catch_filter_with_direction(
    medius_catch_filter_watch_axis(MEDIUS_AXIS_WHEEL), MEDIUS_DIRECTION_POSITIVE);

/* EP0, first 8 bytes: the setup packet and nothing after it */
MediusCatchFilter ep0 = medius_catch_filter_with_capture(
    medius_catch_filter_traffic(MEDIUS_CATCH_CLASS_CONTROL, 0), 8);

Buffered clip playback

Preload a per-frame stream, box-clocked

Build an entry stream with an opaque MediusClipBuilder, then drive playback through an opaque MediusClip handle from medius_device_clip. Each owns its allocation: free the builder with medius_clip_builder_free and the handle with medius_clip_free. Concept on Clip.

BUILDER
FunctionDoes
medius_clip_builder_new() / _free(b) / _clear(b)Allocate / free / reset a builder.
medius_clip_builder_gap(b, uint16_t frames)A gap run (0 = no-op).
medius_clip_builder_move(b, dx, dy) / _wheel(b, dz)A cursor / wheel motion frame.
medius_clip_builder_press / _release / _force_release(b, usage)A one-edge press / soft-release / force-release frame; usage is a MediusUsage (button, key, or media).
medius_clip_builder_edge(b, usage, action)A one-edge frame for any MediusUsage with an explicit MediusAction.
medius_clip_builder_frame(b, dx, dy, wheel, inputs, actions, n)A motion delta plus up to 8 edges on one frame: parallel MediusUsage / MediusAction arrays. Build the inputs with medius_usage_button/_key/_media.
MOVE AND CLICK ON ONE FRAME
MediusClipBuilder *b = medius_clip_builder_new();

/* move (+10, -4) AND press Left on the same frame */
MediusUsage  inputs[1]  = { medius_usage_button(MEDIUS_BUTTON_LEFT) };
MediusAction actions[1] = { MEDIUS_ACTION_PRESS };
medius_clip_builder_frame(b, 10, -4, 0, inputs, actions, 1);
HANDLE
FunctionEffect
medius_device_clip(dev, out) / medius_clip_free(clip)Open / free a clip handle.
medius_clip_append(clip, b)Append the builder's entries to the ring.
medius_clip_set_autolock(clip, const MediusBlanket *scope, uintptr_t scope_len)The auto-lock scope: the MediusBlanket groups scope points at (NULL / 0 = no lock). Set before the first append.
medius_clip_set_loop(clip, uint8_t on) / _set_retain(clip, uint8_t on)Loop at the clip end (retained only) / retain the loaded clip so it can rewind and replay (0 = streaming, the default).
medius_clip_set_ride(clip, uint8_t on)Make the clip's motion wait for a real move under movement riding (0 = the box's own clock, the default).
medius_clip_finalize(clip)Fix a retained clip's end so it can replay and loop.
medius_clip_bind(clip, MediusClipTrigger trigger)Add or overwrite a MediusClipTrigger: a MediusEdge of on drives a MediusClipAction; consume hides the input from the game.
medius_clip_unbind(clip, MediusUsage usage, MediusEdge edge) / _clear_triggers(clip)Remove the binding on that usage + edge; drop every binding.
medius_clip_start(clip) / _stop(clip)Rewind and play (or resume a pause) / stop, flush a streaming clip (rewind a retained one), and release held input and the auto-lock.
medius_clip_pause(clip) / _resume(clip)Halt mid-clip, retaining the cursor and held input / continue from the paused cursor.
medius_clip_restart(clip) / _toggle(clip)Force a rewind and play, even mid-playback / play if idle or paused, stop if playing.
medius_clip_clear(clip)Discard the loaded clip, free the ring, and clear a Faulted state.
medius_clip_query_status(clip, out)Fill a MediusClipStatus: ring depth, progress, and playback counters.
medius_clip_query_config(clip, out)Fill a MediusClipSettings: auto-lock scope, loop/retain, finalized, and the trigger set.

Usage, motion & lock-target builders

Make the value structs the calls take

Pure constructors: no device, no wire traffic. See Inject, Move, and Lock.

FunctionReturns
medius_usage_button(MediusButton button)MediusUsage for medius_device_inject.
medius_usage_key(MediusKey key)MediusUsage addressing a keyboard key.
medius_usage_media(MediusMediaKey media)MediusUsage addressing a media key.
medius_motion_cursor(int16_t dx, int16_t dy)MediusMotion for medius_device_move_axis.
medius_motion_wheel(int16_t delta)MediusMotion for a wheel scroll.
medius_lock_target_axis(MediusLockTargetKind kind)MediusLockTarget for an axis (X / Y / Wheel).
medius_lock_target_usage(MediusUsage usage)MediusLockTarget for a usage (button, key, or media).

Struct inspectors

Read query / event results without the wire

Helpers that interpret a struct you already have. They take it by value (or pointer) and do no I/O. Each mirrors the matching method on the Rust type.

FunctionReturns
medius_locks_scale_of(const MediusLocks *locks, MediusLockTarget target, uint8_t dir)uint8_t: percent of the physical value kept there, 100 when nothing weighs it. See Lock.
medius_locks_is_locked(const MediusLocks *locks, MediusLockTarget target, uint8_t dir)bool: is that target/direction blocked outright (Both needs both fixed signs). A direction merely weighed is not locked.
medius_rate_native_hz(MediusRate rate, float *out_hz)bool: writes the native rate in Hz; false when there is no continuous cadence.
medius_usage_event_is_held(const MediusUsageEvent *event, MediusUsage usage)bool: is that usage (button, key, or media) held in the snapshot.
medius_traffic_event_truncated(const MediusTrafficEvent *ev)bool: ev->len < ev->true_len, so the box cut the packet at the matching entry's capture. Without the comparison a cut packet and a genuinely short one look identical. See MediusTrafficEvent.
medius_traffic_event_setup(const MediusTrafficEvent *ev)const uint8_t *: the 8-byte setup packet of a CONTROL event, or NULL for another class or a capture cut shorter than the setup stage.
medius_traffic_event_data(const MediusTrafficEvent *ev, uintptr_t *out_len)const uint8_t *: the data stage of a CONTROL event, the whole packet for any other class. Both point into ev.
medius_traffic_event_control_status(const MediusTrafficEvent *ev, MediusControlStatus *out)bool: what the real device answered; false for any class but CONTROL.
medius_traffic_event_bus_event(const MediusTrafficEvent *ev, MediusBusEvent *out)bool: the decoded lifecycle event; false for any class but BUS or an unknown kind.
medius_traffic_event_bulk_end_of_transfer(ev) / medius_traffic_event_bulk_zlp(ev)bool: end-of-transfer / zero-length packet, for a VENDOR_BULK event. A ZLP carries no bytes and still terminates a transfer.
medius_catch_filter_same_address(MediusCatchFilter a, MediusCatchFilter b)bool: the two name the same box table entry, whatever their captures.
medius_catch_class_is_input(MediusCatchClass class_) / _is_traffic(class_)bool: one of the four parsed-input classes, which carry no packet / one of the seven byte-oriented ones.
medius_clip_status_is_held(const MediusClipStatus *status, MediusUsage usage)bool: is the clip holding that usage down.
medius_caps_has_mouse(MediusCaps caps)bool: a mouse interface is bound. See Requests.
medius_caps_has_keyboard(MediusCaps caps)bool: a keyboard interface is bound.
medius_caps_is_composite(MediusCaps caps)bool: the clone is multi-HID-interface.

Global functions

Library-level helpers and errors
FunctionDoes
medius_last_error_message(char *buf, uintptr_t cap)Copy the last error's text into buf; returns the full length (size a buffer and retry). See errors.
medius_last_error_proto_ver()The proto-version byte from the last MEDIUS_STATUS_ERR_BAD_PROTO_VER, or 0.
medius_default_query_timeout_ms()The default query reply wait, in ms.
medius_default_keepalive_cadence_ms()The default keepalive interval, in ms.
medius_abi_version()The C ABI version, bumped on any breaking header change; currently 5. Check it at start-up when you load the library dynamically, since a mismatched header and library agree on symbol names but not on struct layout.
medius_version_string()The crate version as a static NUL-terminated string.

Mock box

Scriptable fake for tests, feature-gated

All of these are wrapped in #ifdef MEDIUS_FEATURE_MOCK (the mock cargo feature). The concept lives on Mock; turning the feature on is on Build & features.

FunctionDoes
medius_mock_new()A fresh mock that records commands and auto-replies to queries.
medius_mock_clone / medius_mock_free(MediusMockBox *mock)Share (same state) / free a mock handle.
medius_device_with_mock(const MediusMockBox *mock, MediusDevice **out)Build a MediusDevice over the mock without a handshake.
medius_device_open_mock(const MediusMockBox *mock, MediusDevice **out)Build a MediusDevice over the mock and run the handshake.
medius_mock_set_version / _health / _device_info / _caps / _mouse_caps / _kbd_caps / _rate / _stats / _locks / _catch_state / _imperfect_statusSet the value the mock returns for each query.
medius_mock_set_movement_riding(mock, bool enabled, uint32_t window_ms)Set the movement-riding window the mock reports.
medius_mock_set_bearing(mock, uint16_t window_ms, uint8_t mode)Set the bearing the mock reports. A mode no constant names is ignored, as the box ignores it.
medius_mock_silent(MediusMockBox *mock)Stop answering queries for timeout tests (still records).
medius_mock_push_raw(mock, const uint8_t *bytes, uintptr_t len)Inject raw inbound bytes, as if the box sent them.
medius_mock_push_log(mock, MediusLogLevel level, const char *text)Push a LOG line onto the device's log stream.
medius_mock_push_motion(mock, uint8_t seq, uint32_t ts_us, MediusMotionEvent event)Push a MediusMotionEvent as a Motion catch event.
medius_mock_push_usages(mock, uint8_t seq, uint32_t ts_us, const MediusUsageEvent *event)Push a MediusUsageEvent as a Usages catch event.
medius_mock_push_traffic(mock, uint8_t seq, uint32_t ts_us, MediusClockDomain clock, const MediusTrafficEvent *event)Push a MediusTrafficEvent as a Traffic catch event. A true_len above len is how a cut capture looks.
medius_mock_recorded(MediusMockBox *mock)How many commands the host has sent.
medius_mock_saw(mock, MediusFrameType ty)Whether at least one frame of that type was sent.
medius_mock_clear_recorded(MediusMockBox *mock)Clear the recorded-command log.
medius_mock_recorded_frame(mock, uintptr_t idx, MediusFrameType *out_ty, uint8_t *out_seq, uint8_t *payload_buf, uintptr_t cap)Read recorded frame idx: type, SEQ, and payload bytes.