> ## Documentation Index
> Fetch the complete documentation index at: https://docs.efference.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Firmware Updates

> Check, apply, and monitor firmware updates

Firmware uses signed `.eff` images and A/B slots with rollback. Open the M1
over USB or Bluetooth LE (BLE), then stop device-local recording and uploads
before updating.

The image location is normally not required. The SDK queries the update-check
service for the version this device should be running and passes the result to
the device, so the common case requires no URL.

## Check what is available

`check_update()` issues a single request from the host. It downloads nothing and
does not instruct the device to perform its own check.

```cpp theme={null}
UpdateAvailability avail;
dev.check_update(avail);
// avail.available, avail.target_version, avail.target_version_str, avail.url
```

`available` is false both when the device is current and when the service has
nothing published for it. `service_error` reports the reason in either case,
which distinguishes an absence of published updates from a misconfigured service.

## Apply

```cpp theme={null}
ERROR_CODE ec = dev.update("", [](const UpdateStatus& s) {
    std::printf("update: %s %d%%\n", s.message.c_str(), s.progress);
});
// DEVICE_UP_TO_DATE is a possible (benign) result if the image is not newer
```

The `url` argument selects the source:

| `url`                       | Behavior                                                  |
| --------------------------- | --------------------------------------------------------- |
| `""` (empty)                | query the update-check service and install what it offers |
| `https://...`               | download that URL directly, with no service call          |
| `firmware.eff` (local path) | **sideload**: transferred over the wire, requires USB     |

Regardless of how the image is obtained, the device verifies its signature and
refuses any image that is not strictly newer than the running firmware, so an
incorrect source costs only a download. `update()` returns `DEVICE_UP_TO_DATE` in
that case, and `WIFI_NOT_CONNECTED` if a download is required but the device is
not connected to a network.

`update()` blocks through download, verification, apply, reboot, and
reconnection. Use the callback or `get_update_status()` to monitor progress, and
`abort_update()` to request cancellation.

```cpp theme={null}
UpdateStatus st;
dev.get_update_status(st);
// st.active, st.state, st.progress (0-100, -1 indeterminate)
// st.running_version_int, st.target_version_int
```

## From the CLI

```sh theme={null}
ef-cli check-update                # what would be installed, without downloading it
ef-cli update                      # install whatever the service offers
ef-cli update --url <url>          # install from an explicit URL, skipping the service
ef-cli update --file firmware.eff  # sideload a local image over USB
ef-cli abort-update
```

## Pointing at a different service

The endpoint is compiled in. Override it per invocation with
`EF_UPDATE_CHECK_URL`, or at configure time with
`cmake -DEF_UPDATE_CHECK_URL=https://my-host/ota/check`, which is the
appropriate option for a self-hosted or air-gapped deployment.

<Warning>
  A host-file recording cannot span an update, because the device reboots. The SDK
  finalizes the `.mcap` before applying. Device-local recordings must be stopped
  first, since the device refuses an over-the-air update while recording.
</Warning>

<Note>
  After a successful reconnect, call `grab()` again to start a new live data
  plane. A firmware update cannot preserve a continuous stream across the reboot.
</Note>
