Saltar al contenido
SDK 1.0.0 · Documentación original en inglés · Firmware 1.0.0

API reference

Documentation · Getting started · Public header

All functions use C linkage and operate on one global session. Call from the main game loop, not interrupts or an SDK wait callback. Returned strings belong to the SDK; copy them if you need a snapshot across later polls or room changes.

Contents

Configuration and constants

Constants

NameValueMeaning
CF_VERSION_MAJOR1API version component
CF_VERSION_MINOR0API version component
CF_VERSION_PATCH0API version component
CF_MAX_MESSAGE480Maximum payload on either channel
CF_ROOM_MAX24Legacy constant; not the current parameter or code limit

These macros identify SDK 1.0.0, paired with CanoFlash firmware 1.0.0. Protocol versions are separate; see Compatibility.

Current string limits: game key 63 bytes, room parameters 31 bytes, room code 6 ASCII digits, player name 15 UTF-8 bytes. Storage includes an additional terminator. Keys/parameters exceeding their SPI fields are silently truncated, so validate input lengths before submitting.

Configuration types

typedef struct {
    const char *api_key;
    uint8_t tick_hz;
    uint16_t guard_us;
} cf_config_t;

typedef enum { CF_PRIVATE = 0, CF_PUBLIC = 1 } cf_visibility_t;

typedef struct {
    uint8_t max_players;
    cf_visibility_t visibility;
    const char *params;
} cf_room_t;
FieldDefault and behaviour
api_keyNULL; a nonempty registered game key is required
tick_hz0 selects 20 Hz; clamped above 60 and quantised to whole frame intervals
guard_us0 selects 5 microseconds; otherwise clamped to 1–500
max_players2; use 2–8, subject to the relay's lower configured cap
visibilityCF_PUBLIC; creation only, matchmaking creates public rooms
paramsNULL; equivalent to an empty matchmaking parameter string
void cf_config_init(cf_config_t *cfg);
void cf_room_init(cf_room_t *room);

Both accept NULL as a no-op. cf_config_init() zeroes the struct; the effective 20 Hz / 5 microsecond defaults are applied by cf_connect(). cf_room_init() sets two seats, public visibility and NULL parameters. See Timing for tick-rate rounding.

Session

cf_connect

bool cf_connect(const cf_config_t *cfg, void (*wait_frames)(int n));

Resets local session state and statistics, probes the device, submits the game key and waits for an authenticated relay session. Does not join a room.

Returns true when the session is connected. False can leave:

StateInterpretation
CF_DISCONNECTEDInvalid/null configuration, empty key, or no responding device
CF_FAILEDOPEN failed, incompatible firmware, network/authentication failure, or connection wait exhausted

Validate configuration first before interpreting DISCONNECTED as a hardware fault. The API does not expose a detailed connection error code.

Expect seconds rather than one frame. Device probing allows 360 callback frames; connection waiting adds repeated serial queries and callback waits. There is no guaranteed wall-clock duration. Use a waiting screen.

The callback must advance n display frames without calling back into the SDK. NULL provides no rendering/frame pacing. See Blocking calls.

Call cf_disconnect() before explicitly starting a fresh session.

cf_disconnect

void cf_disconnect(void);

Attempts to close the device session, then clears local state. Use when exiting online mode. The close command has no end-to-end confirmation; if the cable or network is already gone, the relay may retain the old seat until its timeout. For a connected menu between matches, use cf_leave_room() instead.

cf_status and cf_state_t

cf_state_t cf_status(void);

Returns cached state without I/O:

ValueMeaning
CF_DISCONNECTED = 0No active SDK session
CF_CONNECTING = 1Initial connection in progress
CF_CONNECTED = 2Session ready; check cf_in_room() separately
CF_FAILED = 3Attempt/session failed; return to an offline or retry UI
CF_RECONNECTING = 4Recovery in progress; pause simulation and keep polling

Status is refreshed by SDK operations and polls, not by the getter.

Room operations

