FFI Reference¶
The instantlink-ffi crate provides C-compatible bindings for controlling Instax printers from Swift, C, or any language with C FFI support.
Build¶
The FFI crate produces both cdylib (shared) and staticlib (static) libraries:
Output files:
target/release/libinstantlink_ffi.dylib(macOS shared)target/release/libinstantlink_ffi.a(static)
The C header is auto-generated at crates/instantlink-ffi/include/instantlink.h during build via cbindgen.
Status Codes¶
All functions return i32 status codes:
| Code | Meaning |
|---|---|
0 |
Success |
-1 |
Printer not found |
-2 |
Multiple printers found |
-3 |
BLE communication error (or panic caught) |
-4 |
Timeout |
-5 |
Invalid argument (null pointer, bad UTF-8) |
-6 |
Image processing error |
-7 |
Print rejected |
-8 |
No film remaining |
-9 |
Battery too low |
Functions¶
Lifecycle¶
// Initialize logging and runtime. Safe to call multiple times.
void instantlink_init(void);
// Connect to the first available printer. Returns 0 on success.
int32_t instantlink_connect(void);
// Connect to a specific printer by name with configurable scan duration.
// Pass 0 for duration_secs to use the default (5 seconds).
int32_t instantlink_connect_named(const char *name, int32_t duration_secs);
// Disconnect from the current printer.
int32_t instantlink_disconnect(void);
// Check if a printer is currently connected.
// Returns 1 if connected, 0 if not, -3 if internal error.
int32_t instantlink_is_connected(void);
Scanning¶
// Scan for nearby Instax printers.
// Writes a JSON array of printer name strings into out_json.
// Returns the number of bytes written (excluding NUL), or a negative error code.
// Pass 0 for duration_secs to use the default scan duration.
int32_t instantlink_scan(int32_t duration_secs, char *out_json, int32_t out_len);
Status Queries¶
// Get battery level (0-100). Returns negative error code on failure.
int32_t instantlink_battery(void);
// Get remaining film count. Returns negative error code on failure.
int32_t instantlink_film_remaining(void);
// Get film remaining and charging state in one call.
// On success, writes film count to *out_film and charging flag (0 or 1)
// to *out_charging, and returns 0.
int32_t instantlink_film_and_charging(int32_t *out_film, int32_t *out_charging);
// Get total print count. Returns negative error code on failure.
int32_t instantlink_print_count(void);
// Get all status fields in one call. More efficient than calling individual
// getters — performs a single mutex lock and one block_on call.
// All output pointers must be valid and non-null.
int32_t instantlink_status(int32_t *out_battery, int32_t *out_film,
int32_t *out_charging, int32_t *out_print_count);
// Get the connected device's BLE name.
// Returns number of bytes written (excluding NUL), or negative error.
int32_t instantlink_device_name(char *out, int32_t out_len);
// Get the connected device's model string (e.g. "Instax Mini Link").
// Returns number of bytes written (excluding NUL), or negative error.
int32_t instantlink_device_model(char *out, int32_t out_len);
Printing¶
// Print an image file.
// quality: JPEG quality 1-100
// fit_mode: 0=crop, 1=contain, 2=stretch
// print_option: 0=Rich (vivid), 1=Natural (classic)
int32_t instantlink_print(const char *path, uint8_t quality,
uint8_t fit_mode, uint8_t print_option);
// Print with a progress callback.
// Same as instantlink_print, but calls progress_cb(sent, total) after each chunk.
// progress_cb may be NULL (behaves like instantlink_print).
int32_t instantlink_print_with_progress(const char *path, uint8_t quality,
uint8_t fit_mode, uint8_t print_option,
void (*progress_cb)(uint32_t sent, uint32_t total));
LED Control¶
// Set LED color and pattern.
// pattern: 0=solid, 1=blink, 2=breathe
int32_t instantlink_set_led(uint8_t r, uint8_t g, uint8_t b, uint8_t pattern);
// Turn off the LED.
int32_t instantlink_led_off(void);
Swift Usage¶
The macOS app loads the FFI dylib at runtime via dlopen/dlsym. See InstantLinkFFI.swift for the complete wrapper that resolves all 17 symbols.
import Foundation
// Load via dlopen (see InstantLinkFFI.swift for full implementation)
let handle = dlopen("libinstantlink_ffi.dylib", RTLD_NOW)
let initFn = dlsym(handle, "instantlink_init")
// ... resolve other symbols
instantlink_init()
let result = instantlink_connect()
if result == 0 {
let battery = instantlink_battery()
print("Battery: \(battery)%")
// Print with progress callback
instantlink_print_with_progress("/path/to/photo.jpg", 97, 0, 0) { sent, total in
print("Progress: \(sent)/\(total)")
}
instantlink_disconnect()
}
Thread Safety¶
The FFI layer maintains a global tokio runtime (OnceLock<Runtime>) and a Mutex-protected device handle. All functions are safe to call from any thread. The Mutex serializes access to the printer. All functions use catch_unwind to prevent Rust panics from crossing the FFI boundary.
The progress_cb in instantlink_print_with_progress is called from the tokio runtime thread. The macOS app wraps the callback state with an NSLock to safely bridge between the C callback and Swift async contexts.