Types & errors
Every C struct, enum, and status code, by tableThe Medius* types and MEDIUS_* enumerators from medius.h. The calls that produce and consume them are on API index; streams on Streams. What each value means lives with the canonical type docs in the Rust Library and Native API sections.
Each enum has a fixed-width backing: MediusStatus is int32_t; every other enum is uint8_t.
On C23 and C++ the tag carries that underlying type directly (enum MediusButton : uint8_t); on C99 the tag is typedef'd to the integer and you pass the prefixed enumerators (MEDIUS_BUTTON_LEFT).
Structs are plain PODs, nothing heap-allocated: pass by value, read fields directly, free nothing per value. Only the opaque handles have a *_free.
Anything variable-length on the wire lands in an inline fixed-cap array with a count beside it, never a pointer you own. The shapes on this page are ABI version 5, the number medius_abi_version() returns.
Sizing constants
Fixed-cap arrays sized to the wire limitsThe event, lock, and log PODs embed fixed-cap arrays sized to the protocol's own limits, with a count field saying how many slots are live. char arrays are NUL-terminated.
| Macro | Value | Caps |
|---|---|---|
MEDIUS_MAX_USAGES | 256 | MediusUsageEvent.usages, MediusClipStatus.held |
MEDIUS_MAX_LOCKS | 256 | MediusLocks.entries |
MEDIUS_MAX_PATH | 512 | MediusPortInfo.path |
MEDIUS_MAX_LOG_TEXT | 512 | MediusLogLine.text |
MEDIUS_MAX_PRODUCT | 128 | MediusDeviceInfo.product |
MEDIUS_MAX_SERIAL | 128 | MediusPortInfo.serial |
MEDIUS_MAX_NAME | 33 | MediusVersion.name |
MEDIUS_CLIP_TRIG_MAX | 8 | MediusClipSettings.triggers |
MEDIUS_MAX_CATCH_ENTRIES | 32 | MediusCatchState.entries |
MEDIUS_MAX_TRAFFIC_BYTES | 180 | MediusTrafficEvent.bytes |
MEDIUS_MAX_CATCH_ENTRIES is the box's subscription table size, so a MediusCatchState always carries the whole live table.
MEDIUS_MAX_TRAFFIC_BYTES is the largest payload one traffic event carries, so the inline array is never what truncates: a short len means the box cut the packet at your capture.
Enums
uint8_t-backed selectors (MediusStatus is int32_t)Each value is a wire byte; the canonical meaning lives on Enums. The *Kind enums (and MediusClass) tag which arm of a built value (MediusUsage, MediusMotion, MediusCatchEvent) is populated.
MediusDeviceKind
The cloned device's primary kindenum MediusDeviceKind : uint8_t
The kind field of a MediusDeviceInfo, from the cloned device's Boot-interface protocol. Also what medius_device_find_mouse_box / _find_keyboard_box select on. See DeviceKind.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_DEVICE_KIND_UNKNOWN | 0 | Neither a Boot keyboard nor mouse. |
MEDIUS_DEVICE_KIND_KEYBOARD | 1 | The device is a keyboard. |
MEDIUS_DEVICE_KIND_MOUSE | 2 | The device is a mouse. |
MediusAxis
A relative axis idenum MediusAxis : uint8_t /* values match the wire axis id */
The axis a medius_catch_filter_watch_axis subscribes to: the same ids a catch or lock entry carries on the wire.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_AXIS_X | 0 | Horizontal cursor movement. |
MEDIUS_AXIS_Y | 1 | Vertical cursor movement. |
MEDIUS_AXIS_WHEEL | 2 | The scroll wheel. |
MediusAction
The press / release tri-stateenum MediusAction : uint8_t
The override action shared by inject calls, whether a button, key, or media usage. See the injection model.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_ACTION_SOFT_RELEASE | 0 | Drop the box's override, press or force; a physical hold stays down. |
MEDIUS_ACTION_PRESS | 1 | Force the input down. |
MEDIUS_ACTION_FORCE_RELEASE | 2 | Force the input up, masking a physical hold. |
MediusClass
Which arm of a MediusUsage is setenum MediusClass : uint8_t
The kind tag of a MediusUsage you build with medius_usage_button/_key/_media.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_CLASS_BUTTON | 0 | id is a mouse button id. |
MEDIUS_CLASS_KEY | 1 | id is a HID keyboard usage. |
MEDIUS_CLASS_MEDIA | 2 | id is a 16-bit Consumer usage. |
MediusMotionKind
Which arm of a MediusMotion is setenum MediusMotionKind : uint8_t
Tags the MediusMotion you build with medius_motion_cursor/_wheel. See Move.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_MOTION_KIND_CURSOR | 0 | dx/dy apply. |
MEDIUS_MOTION_KIND_WHEEL | 1 | wheel applies. |
MediusLockTargetKind
Which input a MediusLockTarget addressesenum MediusLockTargetKind : uint8_t
The kind of a MediusLockTarget. See Lock.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_LOCK_TARGET_KIND_X | 0 | Horizontal movement. |
MEDIUS_LOCK_TARGET_KIND_Y | 1 | Vertical movement. |
MEDIUS_LOCK_TARGET_KIND_WHEEL | 2 | Scroll wheel. |
MEDIUS_LOCK_TARGET_KIND_USAGE | 3 | A momentary usage (the struct's usage field selects which). |
MediusDirection
An axis sign, a usage edge, or a transfer directionenum MediusDirection : uint8_t
One enum with three readings, picked by what it is attached to: an axis sign, a usage edge, or the transfer direction on a MediusCatchFilter naming a byte-oriented catch class. See LOCK and Catch.
| Enumerator | Value | On an axis or wheel | On a button or key | On a traffic-class filter |
|---|---|---|---|---|
MEDIUS_DIRECTION_BOTH | 0 | Both signs; on a scale, a full pass to the relative pair. | Press and release. | Both directions. |
MEDIUS_DIRECTION_POSITIVE | 1 | Positive (+). | The press edge. | IN, device to PC. |
MEDIUS_DIRECTION_NEGATIVE | 2 | Negative (-). | The release edge. | OUT, PC to device. |
MEDIUS_DIRECTION_WITH | 3 | The sign the box is injecting. | Refused. | No meaning. |
MEDIUS_DIRECTION_AGAINST | 4 | The sign opposing it. | Refused. | No meaning. |
Only an axis has a bearing, so WITH or AGAINST on a lock anywhere else is MEDIUS_STATUS_ERR_RELATIVE_DIRECTION. A media usage has no edges: an edge named on one goes out as MEDIUS_DIRECTION_BOTH, which is what MediusLocks reports it as.
Parameters and struct fields carrying a direction are declared uint8_t, so a value outside the enum reaches the boundary rather than the wire.
| Call | Comes back as |
|---|---|
Any call returning a MediusStatus | MEDIUS_STATUS_ERR_INVALID_ARG; no frame goes out. |
medius_locks_scale_of | It names no entry, so MEDIUS_LOCK_SCALE_PASS. |
medius_locks_is_locked | Unlocked, for the same reason. |
medius_catch_filter_with_direction | Stored, then refused at subscribe time, where there is a status to carry it. |
MediusEdge
Which edge of a trigger usage fires a clip bindingenum MediusEdge : uint8_t
The edge of a MediusClipTrigger's on usage that runs its action. Same wire values as MediusDirection. See Clip.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_EDGE_BOTH | 0 | Both press and release. |
MEDIUS_EDGE_PRESS | 1 | The press edge only. |
MEDIUS_EDGE_RELEASE | 2 | The release edge only. |
MediusClipAction
The engine action a clip trigger drivesenum MediusClipAction : uint8_t
What a bound MediusClipTrigger does to the clip on its edge; the same verbs as the medius_clip_start/_stop/... calls. See Clip.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_CLIP_ACTION_START | 0 | Rewind and play (resume from a pause). |
MEDIUS_CLIP_ACTION_STOP | 1 | Stop and release held input and the auto-lock. |
MEDIUS_CLIP_ACTION_PAUSE | 2 | Halt mid-clip, retaining the cursor and held input. |
MEDIUS_CLIP_ACTION_RESUME | 3 | Continue from the paused cursor. |
MEDIUS_CLIP_ACTION_RESTART | 4 | Force a rewind and play, even mid-playback. |
MEDIUS_CLIP_ACTION_TOGGLE | 5 | Play if idle/paused, stop if playing. |
MediusBlanket
A whole-group lock selectorenum MediusBlanket : uint8_t
A whole input group: which one medius_device_lock_all/_unlock_all block in one call, and the scope medius_clip_set_autolock auto-locks while a clip plays. See Lock.
The values are ABI-local ordinals (matching the crate's Blanket order), not the CLIP_LOCK_* wire bits.
| Enumerator | Value | Meaning | What dir picks |
|---|---|---|---|
MEDIUS_BLANKET_AIM | 0 | The X and Y cursor axes. | A sign, on each axis. |
MEDIUS_BLANKET_WHEEL | 1 | The wheel. | A sign. |
MEDIUS_BLANKET_BUTTONS | 2 | Every mouse button. | An edge, on each button. |
MEDIUS_BLANKET_KEYS | 3 | Every keyboard key and modifier. | An edge: POSITIVE blocks presses, NEGATIVE releases, BOTH both. |
MEDIUS_BLANKET_MEDIA | 4 | Every media (Consumer) usage. | Nothing. Media has no edges. |
MediusLedTarget
Which chip's status LED to driveenum MediusLedTarget : uint8_t
See LED.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_LED_TARGET_DEVICE | 0 | The device chip's own LED. |
MEDIUS_LED_TARGET_HOST | 1 | The host chip's LED, relayed over the inter-chip link. |
MEDIUS_LED_TARGET_BOTH | 2 | Both LEDs at once. |
MediusLedMode
What to drive the LED toenum MediusLedMode : uint8_t
See LED. Solid / Blink use the command's level.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_LED_MODE_AUTO | 0 | Restore the chip's own status display. |
MEDIUS_LED_MODE_OFF | 1 | LED dark. |
MEDIUS_LED_MODE_SOLID | 2 | Lit steadily at level. |
MEDIUS_LED_MODE_BLINK | 3 | Blinks at level. |
MediusRebootTarget
Which chip to restart, and howenum MediusRebootTarget : uint8_t
See Admin.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_REBOOT_TARGET_DEVICE_DOWNLOAD | 0 | Device chip into ROM download mode (flash over the serial link). |
MEDIUS_REBOOT_TARGET_HOST_DOWNLOAD | 1 | Host chip into ROM download mode (flash over its own USB). |
MEDIUS_REBOOT_TARGET_DEVICE_RUN | 2 | Restart the device chip and run its firmware. |
MEDIUS_REBOOT_TARGET_HOST_RUN | 3 | Restart the host chip and run its firmware. |
MediusEmitMode
What paces injected motionenum MediusEmitMode : uint8_t
See Options.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_EMIT_MODE_LEARNED | 0 | Pace to the mouse's learnt native report rate (the default). |
MEDIUS_EMIT_MODE_INTERVAL | 1 | Pace to the cloned mouse's declared poll rate (its bInterval). |
MEDIUS_EMIT_MODE_FIXED | 2 | Pace to a fixed rate in Hz (snapped to 1000/n, capped 1 kHz). |
MediusCatchEventKind
Which arm of a MediusCatchEvent is setenum MediusCatchEventKind : uint8_t
Tells you which member of the MediusCatchEvent union to read. Which arms you can see follows from the MediusCatchClass values you subscribed to: the four input classes decode into motion and usages, every byte-oriented class into traffic. See Catch.
| Enumerator | Value | Read | Raised by |
|---|---|---|---|
MEDIUS_CATCH_EVENT_KIND_MOTION | 0 | data.motion | AXIS |
MEDIUS_CATCH_EVENT_KIND_USAGES | 1 | data.usages | BUTTON, KEY, MEDIA |
MEDIUS_CATCH_EVENT_KIND_TRAFFIC | 2 | data.traffic | HID_IN, HID_OUT, VENDOR_INTERRUPT, VENDOR_BULK, CONTROL, EMIT, BUS |
MediusClockDomain
Which chip's clock stamped an eventenum MediusClockDomain : uint8_t
The clock field of a MediusCatchEvent, beside ts_us. Which domain an event carries is fixed by where it is tapped.
The box is two ESP32-S3s that boot independently, so a stamp is only meaningful against other stamps from the same domain.
| Enumerator | Value | Stamped | Carries |
|---|---|---|---|
MEDIUS_CLOCK_DOMAIN_HOST_CHIP | 0 | In USB interrupt context on the host chip, when the real device's transfer completed. | Motion and usage events, HID_IN, and the IN direction of VENDOR_INTERRUPT / VENDOR_BULK. |
MEDIUS_CLOCK_DOMAIN_DEVICE_CHIP | 1 | At the tap on the device chip, the side facing the game PC. | HID_OUT, both OUT directions, CONTROL, EMIT, and BUS. |
Both clocks are box-local and unrelated to any PC clock. Each is a uint32_t of microseconds: it wraps every ~71.6 minutes and returns to zero when that chip reboots.
A stamp below the previous one is a wrap, a reboot, or a domain change.
To put both on this machine's clock, feed events to a MediusTimeline. To relate the two box domains directly, read the estimate on MediusCatchState.
MediusInputKind
Which arm of a MediusInputEvent is setenum MediusInputKind : uint8_t
Tags a MediusInputEvent off the decoded-input stream. The box sends held-usage snapshots; the stream diffs them into these edges.
| Enumerator | Value | Read |
|---|---|---|
MEDIUS_INPUT_KIND_PRESS | 0 | usage: a momentary usage went down. |
MEDIUS_INPUT_KIND_RELEASE | 1 | usage: a momentary usage came up. |
MEDIUS_INPUT_KIND_MOTION | 2 | dx / dy / dz: one relative-motion report. |
MediusLogLevel
Severity tag on a log lineenum MediusLogLevel : uint8_t
The severity of a MediusLogLine. See Logs & counters.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_LOG_LEVEL_ERROR | 0 | A failure the box couldn't recover from. |
MEDIUS_LOG_LEVEL_WARN | 1 | Something off that the box handled. |
MEDIUS_LOG_LEVEL_INFO | 2 | Normal operational notices. |
MEDIUS_LOG_LEVEL_DEBUG | 3 | Detail for diagnosing a problem. |
MEDIUS_LOG_LEVEL_VERBOSE | 4 | The finest-grained trace output. |
MediusCatchClass
What a catch filter addressestypedef uint8_t MediusCatchClass; /* one MEDIUS_CATCH_CLASS_* value */
The class half of a MediusCatchFilter, and the class_ field of both MediusTrafficEvent and MediusCatchEntry.
Classes 0 to 3 are the same vocabulary Lock uses; the rest address the box's USB plumbing and surface as byte-oriented traffic. See Catch.
| Enumerator | Value | id addresses | With MEDIUS_CATCH_ID_ANY |
|---|---|---|---|
MEDIUS_CATCH_CLASS_BTN | 0 | A mouse button id. | Every button. |
MEDIUS_CATCH_CLASS_KEY | 1 | A HID keyboard usage (modifiers are 0xE0 to 0xE7). | Every key and modifier. |
MEDIUS_CATCH_CLASS_MEDIA | 2 | A 16-bit Consumer usage. | Every media usage. |
MEDIUS_CATCH_CLASS_AXIS | 3 | A MediusAxis: X, Y, or the wheel. | Every axis. |
MEDIUS_CATCH_CLASS_HID_IN | 4 | A cloned HID interface number. | Every HID interface. |
MEDIUS_CATCH_CLASS_HID_OUT | 5 | An interrupt-OUT endpoint address. | Every interrupt-OUT endpoint. |
MEDIUS_CATCH_CLASS_VENDOR_INTERRUPT | 6 | A vendor interrupt endpoint address. | Every vendor interrupt endpoint. |
MEDIUS_CATCH_CLASS_VENDOR_BULK | 7 | A vendor bulk endpoint address. | Every vendor bulk endpoint. |
MEDIUS_CATCH_CLASS_CONTROL | 8 | A control endpoint number (0 is EP0). | Every control endpoint. |
MEDIUS_CATCH_CLASS_EMIT | 9 | An emitting endpoint address. | Every emitting endpoint. |
MEDIUS_CATCH_CLASS_BUS | 10 | Nothing; pass MEDIUS_CATCH_ID_ANY. | Every bus event. |
MEDIUS_CATCH_CLASS_ANY | 0xFF | Nothing; must be MEDIUS_CATCH_ID_ANY. | Every class at once. |
Test one with medius_catch_class_is_input (the four parsed classes, which arrive decoded and carry no packet) or medius_catch_class_is_traffic (the seven byte-oriented ones).
The four input classes are captured at the emission merge point before lock suppression and before injection, so a locked input still reports.
MEDIUS_CATCH_CLASS_EMIT is the mirror image: what the clone put on the wire after injection, locks, and the suppression gate.
MediusCatchFilter
One subscription entry: class, id, direction, capturestruct MediusCatchFilter {
MediusCatchClass class_; /* MEDIUS_CATCH_CLASS_* */
uint16_t id; /* class-specific, or MEDIUS_CATCH_ID_ANY */
uint8_t direction; /* MEDIUS_DIRECTION_*: edge, sign, or flow */
uint8_t capture; /* 0 = whole packet; traffic classes only */
};The array you hand to medius_device_catch_events or medius_device_input_events. Build each one with a medius_catch_filter_* helper, then narrow it with a modifier.
Each element becomes one entry in the box's table; read the accepted set back with medius_device_query_catch. The field is spelled class_ because class is a C++ keyword and the header compiles as both.
| Field | C type | Meaning |
|---|---|---|
class_ | MediusCatchClass | Which address space this entry subscribes in. |
id | uint16_t | The id inside that class, or MEDIUS_CATCH_ID_ANY for every id in it. |
direction | uint8_t, a MEDIUS_DIRECTION_* value | For an input class, the press/release edge exactly as for a lock. For a traffic class, the transfer direction: POSITIVE is IN (device to PC), NEGATIVE is OUT (PC to device). No class is both, so one byte carries either reading unambiguously. |
capture | uint8_t | Bytes kept per event; 0 keeps the whole packet. Traffic classes only: an input class carries no packet, and a non-zero capture on one is refused with MEDIUS_STATUS_ERR_CAPTURE_NOT_APPLICABLE. |
| Macro | Value | Means |
|---|---|---|
MEDIUS_CATCH_ID_ANY | 65535 | Every id in the class. A blanket is one table entry, not an expansion into per-id entries, matching how a blanket lock works. |
MEDIUS_CATCH_CLASS_ANY | 255 | Every class. A real id beside it addresses nothing and is refused. |
MEDIUS_MAX_CATCH_ENTRIES | 32 | Entries the box's table holds. Ask for more and the call fails with MEDIUS_STATUS_ERR_CATCH_TABLE_FULL. |
The useful capture length differs between classes by orders of magnitude. A 64-byte vendor interrupt report is worth having whole; a bulk pipe traced only for framing is worth 16 bytes. So it lives on the entry that matched, not box-wide.
Matching is most-specific-first, and the winning entry is the one whose capture applies. That is what makes "everything at 16 bytes, except endpoint 0x83 in full" two entries rather than an impossibility.
a report arrives on VENDOR_INTERRUPT endpoint 0x83
│
├─ exact { class_ = VENDOR_INTERRUPT, id = 0x0083 } ──▶ resolves first
├─ blanket { class_ = VENDOR_INTERRUPT, id = ID_ANY } ──▶ used if no exact entry
└─ any { class_ = ANY, id = ID_ANY } ──▶ used if neither matched
ties inside one tier go to the earlier entry in your array/* everything the box can see, first 16 bytes only */
MediusCatchFilter blanket =
medius_catch_filter_with_capture(medius_catch_filter_everything(), 16);
/* except this endpoint's IN traffic, which we want whole */
MediusCatchFilter whole = medius_catch_filter_inbound(
medius_catch_filter_traffic(MEDIUS_CATCH_CLASS_VENDOR_INTERRUPT, 0x83));
MediusCatchFilter filters[2] = { blanket, whole };
MediusEventStream *events = NULL;
medius_device_catch_events(dev, filters, 2, &events);A malformed entry now fails the whole call with its own MediusStatus, rather than being dropped with no status. Two filters naming the same table entry, whatever their captures, are what medius_catch_filter_same_address tests.
MediusKey
A HID keyboard/keypad usagetypedef uint8_t MediusKey; /* modifiers are 0xE0 to 0xE7 */
A raw HID keyboard usage passed to the key calls. Pass any usage byte, or one of the MEDIUS_KEY_* macros. The full set of usages is on Usage IDs.
| Macro group | Example | Usage |
|---|---|---|
| Letters | MEDIUS_KEY_A .. MEDIUS_KEY_Z | 4 to 29 |
| Digits | MEDIUS_KEY_1 .. MEDIUS_KEY_0 | 30 to 39 |
| Function | MEDIUS_KEY_F1 .. MEDIUS_KEY_F12 | 58 to 69 |
| Editing / nav | MEDIUS_KEY_ENTER, _ESCAPE, _TAB, _SPACE, _INSERT, _HOME, _DELETE, arrows | various |
| Modifiers | MEDIUS_KEY_LEFT_CTRL .. MEDIUS_KEY_RIGHT_GUI | 224 to 231 (0xE0 to 0xE7) |
MediusMediaKey
A 16-bit HID Consumer usagetypedef uint16_t MediusMediaKey;
A raw Consumer usage passed to the media calls. Pass any 16-bit usage, or a MEDIUS_MEDIA_* macro. The full set is on Usage IDs.
| Macro | Usage | Macro | Usage |
|---|---|---|---|
MEDIUS_MEDIA_PLAY_PAUSE | 205 | MEDIUS_MEDIA_MUTE | 226 |
MEDIUS_MEDIA_NEXT_TRACK | 181 | MEDIUS_MEDIA_VOLUME_UP | 233 |
MEDIUS_MEDIA_PREV_TRACK | 182 | MEDIUS_MEDIA_VOLUME_DOWN | 234 |
MEDIUS_MEDIA_STOP | 183 | MEDIUS_MEDIA_PLAY | 176 |
MEDIUS_MEDIA_PAUSE | 177 |
MediusFrameType
A wire frame TYPE byte (mock only)enum MediusFrameType : uint8_t /* always defined; read only by the mock recorder */
The TYPE byte of a wire frame, used with the mock recorder (medius_mock_saw / medius_mock_recorded_frame). See the mock feature.
| Enumerator | Value | Enumerator | Value |
|---|---|---|---|
MEDIUS_FRAME_TYPE_MOVE | 1 | MEDIUS_FRAME_TYPE_LOCK | 10 |
MEDIUS_FRAME_TYPE_INJECT | 3 | MEDIUS_FRAME_TYPE_CATCH | 11 |
MEDIUS_FRAME_TYPE_RESET | 4 | MEDIUS_FRAME_TYPE_MOTION_EVENT | 12 |
MEDIUS_FRAME_TYPE_QUERY | 5 | MEDIUS_FRAME_TYPE_USAGE_EVENT | 15 |
MEDIUS_FRAME_TYPE_RESP | 6 | MEDIUS_FRAME_TYPE_OPTION | 17 |
MEDIUS_FRAME_TYPE_REBOOT_DL | 7 | MEDIUS_FRAME_TYPE_CLIP_APPEND | 18 |
MEDIUS_FRAME_TYPE_LOG | 8 | MEDIUS_FRAME_TYPE_CLIP_CTRL | 19 |
MEDIUS_FRAME_TYPE_LED | 9 | MEDIUS_FRAME_TYPE_CLIP_SET | 20 |
MEDIUS_FRAME_TYPE_TRAFFIC_EVENT | 22 | MEDIUS_FRAME_TYPE_CLIP_TRIGGER | 21 |
Argument structs
Tagged values you build, then pass inThree small PODs you build with a helper and hand to a call. The medius_*_* constructors set the kind tag and the right field for you.
MediusUsage
A momentary usage for injectWhat medius_device_inject drives. Build with medius_usage_button(...), _key(...), or _media(...); id holds the button id or usage per kind. See Inject.
| Field | C type | Meaning |
|---|---|---|
kind | MediusClass | Which class id names. |
id | uint16_t | Button id, key usage, or media usage. |
MediusMoveTiming
When a move reaches the game PCenum MediusMoveTiming : uint8_t
The timing argument of medius_device_move_axis, against movement riding. See Move.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_MOVE_TIMING_RIDE | 0 | Wait for a real cursor move to carry the delta. |
MEDIUS_MOVE_TIMING_NOW | 1 | Emit on the box's own clock. |
MediusPendingMotion
What a move does to held motionenum MediusPendingMotion : uint8_t
The pending argument of medius_device_move_axis. See Move.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_PENDING_MOTION_KEEP | 0 | Leave motion held for a ride alone. |
MEDIUS_PENDING_MOTION_FLUSH | 1 | Emit it now, ignoring the ride window. |
MEDIUS_PENDING_MOTION_DISCARD | 2 | Drop it. |
MediusMotion
A relative axis for move_axisWhat medius_device_move_axis drives. Build with medius_motion_cursor(dx, dy) or medius_motion_wheel(delta). See Move.
| Field | C type | Meaning |
|---|---|---|
kind | MediusMotionKind | Cursor vs wheel. |
dx | int16_t | X movement (Cursor only). |
dy | int16_t | Y movement (Cursor only). |
wheel | int16_t | Scroll delta (Wheel only). |
MediusLockTarget
What a lock acts onPassed to medius_device_lock / _unlock. Build it with medius_lock_target_axis or medius_lock_target_usage; usage is read only when kind is USAGE. See Lock.
| Field | C type | Meaning |
|---|---|---|
kind | MediusLockTargetKind | X, Y, Wheel, or Usage. |
usage | MediusUsage | The button, key, or media usage, when kind == USAGE. |
Query values
PODs written through a query's out-paramEach medius_device_query_* / _caps / _counters call fills one of these by value. Canonical field docs are on Structs; query semantics on Requests.
MediusVersion
Decoded firmware version and box nameFrom medius_device_query_version. Set the box's name with medius_device_set_name.
| Field | C type | Meaning |
|---|---|---|
proto_ver | uint8_t | Wire-protocol version the firmware speaks. |
fw_major | uint8_t | Firmware major version. |
fw_minor | uint8_t | Firmware minor version. |
fw_patch | uint8_t | Firmware patch version. |
mac | uint8_t[6] | The device chip's base MAC, a stable per-box id. |
name | char[MEDIUS_MAX_NAME] | The box's human-readable name (NUL-terminated; a synthesized default when unset). |
MediusHealth
Box readiness flags (each 0 or 1)From medius_device_query_health.
| Field | C type | True (1) when |
|---|---|---|
link_up | uint8_t | The link to the host chip is up. |
mouse_attached | uint8_t | A real mouse is plugged in. |
clone_configured | uint8_t | The PC has set up the cloned mouse. |
injection_active | uint8_t | At least one injected button or move is held. |
rate_confident | uint8_t | The native-rate estimator window is full. |
lock_on | uint8_t | At least one input is off a full pass: blocked, or merely weighed. |
catch_on | uint8_t | A catch subscription is streaming. |
kbd_attached | uint8_t | A keyboard is attached, cloned, and injectable. |
MediusDeviceInfo
The cloned device's USB identity, kind, and productFrom medius_device_device_info; all-zero/empty when nothing is cloned. product is a NUL-terminated UTF-8 string.
| Field | C type | Meaning |
|---|---|---|
vid | uint16_t | USB vendor id (idVendor). |
pid | uint16_t | USB product id (idProduct). |
bcd_device | uint16_t | Device release (bcdDevice). |
bcd_usb | uint16_t | USB version (bcdUSB), e.g. 0x0200. |
has_serial | uint8_t | The clone serves a serial string. |
has_bos | uint8_t | The clone serves a BOS descriptor. |
kind | MediusDeviceKind | The device's primary kind (Boot-interface protocol). |
product | char[MEDIUS_MAX_PRODUCT] | The product string (NUL-terminated; empty when none). |
MediusCaps
The whole cloned device's capabilitiesFrom medius_device_caps: a mouse half and a keyboard half plus the per-class change-driven flags. Test it with medius_caps_has_mouse, medius_caps_has_keyboard, medius_caps_is_composite.
| Field | C type | Meaning |
|---|---|---|
mouse | MediusMouseCaps | The mouse half (all-zero when no mouse is bound). |
keyboard | MediusKbdCaps | The keyboard half (all-zero when no keyboard is bound). |
mouse_change_driven | uint8_t | Always 0: mouse motion is continuous, so it has a learned cadence. |
kbd_change_driven | uint8_t | 1 when a keyboard is bound: it reports only on a key change. |
MediusMouseCaps
What the cloned mouse can doThe mouse half of MediusCaps; all-zero when no mouse interface is bound.
| Field | C type | Meaning |
|---|---|---|
n_buttons | uint8_t | Buttons the mouse report carries. |
has_x | uint8_t | The report carries an X axis. |
has_y | uint8_t | The report carries a Y axis. |
has_wheel | uint8_t | The report carries a wheel. |
has_report_id | uint8_t | The mouse report sits behind a HID report ID. |
n_hid | uint8_t | Cloned HID interfaces; >1 = composite. |
MediusKbdCaps
What the cloned keyboard can doThe keyboard half of MediusCaps; all-zero when no keyboard is bound. n_keys == 0xFF signals an NKRO bitmap.
| Field | C type | Meaning |
|---|---|---|
n_keys | uint8_t | Keycode-array slots, or 0xFF for an NKRO bitmap. |
nkro | uint8_t | The keyboard reports an NKRO bitmap. |
has_consumer | uint8_t | A Consumer collection is present (media injectable). |
has_system | uint8_t | A system-control collection is present (passthrough-only). |
has_report_id | uint8_t | The keyboard report sits behind a HID report ID. |
MediusRate
The native report rate and clone poll periodFrom medius_device_query_rate. Convert to Hz with medius_rate_native_hz(rate, &hz) (returns false when there's no continuous cadence).
| Field | C type | Meaning |
|---|---|---|
native_period_us | uint16_t | Realised native period in µs; 0 = not learned, or change-driven. |
poll_period_us | uint16_t | Cloned inject-endpoint poll period in µs. |
confident | uint8_t | The estimator window is full and the value is trustworthy. |
change_driven | uint8_t | The active input is event-driven (keyboard/media), so no continuous cadence. |
MediusChipFirmware
What one chip is runningOne chip's half of medius_device_firmware_info.
| Field | C type | Meaning |
|---|---|---|
major, minor, patch | uint8_t | The firmware version this chip is running. |
slot | uint8_t | Which app slot it booted: 0 or 1. |
state | uint8_t | Image state: 0 new, 1 pending-verify, 2 valid, 3 invalid, 4 aborted, 0xFF unknown. See rollback. |
MediusFirmwareInfo
Both chips, and what is stagedFrom medius_device_firmware_info.
| Field | C type | Meaning |
|---|---|---|
device | MediusChipFirmware | The PC-facing chip. |
host_present | uint8_t | 0 when the host chip has not answered over the inter-chip link; host is then meaningless. |
host | MediusChipFirmware | The chip that reads the real device. |
slot_size | uint32_t | Usable bytes in a spare slot; the same on both chips. |
device_staged | uint8_t | An image is written and waiting to be activated. |
host_staged | uint8_t | The same, for the host chip. |
MediusStats
Box-side delivery / telemetry countersFrom medius_device_query_stats. A nonzero tx_drops or tx_wedges means delivery degraded under load.
| Field | C type | Meaning |
|---|---|---|
inject_emits | uint32_t | Pure-injection reports emitted. |
tx_drops | uint16_t | Reports dropped on TX-queue overflow (should stay 0). |
tx_merges | uint16_t | Backed-up reports merged instead of queued. |
tx_maxdepth | uint8_t | Deepest the TX queue has reached. |
tx_wedges | uint8_t | Wedged-endpoint recoveries. |
wakeups | uint16_t | Remote-wakeups issued. |
reset_count | uint16_t | USB bus resets seen. |
config_count | uint16_t | SET_CONFIGURATION events (re-enumerations). |
MediusLocks & MediusLockEntry
The active scales, as an entry listFrom medius_device_query_locks: entries[0..n], one per weighed direction. Read one with medius_locks_scale_of(&locks, target, dir), or ask whether it is blocked outright with medius_locks_is_locked; both count a covering whole-class is_blanket entry. Wire layout on the native LOCKS reply.
Asked with MEDIUS_DIRECTION_BOTH | Answers about |
|---|---|
medius_locks_scale_of | The lowest scale across every direction, relative pair included. Not the figure a delta meets: a delta picks up one from each pair, multiplied. |
medius_locks_is_locked | The two fixed signs only. Name _WITH or _AGAINST to ask about one of those. |
| Field | C type | Meaning |
|---|---|---|
n | uint16_t | Live entries in entries. |
entries | MediusLockEntry[MEDIUS_MAX_LOCKS] | One per weighed direction of an axis or usage. |
| Macro | Value | Meaning |
|---|---|---|
MEDIUS_LOCK_SCALE_BLOCK | 0 | Keep none of the physical value. |
MEDIUS_LOCK_SCALE_PASS | 100 | Keep all of it, untouched. |
MEDIUS_LOCK_SCALE_MAX | 255 | 2.55x, the ceiling. |
| Field | C type | Meaning |
|---|---|---|
target | MediusLockTarget | The weighed axis or usage. |
is_blanket | bool | The entry covers a whole class; target.usage.kind names it and target.usage.id is unused. |
direction | uint8_t, a MEDIUS_DIRECTION_* value | Which direction of the target this entry weighs. |
scale | uint8_t | Percent of the physical value kept; 0 is blocked. A momentary usage carries one bit, so the box stores the block or pass it renders and this never reads between them. |
| Case | What the array holds |
|---|---|
| A blanket key lock | One entry per blocked edge, never MEDIUS_DIRECTION_BOTH. |
| A media lock, blanket or specific | MEDIUS_DIRECTION_BOTH, always. |
A relative direction under MEDIUS_BEARING_MODE_VECTOR | The effective scale, the lower of X's and Y's, on both axes. |
| The wire cap | One reply carries 96 entries, well under MEDIUS_MAX_LOCKS; past that the rest is absent, with nothing marking it. See the native LOCKS budget. |
A direction byte no constant names | The entry is dropped rather than trusted, and n moves with the drop. |
MediusBearing & MediusBearingMode
What WITH and AGAINST are measured againststruct MediusBearing {
uint16_t window_ms; /* 0 = off */
MediusBearingMode mode;
};From medius_device_query_bearing, set with medius_device_set_bearing. See the native bearing.
| Field | C type | Meaning |
|---|---|---|
window_ms | uint16_t | How long an axis holds the direction of its last injected delta. 0 is off, leaving WITH and AGAINST inert whatever their scale. |
mode | MediusBearingMode | How the bearing is read; see below. |
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_BEARING_MODE_PER_AXIS | 0 | Each axis compares its own sign against its own bearing, independently. The default. |
MEDIUS_BEARING_MODE_VECTOR | 1 | The delta is projected onto the injected XY vector, and the relative scale weighs only the part along it. The fixed-sign scales still reach what the projection leaves on each axis. One relative scale, the lower of X's and Y's, governs the whole aim; what MediusLocks reports back is there. |
| Macro | Value | Meaning |
|---|---|---|
MEDIUS_BEARING_WINDOW_DEFAULT_MS | 20 | The factory window. A box that has been set boots at its own value. |
MediusCatchState & MediusCatchEntry
The live subscription table, plus the inter-chip clock estimateFrom medius_device_query_catch: a header followed by entries[0..n], one per accepted MediusCatchFilter. The array is inline and capped at MEDIUS_MAX_CATCH_ENTRIES (32), the box's own table size, so the reply always carries the whole table.
The order is the order the box accepted them in, not the order it matches in: matching is worked out per event, most-specific-first, with ties going to the earlier entry.
| Field | C type | Meaning |
|---|---|---|
table_full | uint8_t | 1 when an entry was refused because the table was already full. |
dropped | uint32_t | Box-wide events shed under back-pressure, across every entry. |
clock | MediusClockEstimate | The measured difference between the two chips' clocks (below). |
n | uint16_t | Live entries in entries; 0 means nothing is subscribed. |
entries | MediusCatchEntry[MEDIUS_MAX_CATCH_ENTRIES] | One per accepted filter, in insertion order. |
| Field | C type | Meaning |
|---|---|---|
filter | MediusCatchFilter | The accepted subscription: class, id, direction, and the capture that applies when this entry is the match. |
dropped | uint16_t | Events this entry could not queue. |
Delivery is four strict-priority queues: input and bus first, then the byte-oriented traffic classes, then control, then vendor bulk. Under a busy mouse, bulk can starve completely.
So the count is kept twice. The header's dropped says you are losing events; the per-entry one says which subscription is losing them, and those want different fixes.
The box measures the difference with a four-timestamp exchange across the inter-chip link, stamping each frame as it reaches the wire rather than when it is queued. Queueing is the largest and most variable delay on that link.
| Field | C type | Meaning |
|---|---|---|
offset_us | int32_t | The host chip's clock minus the device chip's. Add it to a DEVICE_CHIP stamp to read that stamp on the HOST_CHIP timeline; subtract to go the other way. |
rate_ppb | int32_t | Relative drift in parts per billion, for extrapolating between exchanges. MEDIUS_CLOCK_RATE_NONE means none was fitted, which is a different answer from a fitted 0. |
delay_us | uint16_t | The best round trip measured in the window; the offset is good to about half of it. This is what says whether a cross-domain comparison is worth making. |
age_ms | uint32_t | How old the estimate is. MEDIUS_CLOCK_AGE_NONE keeps "never measured" distinct from an offset that happens to be zero; both read as offset_us == 0 and only one is usable. |
MediusImperfectStatus
The imperfect-clone state (each 0 or 1)From medius_device_query_imperfect. See Options.
| Field | C type | True (1) when |
|---|---|---|
allowed | uint8_t | The opt-in toggle; cloning an over-capacity device is allowed. |
over_capacity | uint8_t | The device needs an interrupt-IN endpoint the box can't service. |
clone_imperfect | uint8_t | The live clone is over-capacity and was cloned anyway, so one interface is dead. |
MediusEmitPaceStatus
The emit-rate pacing stateFrom medius_device_query_emit_pace. See Options.
| Field | C type | Meaning |
|---|---|---|
mode | MediusEmitMode | The selected mode. |
fixed_hz | uint16_t | The rate requested for FIXED (0 otherwise). |
resolved_hz | uint16_t | The ceiling in effect; 0 = learnt/adaptive, or no device yet in INTERVAL. |
force_hz | uint16_t | The forced wire rate requested; 0 leaves the device's own. |
advertised_hz | uint16_t | What the clone's input endpoints advertise now, forced or native; 0 = no clone. |
force_active | uint8_t | 1 when a forced interval is written into the descriptor being served. |
MediusCountersSnapshot
Host-side always-on link countersFrom medius_device_counters. See Logs & counters.
| Field | C type | Meaning |
|---|---|---|
frames_tx | uint64_t | Frames sent to the box. |
frames_rx | uint64_t | Frames received from the box. |
crc_drops | uint64_t | Inbound frames dropped on a bad checksum. |
reconnects | uint64_t | Times the library reopened the port. |
MediusPortInfo
A discovered medius serial portFilled by medius_find_ports; path and serial are NUL-terminated. Canonical docs on PortInfo.
| Field | C type | Meaning |
|---|---|---|
path | char[MEDIUS_MAX_PATH] | Serial port path (NUL-terminated). |
vid | uint16_t | USB vendor id (0x1A86). |
pid | uint16_t | USB product id (0x55D3). |
serial | char[MEDIUS_MAX_SERIAL] | The CH343 adapter's serial (NUL-terminated); empty when has_serial == 0. |
has_serial | uint8_t | Whether the adapter serves a serial string. |
MediusBoxInfo
One discovered box: port, version, and cloned deviceFilled by medius_list: one entry per connected box, each opened and handshaked in turn. See BoxInfo.
| Field | C type | Meaning |
|---|---|---|
port | MediusPortInfo | The box's control port (path + CH343 serial). |
version | MediusVersion | Its firmware version, with the box MAC and name. |
device | MediusDeviceInfo | The device it clones. |
Event & log types
Fixed-size PODs off the streamsThe values you read off the catch and log streams. Catch semantics on Catch; canonical docs on Structs.
MediusMotionEvent
One physical relative-axis snapshotThe user's real motion at the merge point, before any lock suppression or injection. Surfaces as the Motion arm of a MediusCatchEvent, raised by a MEDIUS_CATCH_CLASS_AXIS subscription.
It carries no timestamp of its own: the enclosing event's ts_us and clock cover it, and for motion the domain is always MEDIUS_CLOCK_DOMAIN_HOST_CHIP.
| Field | C type | Meaning |
|---|---|---|
dx | int16_t | Relative X this report (right positive). |
dy | int16_t | Relative Y this report (down positive). |
dz | int16_t | Wheel delta this report (up positive). |
MediusUsageEvent
One held-usage snapshot for a classThe held usages of one class (button, key, or media; modifiers are key usages 0xE0 to 0xE7) in usages[0..n], buttons and keys the same shape. Test one with medius_usage_event_is_held(&event, usage). Raised by a BTN, KEY, or MEDIA subscription.
Like motion, it carries no timestamp of its own: it uses the enclosing event's ts_us and clock, which for a usage snapshot is always MEDIUS_CLOCK_DOMAIN_HOST_CHIP.
| Field | C type | Meaning |
|---|---|---|
class_ | MediusClass | Which class this snapshot is of. Carried here rather than read off the first entry, because the snapshot that most needs it is the one with n == 0. |
direction | uint8_t, a MEDIUS_DIRECTION_* value | The edge that produced it: the subscribed set grew (POSITIVE) or shrank (NEGATIVE). |
n | uint16_t | Live usages in usages. |
usages | MediusUsage[MEDIUS_MAX_USAGES] | The held MediusUsage usages (button, key, or media). |
Diffing successive snapshots into press and release edges is what the decoded-input stream does for you.
MediusTrafficEvent
One captured packet off a traffic classstruct MediusTrafficEvent {
MediusCatchClass class_;
uint16_t id;
uint8_t direction;
uint8_t flags;
uint16_t true_len; /* length before capture truncation */
uint16_t len; /* bytes actually kept */
uint8_t bytes[MEDIUS_MAX_TRAFFIC_BYTES];
};The Traffic arm of a MediusCatchEvent, raised by any of the byte-oriented catch classes.
bytes is an inline array rather than a pointer, capped at MEDIUS_MAX_TRAFFIC_BYTES (180), so the event stays a fixed-size POD you can copy, queue, and drop with nothing to free.
| Field | C type | Meaning |
|---|---|---|
class_ | MediusCatchClass | Which class produced the event; it also selects how flags reads. |
id | uint16_t | The endpoint address, endpoint number, or interface number, per the class. |
direction | uint8_t, a MEDIUS_DIRECTION_* value | POSITIVE = IN (device to PC), NEGATIVE = OUT (PC to device). |
flags | uint8_t | Class-specific; see the table below. 0 for classes that define none. |
true_len | uint16_t | The packet's length on the bus, before capture cut it. |
len | uint16_t | Bytes actually captured; the live prefix of bytes. |
bytes | uint8_t[MEDIUS_MAX_TRAFFIC_BYTES] | The capture, valid over bytes[0..len]. |
Without true_len, a packet the box cut at your capture and a genuinely short packet are indistinguishable. medius_traffic_event_truncated(&ev) is that comparison.
| Class | flags reads as | Decode it with |
|---|---|---|
MEDIUS_CATCH_CLASS_VENDOR_BULK | Bit 0: end of transfer. Bit 1: a zero-length packet. | medius_traffic_event_bulk_end_of_transfer, medius_traffic_event_bulk_zlp |
MEDIUS_CATCH_CLASS_CONTROL | The real device's answer: 0 it completed, 0xFD it STALLed, 0xFE it NAKed to timeout. | medius_traffic_event_control_status, into a MediusControlStatus |
MEDIUS_CATCH_CLASS_BUS | The bus event kind (table below). | medius_traffic_event_bus_event, into a MediusBusEvent |
| every other class | 0. | - |
A CONTROL event covers a whole completed transaction, not one stage of one: bytes is the 8-byte SETUP packet followed by the data stage, and direction says which way that data went. Split them with medius_traffic_event_setup and medius_traffic_event_data.
A request the box answered from its own descriptor cache still produces an event.
A BUS event puts the kind in flags and up to two operands in bytes. medius_traffic_event_bus_event decodes both into a MediusBusEvent.
MediusBusEventKind | flags | Operands |
|---|---|---|
MEDIUS_BUS_EVENT_KIND_RESET | 0 | none |
MEDIUS_BUS_EVENT_KIND_SUSPEND | 1 | none |
MEDIUS_BUS_EVENT_KIND_RESUME | 2 | none |
MEDIUS_BUS_EVENT_KIND_CONFIGURED | 3 | configuration |
MEDIUS_BUS_EVENT_KIND_DECONFIGURED | 4 | none |
MEDIUS_BUS_EVENT_KIND_SET_INTERFACE | 5 | interface, alt |
MEDIUS_BUS_EVENT_KIND_DEVICE_ATTACHED | 6 | none |
MEDIUS_BUS_EVENT_KIND_DEVICE_DETACHED | 7 | none |
MEDIUS_BUS_EVENT_KIND_CLONE_UP | 8 | none |
MEDIUS_BUS_EVENT_KIND_CLONE_DOWN | 9 | none |
None of these announces a chip reboot, which is the only thing that restarts a stamping clock. Call medius_timeline_reset for a chip you know restarted.
MediusCatchEvent
One catch-stream event (a tagged union)struct MediusCatchEvent {
MediusCatchEventKind kind;
uint32_t ts_us;
MediusClockDomain clock;
union MediusCatchEventData {
MediusMotionEvent motion;
MediusUsageEvent usages;
MediusTrafficEvent traffic;
} data;
}Written by medius_event_stream_recv and friends. Read the union member named by kind. See MediusClockDomain for which class lands in which domain.
| Field | C type | Meaning |
|---|---|---|
kind | MediusCatchEventKind | Which union member is live. |
ts_us | uint32_t | When the report or packet was seen, in box microseconds. Wraps every ~71.6 minutes and restarts at a chip reboot. See Catch timestamps. |
clock | MediusClockDomain | Which chip's clock ts_us came from. Compare stamps only within one domain, or map both onto your own clock with a MediusTimeline. |
data.motion | MediusMotionEvent | Read when kind == MOTION. |
data.usages | MediusUsageEvent | Read when kind == USAGES. |
data.traffic | MediusTrafficEvent | Read when kind == TRAFFIC. |
| Part | Bytes | Made of |
|---|---|---|
data.motion | 6 | Three int16_t deltas. |
data.traffic | 190 | 10 bytes of header once padded, plus bytes[180]. |
data.usages | 1028 | class_, direction, n, plus 256 x 4-byte MediusUsage = 1024. |
| the union | 1028 | The largest arm, so usages sets it. |
MediusCatchEvent | 1040 | kind, ts_us, clock, their padding, and the union. |
An event is 1040 bytes whichever arm is live. The exact padding is the compiler's, so use sizeof if you need the number itself.
MediusLogLine
One device log lineWritten by medius_log_stream_recv; text is NUL-terminated.
| Field | C type | Meaning |
|---|---|---|
level | MediusLogLevel | Severity tag. |
text | char[MEDIUS_MAX_LOG_TEXT] | The decoded message (NUL-terminated). |
MediusInputEvent
One decoded press, release, or motion reportstruct MediusInputEvent {
MediusInputKind kind; /* PRESS = 0, RELEASE = 1, MOTION = 2 */
uint32_t ts_us;
MediusClockDomain clock; /* always HOST_CHIP for physical input */
MediusUsage usage; /* the edge's usage; zeroed for MOTION */
int16_t dx, dy, dz;
};Written by medius_input_stream_recv and its non-blocking siblings. The box sends held-usage snapshots; the stream diffs them, so a caller reads edges instead of sets.
| Field | C type | Meaning |
|---|---|---|
kind | MediusInputKind | Which fields are live. |
ts_us | uint32_t | The report's arrival stamp, in the clock chip's microseconds. |
clock | MediusClockDomain | Always MEDIUS_CLOCK_DOMAIN_HOST_CHIP: physical input is stamped on the host chip. |
usage | MediusUsage | The button, key, or media usage this is an edge on; zeroed for MOTION. |
dx, dy, dz | int16_t | Relative X, Y, and wheel this report; zero unless kind is MOTION. |
MediusStamped
One event placed on this machine's clockstruct MediusStamped {
uint64_t host_ns; /* on the caller's own monotonic scale */
uint64_t box_us; /* unwrapped past the 32-bit rollover */
uint64_t excess_ns; /* jitter above the measured floor */
};Written by medius_timeline_observe. host_ns comes back on the same scale as the now_ns you passed in.
| Field | C type | Meaning |
|---|---|---|
host_ns | uint64_t | When the event happened, on the caller's monotonic clock. |
box_us | uint64_t | The event's own stamp, unwrapped: a raw ts_us wraps every ~71.6 minutes. |
excess_ns | uint64_t | How much later than the measured floor this event reached you. Jitter, not latency. |
MediusClipTrigger
One physical-input binding that drives the clipA managed binding you add with medius_clip_bind: when on hits edge, the box runs action on the clip. Build the on usage with the medius_usage_* helpers. Concept on Clip.
| Field | C type | Meaning |
|---|---|---|
on | MediusUsage | The physical button, key, or media usage that fires the binding. |
edge | MediusEdge | Which edge of on fires it. |
action | MediusClipAction | What it does to the clip. |
consume | uint8_t | 1 to suppress the input so it never reaches the PC; 0 to let it pass through. |
MediusClipSettings
The clip configuration read back from the boxFrom medius_clip_query_config: the auto-lock scope, the loop/retain/finalize scalars, and the live trigger set. Concept on Clip.
| Field | C type | Meaning |
|---|---|---|
autolock_bits | uint8_t | The auto-lock scope as CLIP_LOCK_* wire bits (set with medius_clip_set_autolock). |
loop_ | uint8_t | Playback loops at the clip end (retained mode only). |
retain | uint8_t | The loaded clip is retained so it can rewind and replay (0 = streaming). |
finalized | uint8_t | A retained clip's end is fixed, so it can replay and loop. |
ride | uint8_t | The clip's motion waits for a real move under movement riding. |
triggers | MediusClipTrigger[MEDIUS_CLIP_TRIG_MAX] | The bound triggers, triggers[0..n]. |
n | uint8_t | Live entries in triggers. |
MediusClipStatus & MediusClipState
Buffered-clip ring and playback stateFrom medius_clip_query_status; state is a MediusClipState. Concept on Clip.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_CLIP_STATE_IDLE | 0 | No clip playing (empty, or a loaded clip parked at its start). |
MEDIUS_CLIP_STATE_PLAYING | 1 | Draining the ring, one entry per native frame. |
MEDIUS_CLIP_STATE_PAUSED | 2 | Halted mid-clip; the cursor and any held usages are retained. |
MEDIUS_CLIP_STATE_FAULTED | 3 | An append was dropped or the ring overflowed; recover with medius_clip_clear. |
| Field | C type | Meaning |
|---|---|---|
state | MediusClipState | The lifecycle state. |
free | uint32_t | Ring bytes free; pace top-ups off this. |
total | uint32_t | The retained clip size in bytes; streaming, the buffered-but-undrained bytes. |
played | uint32_t | Bytes played from the clip start (retained progress; ~0 while streaming). |
ticks | uint32_t | Content frames drained since the last start (gap runs are not counted). |
underruns | uint16_t | Empty-ring episodes. |
overruns | uint16_t | Appends dropped because the ring was full. |
seq_gaps | uint16_t | Dropped append frames detected. |
held_n | uint16_t | Held usages in held. |
held | MediusUsage[MEDIUS_MAX_USAGES] | The buttons, keys, and media the clip is holding down; test one with medius_clip_status_is_held. |
Errors
MediusStatus plus a thread-local messageenum MediusStatus : int32_t /* MEDIUS_STATUS_OK == 0; everything else is a failure */
Every fallible call returns a MediusStatus and writes its result through an out-param. On failure the detail lives in thread-local state. Read it before the next call on that thread overwrites it. Canonical mapping on Errors.
| Enumerator | Value | Meaning |
|---|---|---|
MEDIUS_STATUS_OK | 0 | Success. |
MEDIUS_STATUS_ERR_IO | 1 | An underlying serial or OS error. |
MEDIUS_STATUS_ERR_NOT_FOUND | 2 | No device matched the expected VID/PID. |
MEDIUS_STATUS_ERR_NO_REPLY | 3 | The box never answered the version query during the handshake. |
MEDIUS_STATUS_ERR_BAD_PROTO_VER | 4 | The box answered with an unexpected proto_ver (see medius_last_error_proto_ver). |
MEDIUS_STATUS_ERR_QUERY_TIMEOUT | 5 | A query waited past its timeout with no reply. |
MEDIUS_STATUS_ERR_DISCONNECTED | 6 | The link dropped (also returned by a stream when it closes). |
MEDIUS_STATUS_ERR_FRAME_TOO_LONG | 7 | An outbound frame exceeded the wire limit. |
MEDIUS_STATUS_ERR_UPDATE | 8 | The box refused a firmware update op. |
MEDIUS_STATUS_ERR_INVALID_ARG | 9 | A bad argument (e.g. a null required pointer). |
MEDIUS_STATUS_ERR_PANIC | 10 | A Rust panic was caught at the boundary. |
MEDIUS_STATUS_ERR_UNKNOWN | 11 | An unclassified failure. |
MEDIUS_STATUS_ERR_CATCH_TABLE_FULL | 12 | The subscription needs more entries than the box's table holds. |
MEDIUS_STATUS_ERR_EMPTY_SUBSCRIPTION | 13 | A catch subscription with no filters, which would never yield an event. |
MEDIUS_STATUS_ERR_CAPTURE_NOT_APPLICABLE | 14 | A non-zero capture on an input class, which carries no packet. |
MEDIUS_STATUS_ERR_NOT_AN_INPUT_FILTER | 15 | A traffic class passed to medius_device_input_events, which cannot decode one. |
MEDIUS_STATUS_ERR_WILDCARD_NOT_INPUT | 16 | The everything filter passed to medius_device_input_events; it covers traffic too. |
MEDIUS_STATUS_ERR_HALF_EDGE_INPUT_FILTER | 17 | An input filter narrowed to one edge, which cannot be decoded into press and release. |
MEDIUS_STATUS_ERR_RESERVED_ID | 18 | An exact id equal to the blanket sentinel, which would address the whole class. |
MEDIUS_STATUS_ERR_RELATIVE_DIRECTION | 19 | MEDIUS_DIRECTION_WITH or _AGAINST where only a fixed sign or edge can be addressed. They are resolved against the bearing at emit time, which is after the call is made. |
| Function | Returns | Meaning |
|---|---|---|
medius_last_error_message(char *buf, uintptr_t cap) | uintptr_t | Copies the last error's text (NUL-terminated, truncated to cap); returns the full length, so you can size a buffer and retry. |
medius_last_error_proto_ver(void) | uint8_t | The version byte from a BAD_PROTO_VER error, or 0. |
MediusDevice *dev = NULL;
if (medius_device_find(&dev) != MEDIUS_STATUS_OK) {
char buf[256];
medius_last_error_message(buf, sizeof buf);
fprintf(stderr, "open failed: %s\n", buf);
return 1;
}