All joins require a connected session with no current room or pending join/leave. They wait for a result using the same callback convention as cf_connect(). A failed room operation does not necessarily end the session.

cf_create_room

const char *cf_create_room(const cf_room_t *room, void (*wait_frames)(int n));

Creates a new room. Returns an SDK-owned code string on success, NULL on failure. A NULL room uses two public seats and empty parameters.

The initial metadata read can fail even after admission: a non-NULL return can temporarily point to an empty string. Continue polling and display cf_room_code() when it becomes available.

cf_join_code

bool cf_join_code(const char *code, void (*wait_frames)(int n));

Joins an existing room for this game by six-digit code, including private rooms. Never creates a missing room. Returns true on admission. NULL/empty code returns false with CF_JOIN_NO_SUCH_ROOM; supply exactly six ASCII digits.

Code joins do not compare your desired parameters/capacity. Games with several wire versions must also negotiate compatibility after a code join.

cf_matchmake

bool cf_matchmake(const cf_room_t *room, void (*wait_frames)(int n));

Finds a public waiting room matching game key, effective capacity and parameter string exactly. If none has space, creates one. Returns true on admission. NULL uses the default room options. visibility does not make matchmaking create a private room.

cf_join_error and cf_join_error_t

cf_join_error_t cf_join_error(void);

Cached result of the last join attempt:

ValueMeaning / recovery
CF_JOIN_OK = 0No join error
CF_JOIN_NO_SUCH_ROOM = 1Missing/invalid code, or room belongs to another game
CF_JOIN_FULL = 2All seats occupied or reserved
CF_JOIN_PLAYING = 3New players cannot join a playing room
CF_JOIN_NO_SESSION = 4Session is not connected
CF_JOIN_NO_LINK = 5Device status/request exchange failed
CF_JOIN_BUSY = 6Already in a room, or a join/leave is pending
CF_JOIN_TIMEOUT = 7Result not confirmed in time; cancellation requested
CF_JOIN_FAILED = 8Other relay rejection

After BUSY or TIMEOUT, keep polling and let pending work settle. Do not blindly repeat CREATE: the previous outcome may not yet be known.

cf_leave_room

void cf_leave_room(void);

Requests leaving/cancellation while keeping the session. Waits briefly for confirmation. If delayed, membership can remain true and sends/new joins are refused until the operation settles. Keep polling.

No-op when not connected or when no room operation exists. Confirmed leaving clears room payload buffers and marks a pending outgoing reliable ticket LOST. Leaving voluntarily does not reserve a seat for resume.

Room metadata

These getters do no I/O. The normal status/metadata cadence is every 20 successful ticks, about one second at the default rate, and slower with low frame rates or failed exchanges. Metadata is also requested after joining.

SignatureResult
bool cf_in_room(void)Confirmed membership; may remain true during pending leave/recovery
const char *cf_room_code(void)Six-digit code, or empty when absent/not yet available
const char *cf_player_name(uint8_t slot)SDK-owned UTF-8 name; empty for unknown/invalid seat
uint8_t cf_slot(void)Local slot, 0–7; meaningful only in a room
uint8_t cf_peers(void)Occupied seats including self and temporarily absent players
uint8_t cf_peer_mask(void)Bit N set for occupied/reserved seat N
uint8_t cf_away_mask(void)Bit N set for a temporarily absent occupant
uint8_t cf_capacity(void)Effective room capacity; zero outside a room
bool cf_is_master(void)Connected local player is the master, with no pending leave
uint8_t cf_master_slot(void)Master slot, or 0xFF if unknown/no master
cf_room_state_t cf_room_state(void)Cached waiting/playing state

Names are at most 15 bytes plus NUL. Adapt unsupported characters to your font and provide a fallback while metadata is pending. Occupancy and names can refresh at different times; a name is not a stable player identifier.

cf_set_room_state and cf_room_state_t

typedef enum {
    CF_ROOM_WAITING = 0,
    CF_ROOM_PLAYING = 1
} cf_room_state_t;

bool cf_set_room_state(cf_room_state_t state);

