ef::Device is the single entry point to the SDK. It is move-only (one handle
owns one device session).
Key behavior:
open()claims and configures a live device, caches its identity, and normally leaves it ready inIDLE(pre-existing device activity may reportSTREAMING). The firstgrab()starts the USB or WiFi/UDP data plane. MCAP replay creates its reader duringopen().- Calls that communicate with the device return
ERROR_CODEand return data throughoutparameters.get_*methods without anERROR_CODEdo not block and return cached values. - Calls that are invalid for the current
DEVICE_STATEreturnINVALID_FUNCTION_CALLwithout contacting the device.
Lifecycle
scan_ble is set. Static, so no open handle is required.
open() validates the session configuration against the device’s enabled
capability menu (INVALID_RESOLUTION / INVALID_FPS /
UNSUPPORTED_COMPRESSION), syncs the device clock, and prepares capture.
close() stops any host-file recording and releases the transport. It does
not stop a device-local recording. get_state()
returns the last known DEVICE_STATE and never blocks.
is_authenticated() reports whether this session has supplied a valid control
password. It is meaningful only when the device gates the link, which applies to
any BLE link and to a USB link where DeviceInformation::usb_locked is set.
open() succeeds with an incorrect password, because a gated device still
responds to info, state and storage, which an operator requires when
recovering a device whose password has been lost. Check this value before calling
a gated verb. See Access Control and Encryption.
get_state() is also current, and reports whether a fault is latched. A latched
device has entered SAFE and requires a health-gated recovery. Because the
DEVICE_STATE enum has no fault value, such a device reports CLOSED, so
poll_fault is the means of distinguishing a fault-closed device from one that
is simply not open. When reason is supplied it receives the most recent anomaly
cause. It is populated both for a latched fault and for an abnormal session end
(for example disk_full or capture_stopped), and is empty once a session
starts cleanly, so reason should be checked even when the return value is
false.
Data plane
grab_timeout_ms.
Returns SUCCESS, GRAB_TIMEOUT (non-fatal; continue the loop),
CORRUPTED_FRAME (a lossy frame, delivered only with return_partial),
END_OF_BUFFER (MCAP replay exhausted), or COMMUNICATION_ERROR (the transport
has failed).
mat in the requested VIEW. The
Mat owns its buffer. In a build without FFmpeg, the only supported combination
is a COMPRESSION_MODE::RAW session retrieved as VIEW::NV12; any other
combination returns UNSUPPORTED_COMPRESSION.
IMAGE = last grabbed frame’s capture time (device clock); CURRENT = host
wall clock now.
Identity & health
get_device_information() returns a cached snapshot and performs no device
communication. The snapshot is captured at open() and updated by the WiFi
calls, so a handle held open across a network change continues to report the
values captured earlier. Call refresh_device_information() to update it, as
poll_fault() does for device state, and read the struct again afterwards:
the accessor returns by value, so copies taken earlier are unaffected.
If the transport is unavailable at the time of the refresh, the WiFi association
and the BLE link are reset to unknown rather than retaining their previous
values, so a disconnected device does not continue to report itself as
connected. The health status is retained, because it records a sweep that
completed and clearing it would misreport a healthy device as failed.
Recording
HOST_FILE writes the live stream to a local MCAP file. DEVICE_LOCAL records
on the M1 and continues across close() or a host disconnect. Downloads use the
USB or Bluetooth LE (BLE) control link; uploads use WiFi.
Updates
check_update() issues a single host-side request to the update-check service
and downloads nothing. An empty url installs whatever the service offers, an
https:// URL is downloaded as given, and a local .eff path is transferred
over the wire, which requires USB. update() blocks through apply and reboot,
reporting progress through the callback.
last_error_message() returns the reason reported by whichever component refused
the operation, the device or the service. The ERROR_CODE provides the category,
while this message is generally the actionable detail.
WiFi, time, location, admin
IMU_DATA overload also selects on-device IMU handling for the session:
RAW records uncalibrated samples (the default), CALIBRATED applies the stored
M*S*(x-b) per sample, and BOTH emits both.
Access control and encryption
set_usb_lock locks or unlocks the USB control plane. Unlocked, the factory
default, USB has full privileges. Locked, it gates exactly as BLE does and
open() authenticates with InitParameters::ble_password. Changing it in either
direction requires the current password. session_only opens an already
locked device for the current power session without changing the stored policy,
so the device continues to report usb_locked and the override is lost when
power is removed. It is refused on a device that is not locked, and
authentication never sets it implicitly.
set_encryption enables or disables at-rest encryption for subsequent
recordings. Existing recordings retain the state they were written with. It
returns INVALID_FUNCTION_CALL when no key exists, so enabled never indicates
that recordings are being written unencrypted. Read last_error_message() for
the device’s specific reason for any refusal described below; the ERROR_CODE
provides only the category.
create_encryption_key generates the device key and returns it. This is the only
occasion on which the key is returned in full, so the caller must retain it: it
decrypts every recording made from that point onward. It is refused with
INVALID_FUNCTION_CALL when a key already exists, because replacing one would
render every recording written under it permanently undecryptable. Rotation is
delete_encryption_key followed by create.
delete_encryption_key requires key_id to match the installed key (see
DeviceInformation::encryption_key_id), which prevents a caller from destroying
a key it has not identified; a mismatch returns INVALID_FUNCTION_CALL. out
contains the destroyed key with present == false, which is the final
opportunity to retain it for ciphertext already recorded. It requires the IDLE
state, since a running session holds the key in memory and would continue
encrypting under it after the call reported it destroyed.
factory_reset restores defaults: password, USB unlocked, encryption off, and
WiFi, calibration, capture configuration, recordings and runtime state cleared.
It is ungated on USB only, so that physical possession provides a recovery path
when the password is lost; over BLE it requires the password like any other verb.
It is refused while a capture is active.
Read the current state from get_device_information(). The conceptual model, the
CLI equivalents, and host-side decryption with ef-decrypt are covered in
Access Control and Encryption.
Calibration
IDLE state and take effect on the next capture session.
set_camera_calibration persists the Double Sphere intrinsics produced by the
OpenCV calibration tool. Read them back through
get_device_information().camera_configuration.calibration.
CalibrationParameters also carries two rectification fields:
The intrinsics are published as recording metadata in either configuration, so a
host consumer can perform rectification instead. With
rectify enabled, the
device produces rectilinear frames and fov_scale determines how much of the
lens field they cover. With it disabled, frames remain raw fisheye under the
double-sphere model.
set_imu_calibration persists the IMU field calibration from the host-side
solve, comprising bias, M*S, per-sensor noise and temporal terms, the
camera-to-IMU transform, and the time offset. All fields round-trip through
get_device_information().sensors_configuration. reset_calibration restores
the factory default for the selected sensors. The camera factory default is all
zeros, meaning uncalibrated.
