From 415b1bd0c91f166d5e175f7cfd9888bfc404954a Mon Sep 17 00:00:00 2001 From: Azalea Gui Date: Tue, 24 Jan 2023 11:43:15 -0500 Subject: [PATCH] [+] Observers ver.1 --- .../hydev/wearsync/bles/BluetoothHandler.kt | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/org/hydev/wearsync/bles/BluetoothHandler.kt b/app/src/main/java/org/hydev/wearsync/bles/BluetoothHandler.kt index 2f5ca79..e92e076 100644 --- a/app/src/main/java/org/hydev/wearsync/bles/BluetoothHandler.kt +++ b/app/src/main/java/org/hydev/wearsync/bles/BluetoothHandler.kt @@ -3,27 +3,16 @@ package org.hydev.wearsync.bles import android.content.Context import com.welie.blessed.* import kotlinx.coroutines.* -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED import org.hydev.wearsync.BluePeri import org.hydev.wearsync.bles.decoders.* import timber.log.Timber import timber.log.Timber.DebugTree -import java.util.* +import kotlin.reflect.KClass internal class BluetoothHandler private constructor(context: Context) { var central: BluetoothCentralManager val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) - val batteryChannel = Channel(UNLIMITED) - val heartRateChannel = Channel(UNLIMITED) - val bloodPressureChannel = Channel(UNLIMITED) - val glucoseChannel = Channel(UNLIMITED) - val pulseOxSpotChannel = Channel(UNLIMITED) - val pulseOxContinuousChannel = Channel(UNLIMITED) - val temperatureChannel = Channel(UNLIMITED) - val weightChannel = Channel(UNLIMITED) - private fun BluePeri.handle() { scope.launch { try { @@ -34,48 +23,42 @@ internal class BluetoothHandler private constructor(context: Context) { Timber.i("Received: ${read(ModelDecoder())}") Timber.i("Battery level: ${read(BatteryDecoder())}") - observe(batteryChannel, BatteryDecoder()) - observe(heartRateChannel, HeartRateDecoder()) - observe(temperatureChannel, TemperatureDecoder()) - observe(weightChannel, WeightDecoder()) - observe(bloodPressureChannel, BloodPressureDecoder()) - observe(pulseOxSpotChannel, PLXSpotDecoder()) - observe(pulseOxContinuousChannel, PLXContinuousDecoder()) - } catch (e: IllegalArgumentException) { - Timber.e(e) - } catch (b: GattException) { - Timber.e(b) + decoders.forEach { observe(it) } } + catch (e: IllegalArgumentException) { Timber.e(e) } + catch (b: GattException) { Timber.e(b) } } } - /** - * Observe a specific mesasurement - */ - suspend fun BluePeri.observe(dec: IDecoder, callback: (T) -> Unit) { - getCharacteristic(dec.sid, dec.cid)?.let { - observe(it) { value -> - val measurement = dec.decode(value) - callback(measurement) - Timber.d(measurement.toString()) - } - } - dec.additionalSetup(this) + val listeners = HashMap, MutableList<(Any) -> Unit>>() + + inline fun > observe(crossinline cb: (M) -> Unit) + { + (listeners[D::class] ?: error("Cannot observe unknown decoder class ${D::class}")) + .add { cb(it as M) } } - suspend fun BluePeri.observe(chan: Channel, dec: IDecoder) = - observe(dec) { chan.trySend(it) } + private suspend fun BluePeri.observe(dec: IDecoder) { + val cls = dec::class + listeners[cls] = ArrayList() + + observe(dec) { + listeners[cls]?.forEach { cb -> cb(it) } + } + } /** * Scan and connect to a peripheral at a specific address */ fun connectAddress(address: String, callback: (BluePeri) -> Unit = {}) { + Timber.d("Scanning for device with address $address") central.stopScan() - central.scanForPeripheralsWithAddresses(arrayOf(address), { peripheral, scanResult -> - if (peripheral.address != address) return@scanForPeripheralsWithAddresses + central.scanForPeripheralsWithAddresses(arrayOf(address), { peri, _ -> + if (peri.address != address) return@scanForPeripheralsWithAddresses + Timber.d("Device found, connecting...") central.stopScan() - connectPeripheral(peripheral) { callback(peripheral) } + connectPeripheral(peri) { callback(peri) } }, {}) } @@ -93,6 +76,9 @@ internal class BluetoothHandler private constructor(context: Context) { } companion object { + val decoders = listOf(BatteryDecoder(), BloodPressureDecoder(), GlucoseDecoder(), HeartRateDecoder(), + PLXSpotDecoder(), PLXContinuousDecoder(), TemperatureDecoder(), WeightDecoder()) + private var instance: BluetoothHandler? = null val Context.ble get(): BluetoothHandler { if (instance == null) { @@ -103,6 +89,20 @@ internal class BluetoothHandler private constructor(context: Context) { suspend fun BluePeri.read(decoder: IDecoder) = getCharacteristic(decoder.sid, decoder.cid)?.let { decoder.decode(readCharacteristic(it)) } + + /** + * Observe a specific measurement + */ + private suspend fun BluePeri.observe(dec: IDecoder, callback: (T) -> Unit) { + getCharacteristic(dec.sid, dec.cid)?.let { + observe(it) { value -> + val measurement = dec.decode(value) + callback(measurement) + Timber.d(measurement.toString()) + } + } + dec.additionalSetup(this) + } } init {