Package-level declarations

Types

Link copied to clipboard
class BrainAccessClient(transport: Transport, store: ConfigStore = InMemoryConfigStore(), scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default))

Entry point: owns the scanner (app-scoped, independent of connections, so scan-while- connected is trivial) and the live DeviceSessions. Multiple simultaneous devices are supported — each connection is an independent session with its own scope.

Link copied to clipboard

Typed failures surfaced by the SDK. Fallible operations return Result carrying one of these instead of crashing or swallowing the error (the legacy code returned false / dropped silently). Transport implementations map their stack's errors onto these.

Link copied to clipboard

JSON (de)serialization for DeviceConfig. Lives in :core (not :protocol) to keep the protocol module dependency-free. Electrode labels ARE stored: they are user-edited, so deriving them from the model would silently discard a custom montage on reconnect.

Link copied to clipboard
interface ConfigStore

Per-headset config persistence, behind an interface so it is swappable (SharedPreferences today, DataStore later) and fakeable in tests. Replaces the legacy mutable static companion { var currentConfig } shared across instances.

Link copied to clipboard
value class DeviceId(val value: String)

Opaque device handle (BLE address/uuid), abstracted away from the OS BLE types.

Link copied to clipboard
data class DeviceInfo(val manufacturer: String?, val modelNumber: String?, val hardwareVersion: String?, val firmwareVersion: String?, val serialNumber: String?)

Device Information Service strings, read best-effort during DeviceSession.initialize. A characteristic the device does not expose — or a failed read — yields null; device info is never a reason to fail the handshake.

Link copied to clipboard

One connected device. Owns a supervised CoroutineScope cancelled on disconnect; the handshake awaits suspend acks from the GattConnection instead of polling a shared event log with magic delays (the legacy design). Fallible ops return Result.

Link copied to clipboard
sealed interface DeviceState

Lifecycle of a BrainAccessDevice, exposed as a StateFlow.

Link copied to clipboard
class DiscoveredDevice(val id: DeviceId, val name: String, val model: DeviceModel, val rssi: Int = 0)

A scan result: enough to identify the device and pick its DeviceModel.

Link copied to clipboard
class EegChunk(val deviceId: DeviceId, val channels: List<String>, val srate: Int, val samples: FloatArray, val sampleCount: Int, val accel: FloatArray?, val gyro: FloatArray?, val firstSampleIndex: Long, val hostTimeNs: Long, val isDummy: BooleanArray, val contact: BooleanArray, val batteryPct: Float)

A batch of decoded samples from one stream packet — the efficient public unit (one object per packet, not per sample). Channel labels + srate travel with the data so consumers never reconstruct layout by hand (the legacy positional FloatArray contract is gone).

Link copied to clipboard
interface GattConnection

One device's GATT surface. Every fallible op suspends until the stack acknowledges it (the suspend-ack model that replaces the legacy poll-the-event-log state machine). Characteristic identifiers are the UUID strings from GattUuids.

Link copied to clipboard

Process-lifetime in-memory store; the default when no persistence is wired.

Link copied to clipboard
sealed interface OtaProgress

Progress of a DeviceSession.updateFirmware transfer.

Link copied to clipboard
class SharedPreferencesConfigStore(context: Context, fileName: String = "brainaccess_config") : ConfigStore

ConfigStore backed by SharedPreferences (one JSON entry per headset, keyed by the BLE address carried in DeviceId). Zero extra dependency beyond the platform. Exercised on-device (not in JVM unit tests); the JSON round-trip is covered by ConfigCodecTest.

Link copied to clipboard
interface Transport

Abstraction over the BLE stack. The production implementation lives in :transport-android (Nordic Android-BLE-Library); tests inject a fake. This interface is deliberately Android-free so all orchestration in :core is unit-testable on the JVM.