Package-level declarations

Types

Link copied to clipboard
data class BatteryGauge(val voltageMv: Float, val currentMa: Float, val healthPct: Float?, val chargeLevelPct: Float?)

Fuel-gauge reading from the device's "full battery info" characteristics. Read on demand via DeviceSession.readBatteryGauge; distinct from the coarse SIG Battery Level percentage carried on DeviceSession.battery.

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 throwing from the call site. Transport implementations map their stack's errors onto these.

Link copied to clipboard

Build identity of this SDK.

Link copied to clipboard
data class BrainAccessMetadata(val templateName: String, val template: String, val templateJson: MontageTemplate, val biasChannels: List<String>, val gain: List<Int>)

The brainaccess node of the metadata: BrainAccess-specific, not part of the XDF convention.

Link copied to clipboard
data class CapMetadata(val manufacturer: String?, val name: String?, val labelscheme: String?)

The cap node of the metadata.

Link copied to clipboard
data class ChannelMetadata(val label: String, val type: String, val unit: String, val location: Electrode? = null, val hardware: ElectrodeHardware? = null)

One recorded/streamed channel: label, contract type (com.neurotec.brainaccess.protocol.ChannelType), contract unit (com.neurotec.brainaccess.protocol.ChannelUnit) and, for EEG electrodes, the standard 10-05 location (mm, X right / Y front / Z up) and electrode hardware.

Link copied to clipboard
data class ChargingSettings(val stayOnWhileCharging: Boolean, val idlePowerOffMinutes: Int)

The device's charging-settings service (stay-on-while-charging and idle power-off). Both values live in device RAM: they survive a disconnect but revert to the defaults (off, 20 min) at power-off.

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.

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. 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 wireLastSampleIndex: Long, val packetBytes: Int, val hostTimeNs: Long, val isDummy: BooleanArray, val contact: BooleanArray, val batteryPct: Float, val digitalInput: BooleanArray? = null)

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.

Link copied to clipboard
data class ElectrodeHardware(val manufacturer: String, val coupling: String, val material: String, val surface: String)

Per-electrode hardware description (the hardware node of a channel in the LSL contract).

Link copied to clipboard
interface GattConnection

One device's GATT surface. Every fallible op suspends until the stack acknowledges it (suspend-ack model). 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
data class LinkInfo(val mtu: Int = 23, val txPhy: Int? = null, val rxPhy: Int? = null, val intervalUnits: Int? = null, val latency: Int? = null, val supervisionTimeoutUnits: Int? = null)

The negotiated BLE link parameters for one connection, as last reported by the stack.

Link copied to clipboard
data class MontageTemplate(val device: String, val template: String, val templateName: String, val channels: List<String>, val active: List<Boolean>, val pin: List<Int>, val bias: List<Boolean>, val gain: List<Int>, val reference: String, val ground: String, val capManufacturer: String, val capModel: String, val electrodeCoupling: String, val electrodeMaterial: String, val electrodePadChannels: List<String>, val srate: Int, val impedanceMode: Boolean, val testSignal: Boolean)

The montage settings that make a BrainAccess device reproducible — Board's template_json (its MONTAGE_KEYS subset of the template file), key for key.

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
data class StreamMetadata(val schemaVersion: Int = SCHEMA_VERSION, val origin: String = "device", val manufacturer: String?, val model: String?, val modelVariant: String?, val serialNumber: String?, val firmwareVersion: String?, val hardwareVersion: String?, val samplingRate: Double?, val reference: String?, val ground: String?, val hardwareFilters: Map<String, Map<String, String>>?, val cap: CapMetadata, val channels: List<ChannelMetadata>, val locationSource: String?, val testSignal: Boolean?, val impedanceMode: Boolean?, val notApplicable: List<String> = emptyList(), val brainaccess: BrainAccessMetadata?, val canDropSamples: Boolean?, val precisionBits: Int?, val versions: Map<String, String>?)

Stream metadata, BrainAccess Board StreamMetadata schema v1 field for field. Unknown values are null. toJson produces the JSON BrainAccess Board uses for recording metadata; the LSL outlet writes the same data into the stream header. The lsl field (set by Board for captured streams only) is always null here.

Link copied to clipboard
data class TimedRead(val value: ByteArray, val sentNs: Long, val receivedNs: Long)

One characteristic read with the host's monotonic clock around it, from GattConnection.readTimed.

Link copied to clipboard
data class TimeSyncInfo(val supported: Boolean, val pings: Long, val minRttMs: Double, val uplinkEnvelopeMs: Double, val sampleRateHz: Double, val valid: Boolean)

How DeviceSession.sampleIndexAt places host times on the device's sample counter, and how well the device's clock fits the host's. For diagnostics; nothing else depends on it.

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.

Properties

Link copied to clipboard

Column prefix of the per-electrode contact companions (contact_<label>).

Link copied to clipboard

Label of the digital-input column of the LSL contract.

Functions

Link copied to clipboard
fun lslContractChannels(eegLabels: List<String>, hasAccel: Boolean, hasGyro: Boolean, impedance: Boolean, digitalInput: Boolean = false): List<ChannelMetadata>

The channel list of a BrainAccess LSL stream, in BrainAccess Board LSL contract v1 column order: EEG electrodes, contact_<label> per electrode, Accel_x/y/z (if hasAccel), Gyro_x/y/z (if hasGyro), Digital (if digitalInput: type TRIG, unit value, 0 or 1 per sample, the level of the device's digital input; present only when the stream was started with it), Sample, Streaming, Battery.

Link copied to clipboard
fun DeviceSession.streamMetadata(channels: List<ChannelMetadata>, outputMode: OutputMode, software: Map<String, String> = emptyMap()): StreamMetadata

Build the StreamMetadata of this session for the given channels (the LSL path passes lslContractChannels; recorders pass their own file-specific lists). Identity fields come from the Device Information Service (DeviceSession.info; null when not read or blank), the montage from DeviceSession.currentConfig. software adds entries to versions (e.g. board); the SDK adds kotlin_sdk (BrainAccessKit.VERSION) and contract.