Medius - BindingsFirst program

First program

Find the box, send a command, read one event, free it

One file: connect, read the firmware version, move the cursor, click the left button, wait for one physical input, then free it. C has no exceptions, so every fallible call returns a MediusStatus you check, and the detail comes from medius_last_error_message. What the commands mean lives in the Library and Native sections; this page is only the C mechanics.

Get medius.h and the library from Build & features. New to the box itself? Read the Native quickstart first.

  find()            ──▶  open + handshake      blocks
  query_version()   ──▶  read the version      blocks
  move() / press()  ──▶  inject input          fire-and-forget
  catch_events()    ──▶  subscribe to input    fire-and-forget
  recv()            ──▶  next physical event   blocks
  free()            ──▶  close, NULL-safe      local

The program

Every call, with error checks

check() is the whole error story: compare against MEDIUS_STATUS_OK (which is 0), and on anything else pull the text with medius_last_error_message. Results land through an out-pointer (&dev, &v, &events), never the return value.

#include <stdio.h>
#include <medius.h>

/* Returns 0 on success, 1 on failure (after printing the last error). */
static int check(MediusStatus s, const char *what) {
    if (s == MEDIUS_STATUS_OK) return 0;
    char msg[256];
    medius_last_error_message(msg, sizeof msg);   /* detail for the last failure */
    fprintf(stderr, "%s failed (status %d): %s\n", what, (int)s, msg);
    return 1;
}

int main(void) {
    MediusDevice *dev = NULL;
    if (check(medius_device_find(&dev), "find"))            /* open first box + handshake */
        return 1;

    printf("medius-capi %s (abi %u)\n", medius_version_string(), medius_abi_version());

    MediusVersion v;
    if (!check(medius_device_query_version(dev, &v), "query_version"))
        printf("firmware %u.%u.%u (proto %u)\n", v.fw_major, v.fw_minor, v.fw_patch, v.proto_ver);

    check(medius_device_move_rel(dev, 100, -50), "move_rel");   /* fire-and-forget */
    check(medius_device_press(dev, medius_usage_button(MEDIUS_BUTTON_LEFT)), "press");
    check(medius_device_soft_release(dev, medius_usage_button(MEDIUS_BUTTON_LEFT)), "release");

    MediusEventStream *events = NULL;
    if (!check(medius_device_catch_events(dev, MEDIUS_CATCH_MASK_ALL, &events), "catch_events")) {
        MediusCatchEvent ev;                                   /* blocks for one physical event */
        if (medius_event_stream_recv(events, &ev) == MEDIUS_STATUS_OK &&
            ev.kind == MEDIUS_CATCH_EVENT_KIND_MOTION)
            printf("motion: dx=%d dy=%d dz=%d\n",
                   ev.data.motion.dx, ev.data.motion.dy, ev.data.motion.dz);
        medius_event_stream_free(events);                      /* unsubscribe */
    }

    medius_device_free(dev);                                   /* close link, join threads */
    return 0;
}
PRINTS (numbers depend on your box)
medius-capi 3.0.0 (abi 3)
firmware 3.0.0 (proto 3)
motion: dx=12 dy=-4 dz=0

medius_event_stream_recv blocks until the user touches the mouse or keyboard. To poll instead, or to loop over many events, see Streams.

Run it

gcc or clang, link libmedius_capi

Run from the unpacked release, with medius.h under include/ and libmedius_capi.so beside it. cc, gcc, and clang all work.

cc first.c -Iinclude -L. -lmedius_capi -o first
LD_LIBRARY_PATH=. ./first      # so the loader finds libmedius_capi.so
FlagWhat it does
-IincludeWhere medius.h lives.
-L.Where libmedius_capi lives (here, the current dir).
-lmedius_capiLink the library (file name is libmedius_capi).

Static linking (libmedius_capi.a), Windows, and the mock / flash feature macros are on Build & features.

Walkthrough

Errors, out-params, freeing, blocking
MechanicHow it works in C
ErrorsEvery fallible call returns a MediusStatus; MEDIUS_STATUS_OK is 0, everything else is a failure. Read the human text with medius_last_error_message(buf, cap) right after the failing call.
ResultsReturn values are status codes, so data comes back through an out-pointer: medius_device_query_version(dev, &v) fills v.
FreeingEach handle has a *_free: medius_device_free, medius_event_stream_free, medius_log_stream_free. All are NULL-safe no-ops. Catch events are fixed-size structs, so there's nothing to free per event.
Fire-and-forgetmove_rel, wheel, press, inject, and the lock / LED calls queue a frame and return at once. This is the fire-and-forget model.
Blocksmedius_device_find / _open (the handshake), every medius_device_query_*, and medius_event_stream_recv wait for a reply or an event.
Sharingmedius_device_clone / medius_event_stream_clone hand back another handle to the same link; each clone must be freed. See Lifecycle.
MediusStatus medius_device_find(MediusDevice **out);
uintptr_t    medius_last_error_message(char *buf, uintptr_t cap);  /* returns full length */

medius_last_error_message is per-thread and reflects only the most recent failure on that thread, so read it before the next call overwrites it. It returns the full message length (excluding the NUL), so size your buffer and retry if it was truncated.

Call reference

Each call's Library and Native page
In the programWhat it means
medius_device_findConnection · the handshake
medius_device_query_versionRequests
medius_device_move_relMove · Native move
medius_device_press / _soft_releaseInject · the injection model
medius_device_catch_events / medius_event_stream_recvCatch · consuming them in C on Streams
medius_device_freeLifecycle

Every call and type is indexed on API index and Types & errors. These mirror the medius crate (source).