Skip to main content
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 in IDLE (pre-existing device activity may report STREAMING). The first grab() starts the USB or WiFi/UDP data plane. MCAP replay creates its reader during open().
  • Calls that communicate with the device return ERROR_CODE and return data through out parameters. get_* methods without an ERROR_CODE do not block and return cached values.
  • Calls that are invalid for the current DEVICE_STATE return INVALID_FUNCTION_CALL without contacting the device.

Lifecycle

Discovers attached devices: USB in all cases, and BLE advertisers when 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.
Refreshes the device state from the firmware state machine, so a subsequent 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

Blocks until the next frame is assembled, for at most 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).
Decodes and converts the grabbed frame into 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.
Drains queued IMU samples in chronological order.
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

The 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.
factory_reset destroys the encryption key. Every recording made under it becomes permanently undecryptable, including copies already transferred elsewhere. Unlike delete_encryption_key, it does not return the key first, because it responds unauthenticated over USB and returning a key to an unauthenticated caller is the exposure that destroying it removes.
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

All three require the 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.