Only the master may request a change. Returns false if the master precondition fails; true means the command was attempted, not relay confirmation. Continue polling and wait for cf_room_state() to report the desired state. Use only the two enum values. See Rooms.

Normal messages

cf_send and cf_can_send

bool cf_send(const void *data, uint16_t len);
bool cf_can_send(void);

cf_send() copies 1–480 bytes for broadcast to the other room occupants. The sender receives no echo. Polling transmits one fragment per successful tick.

Returns false for NULL data, invalid length, no active connected room, a pending join/leave, or an outgoing normal message still pending. A true return is local acceptance, not remote delivery.

cf_can_send() checks room/state/queue availability only; it cannot validate the buffer or length of a later call. Normal and reliable submissions have separate outgoing slots.

Reliable messages

cf_send_reliable

uint8_t cf_send_reliable(const void *data, uint16_t len);

Copies 1–480 bytes locally and returns a ticket in 1–255. Returns 0 for invalid data/length, unavailable room, pending reliable submission, or exhaustion of the internal operation counter. No serial I/O occurs in this call.

After a nonzero result, the SDK owns retries. Continue polling; do not submit the same application event again just because confirmation is delayed.

cf_delivery and cf_delivery_t

cf_delivery_t cf_delivery(uint8_t ticket);
ValueMeaning
CF_DELIVERY_NONE = 0Zero/noncurrent ticket, or no tracked submission
CF_DELIVERY_PENDING = 1Admission not yet confirmed
CF_DELIVERY_DELIVERED = 2Relay admission confirmed; not game processing
CF_DELIVERY_LOST = 3Admission unconfirmed/failed; remote outcome may be unknown

Only the current ticket is tracked. Tickets wrap after 255 submissions, so do not retain them as permanent event IDs. A later recipient failure does not retroactively turn an admitted ticket into an application acknowledgement.

See Reliable events for ordering, removal and reconciliation.

cf_reliable_waiting

uint8_t cf_reliable_waiting(void);

Cached device queue count plus any complete reliable event retained locally. Useful diagnostically; it excludes events still waiting at the relay.

Receiving

cf_poll

uint16_t cf_poll(void *out, uint16_t max_len);

Call once per frame. On due ticks it exchanges data, services pending reliable work and periodically refreshes state/metadata. Returns one complete message's length, or zero when none is delivered. At most one message is returned per call, and only on a due successful tick in a usable room.

Reliable messages have priority, while normal fragments are still assembled. If a reliable message does not fit the output buffer it stays pending; another normal message that fits may still be returned. Use CF_MAX_MESSAGE bytes.

NULL output or zero capacity maintains the session without consuming messages. Normal buffers retain only the latest complete state per sender. Reliable queues are bounded, so indefinite non-consumption can lead to removal.

Receive metadata

uint8_t cf_last_sender(void);
uint32_t cf_last_sender_generation(void);
bool cf_last_was_reliable(void);

Read immediately after a nonzero poll:

  • Sender is the relay-assigned slot, for either channel.
  • Generation distinguishes successive occupants of a slot; preserved on resume.
  • The boolean identifies the reliable channel.

Do not interpret these getters as metadata for a zero-length poll. Before any message, sender is 0xFF and generation is zero.

Diagnostics

void cf_get_stats(cf_stats_t *out);

Copies counters into cf_stats_t; NULL is a no-op. Counters reset on cf_connect(). A disconnect alone does not reset the statistics.

Field (uint32_t)Counts
ticks_okSuccessful serial tick exchanges
ticks_timeoutTimed-out tick exchanges
ticks_unalignedFailed tick alignment
msgs_sentNormal messages whose fragments were handed to the device
msgs_receivedNormal messages returned to the game
msgs_droppedDetected normal-fragment assembly failures; not every network loss
reliable_sentOutgoing events observed as admitted by the relay
reliable_recvReliable events returned to the game
reliable_lostPending events observed as lost/unconfirmed

These counters do not prove that every peer processed a message. In particular, a lost confirmation does not prove the relay never received the event.

Descargar esta guía