---
title: Device Setup & Readiness
slug: device-setup-and-readiness
docTags: 
createdAt: 2026-06-19T11:50:23.616Z
---

A Miura reader must be in a known-good state before it can transact: on the OS and MPI versions the SDK supports, with security keys loaded, its ECC terminal certificate signed and installed, and its configuration current. All of this is coordinated by a **single entry point:&#x20;**`ensureDeviceReady()`.

## Ensuring the device is ready to transact&#x20;

`ensureDeviceReady()` brings the selected device into a Toro-compatible state. In one call it will, as needed:

1. Reset the reader to the SDK's required MPI version.
2. Reset the reader to the SDK's required OS version.
3. Reconnect to the reader after any reboot triggered by the above.
4. Check the TMS for pending updates.
5. Sign and install the ECC terminal certificate.
6. Inject security keys (SRED / PIN).
7. Apply pending configuration updates.

:::CodeblockTabs
```kotlin
toro.ensureDeviceReady(
    onStateChanged = { state ->
        Log.d(TAG, "Device setup: $state")
        // Drive end-user messaging from `state`
    },
    onSuccess = {
        Log.d(TAG, "Device is ready")
    },
    onError = { error ->
        Log.e(TAG, "Device setup failed", error)
    }
    // onManualEccSigningRequired is optional in Kotlin (defaults to a no-op) and is
    // TEST-device only, so it is omitted here. See "Manual ECC signing" below.
)
```

```java
toro.ensureDeviceReady(new DeviceSetupListener() {
    @Override
    public void onStateChanged(@NonNull DeviceSetupState state) {
        // Drive end-user messaging from `state`
    }

    @Override
    public void onSuccess() {
        // Device is ready
    }

    @Override
    public void onError(@NonNull ToroException error) {
        // Device setup failed
    }

    @Override
    public void onManualEccSigningRequired(@NonNull byte[] csr) {
        // TEST devices only — leave empty in production. See "Manual ECC signing" below.
    }
});
```
:::

### Safe to re-run

`ensureDeviceReady()` is **safe to call repeatedly**. Steps that are already satisfied are skipped, so it only does the work the device actually needs. If the device is already on the correct OS and MPI, has its keys and certificate, and has no pending TMS updates, no changes are made to the device (the TMS status check still runs each time to determine that).

Because of this, you should call it both:

- when **first pairing** a new reader, and
- on **every app launch** (and/or whenever a device is selected).

On a healthy device the only unavoidable work is a single `StatusReport` to the TMS to confirm there are no pending updates.

### Which OS / MPI versions?

`ensureDeviceReady()` targets the specific OS and MPI versions that the current Toro SDK release is built and tested against. The values the SDK requires are exposed as constants on `MiuraDeviceInfo` (`MiuraDeviceInfo.REQUIRED_OS_VERSION` and `MiuraDeviceInfo.REQUIRED_MPI_VERSION`), which indicate which MPI and OS that SDK release is designed for. The `osVersionOk` / `mpiVersionOk` fields of `baselineStatus` are derived from them.

## Tracking progress: `DeviceSetupState`

The `onStateChanged` callback fires on the main thread each time setup moves to a new phase, with a `DeviceSetupState` value. Use it to show appropriate messaging to the operator and cardholder.

## Automatic reconnection after reboot

Resetting the OS/MPI or applying certain updates causes the reader to reboot. The reader gives no direct "reboot finished" signal, so the SDK reconnects automatically by polling for the connection to come back, then continues, with no integrator intervention required. While this is happening, `onStateChanged` reports `RECONNECTING`.

## Manual ECC signing (TEST devices only)

**Most integrations can ignore this section.** For **PROD** devices, `ensureDeviceReady()` provisions the ECC terminal certificate end-to-end via the TMS, so there is nothing to do — and PROD devices never reach the manual-signing state. Manual ECC signing only ever applies to **TEST** devices used during development, where there is no TMS CSR-signing service and the certificate must instead be signed out-of-band by the device manufacturer.

Because it is a development-only, low-frequency step, you are **not** expected to build manual-signing support into your app. The `onManualEccSigningRequired` callback is only ever invoked for TEST devices, which your production app will never see, so **PROD integrations can ignore it entirely:**

- **Kotlin** — the callback is optional; it defaults to a no-op, so you can simply omit it.
- **Java** — `DeviceSetupListener.onManualEccSigningRequired` must be implemented, but the body can be left empty.

Instead, use our **sample app** to provision TEST devices. It ships as a ready-made APK with a complete manual-signing UI, so you can get a TEST device's certificate signed and installed without writing any of this yourself.

### What happens under the hood

For completeness, when a TEST device needs its ECC certificate signed, setup:

1. Generates the CSR on the device.
2. Halts at `DeviceSetupState.MANUAL_ECC_SIGNING_REQUIRED` and delivers the raw CSR bytes via the `onManualEccSigningRequired` callback. (When this happens, `onSuccess`/`onError` are **not** called for that run.)

To complete provisioning:

1. Get the CSR signed, producing a signed `terminal-ecc-cert.json`.
2. Install it with `installEccTerminalCert()`; the device restarts automatically on success.
3. Call `ensureDeviceReady()` again to finish setup.

The sample app implements exactly this flow. If you do need to drive it yourself, the callback receives the CSR bytes:

## Error handling

If a setup step fails, `onError` is invoked on the main thread with a `ToroException`. Setup does not partially "succeed"; re-running `ensureDeviceReady()` after resolving the cause will resume from wherever the device currently is, skipping any steps already completed.
