From cde26ccf56928c86400f33008430ebca5ab229b9 Mon Sep 17 00:00:00 2001 From: Travis Wyatt Date: Mon, 11 Jan 2021 23:39:32 -0800 Subject: [PATCH 1/4] Simplify/optimize characteristic and descriptor lookups When a service, characteristic or descriptor cannot be found, `IOException` is now thrown with a `message` stating the UUID that could not be found. On Apple platform, services are now cached on service discovery (which matches behavior of the other platform targets). Closes #14 Closes #38 --- core/src/androidMain/kotlin/Peripheral.kt | 102 ++++++------------ .../src/androidMain/kotlin/PlatformService.kt | 36 +++++++ core/src/commonMain/kotlin/Characteristic.kt | 5 + core/src/commonMain/kotlin/Descriptor.kt | 9 ++ core/src/commonMain/kotlin/Service.kt | 6 ++ core/src/jsMain/kotlin/Peripheral.kt | 46 +++----- core/src/jsMain/kotlin/PlatformService.kt | 36 +++++++ core/src/macosX64Main/kotlin/Peripheral.kt | 53 +++------ .../macosX64Main/kotlin/PlatformService.kt | 36 +++++++ 9 files changed, 191 insertions(+), 138 deletions(-) diff --git a/core/src/androidMain/kotlin/Peripheral.kt b/core/src/androidMain/kotlin/Peripheral.kt index ffa20238a..0a15a5cf0 100644 --- a/core/src/androidMain/kotlin/Peripheral.kt +++ b/core/src/androidMain/kotlin/Peripheral.kt @@ -1,7 +1,6 @@ package com.juul.kable import android.bluetooth.BluetoothDevice -import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT import android.bluetooth.BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE import android.bluetooth.BluetoothGattDescriptor @@ -70,9 +69,12 @@ public class AndroidPeripheral internal constructor( private val observers = Observers(this) @Volatile - internal var platformServices: List? = null + private var _platformServices: List? = null + private val platformServices: List + get() = checkNotNull(_platformServices) { "Services have not been discovered for $this" } + public override val services: List? - get() = platformServices?.map { it.toDiscoveredService() } + get() = _platformServices?.map { it.toDiscoveredService() } @Volatile private var _connection: Connection? = null @@ -144,7 +146,7 @@ public class AndroidPeripheral internal constructor( connection.execute { discoverServices() } - platformServices = connection.bluetoothGatt + _platformServices = connection.bluetoothGatt .services .map { it.toPlatformService() } } @@ -206,37 +208,50 @@ public class AndroidPeripheral internal constructor( ): Flow = observers.acquire(characteristic) internal suspend fun startNotifications(characteristic: Characteristic) { - val bluetoothGattCharacteristic = bluetoothGattCharacteristicFrom(characteristic) - connection.bluetoothGatt.setCharacteristicNotification(bluetoothGattCharacteristic, true) - writeConfigDescriptor(characteristic, ENABLE_NOTIFICATION_VALUE) + val platformCharacteristic = platformServices.findCharacteristic(characteristic) + connection + .bluetoothGatt + .setCharacteristicNotification(platformCharacteristic.bluetoothGattCharacteristic, true) + + writeConfigDescriptor(platformCharacteristic, ENABLE_NOTIFICATION_VALUE) } internal suspend fun stopNotifications(characteristic: Characteristic) { - writeConfigDescriptor(characteristic, DISABLE_NOTIFICATION_VALUE) - val bluetoothGattCharacteristic = bluetoothGattCharacteristicFrom(characteristic) - connection.bluetoothGatt.setCharacteristicNotification(bluetoothGattCharacteristic, false) + val platformCharacteristic = platformServices.findCharacteristic(characteristic) + writeConfigDescriptor(platformCharacteristic, DISABLE_NOTIFICATION_VALUE) + + val bluetoothGattCharacteristic = platformCharacteristic.bluetoothGattCharacteristic + connection + .bluetoothGatt + .setCharacteristicNotification(bluetoothGattCharacteristic, false) } private suspend fun writeConfigDescriptor( - characteristic: Characteristic, + characteristic: PlatformCharacteristic, value: ByteArray ) { if (writeObserveDescriptor == Never) return - val descriptor = LazyDescriptor( - serviceUuid = characteristic.serviceUuid, - characteristicUuid = characteristic.characteristicUuid, - descriptorUuid = clientCharacteristicConfigUuid - ) - val bluetoothGattDescriptor = bluetoothGattDescriptorOrNullFrom(descriptor) + val bluetoothGattDescriptor = characteristic + .descriptors + .firstOrNull(clientCharacteristicConfigUuid) + ?.bluetoothGattDescriptor if (bluetoothGattDescriptor != null) { write(bluetoothGattDescriptor, value) } else if (writeObserveDescriptor == Always) { - error("Unable to start observation for $characteristic, config descriptor not found.") + error("Unable to start observation for characteristic ${characteristic.characteristicUuid}, config descriptor not found.") } } + private fun bluetoothGattCharacteristicFrom( + characteristic: Characteristic + ) = platformServices.findCharacteristic(characteristic).bluetoothGattCharacteristic + + private fun bluetoothGattDescriptorFrom( + descriptor: Descriptor + ) = platformServices.findDescriptor(descriptor).bluetoothGattDescriptor + override fun toString(): String = "Peripheral(bluetoothDevice=$bluetoothDevice)" } @@ -250,57 +265,6 @@ private suspend fun Peripheral.suspendUntilDisconnected() { state.first { it is State.Disconnected } } -private fun AndroidPeripheral.bluetoothGattCharacteristicFrom( - characteristic: Characteristic, -): BluetoothGattCharacteristic { - val services = checkNotNull(platformServices) { - "Services have not been discovered for $this" - } - - val characteristics = services - .first { characteristic.serviceUuid == it.serviceUuid } - .characteristics - return characteristics - .first { characteristic.characteristicUuid == it.characteristicUuid } - .bluetoothGattCharacteristic -} - -private fun AndroidPeripheral.bluetoothGattDescriptorFrom( - descriptor: Descriptor, -): BluetoothGattDescriptor { - val services = checkNotNull(platformServices) { - "Services have not been discovered for $this" - } - - val characteristics = services - .first { descriptor.serviceUuid == it.serviceUuid } - .characteristics - val descriptors = characteristics - .first { descriptor.characteristicUuid == it.characteristicUuid } - .descriptors - return descriptors - .first { descriptor.descriptorUuid == it.descriptorUuid } - .bluetoothGattDescriptor -} - -private fun AndroidPeripheral.bluetoothGattDescriptorOrNullFrom( - descriptor: Descriptor, -): BluetoothGattDescriptor? { - val services = checkNotNull(platformServices) { - "Services have not been discovered for $this" - } - - val characteristics = services - .firstOrNull { descriptor.serviceUuid == it.serviceUuid } - ?.characteristics - val descriptors = characteristics - ?.firstOrNull { descriptor.characteristicUuid == it.characteristicUuid } - ?.descriptors - return descriptors - ?.firstOrNull { descriptor.descriptorUuid == it.descriptorUuid } - ?.bluetoothGattDescriptor -} - private val WriteType.intValue: Int get() = when (this) { WithResponse -> WRITE_TYPE_DEFAULT diff --git a/core/src/androidMain/kotlin/PlatformService.kt b/core/src/androidMain/kotlin/PlatformService.kt index 9a4c9d264..682ebf22a 100644 --- a/core/src/androidMain/kotlin/PlatformService.kt +++ b/core/src/androidMain/kotlin/PlatformService.kt @@ -26,3 +26,39 @@ internal fun BluetoothGattService.toPlatformService(): PlatformService { bluetoothGattService = this, ) } + +/** @throws IOException if service or characteristic is not found. */ +internal fun List.findCharacteristic( + characteristic: Characteristic +) = findCharacteristic( + serviceUuid = characteristic.serviceUuid, + characteristicUuid = characteristic.characteristicUuid +) + +/** @throws IOException if service or characteristic is not found. */ +private fun List.findCharacteristic( + serviceUuid: Uuid, + characteristicUuid: Uuid +): PlatformCharacteristic = this + .first(serviceUuid) + .characteristics + .first(characteristicUuid) + +/** @throws IOException if service, characteristic or descriptor is not found. */ +internal fun List.findDescriptor( + descriptor: Descriptor +) = findDescriptor( + serviceUuid = descriptor.serviceUuid, + characteristicUuid = descriptor.characteristicUuid, + descriptorUuid = descriptor.descriptorUuid +) + +/** @throws IOException if service, characteristic or descriptor is not found. */ +private fun List.findDescriptor( + serviceUuid: Uuid, + characteristicUuid: Uuid, + descriptorUuid: Uuid +): PlatformDescriptor = + this.findCharacteristic(serviceUuid, characteristicUuid) + .descriptors + .first(descriptorUuid) diff --git a/core/src/commonMain/kotlin/Characteristic.kt b/core/src/commonMain/kotlin/Characteristic.kt index 64f516f31..798dc7b3f 100644 --- a/core/src/commonMain/kotlin/Characteristic.kt +++ b/core/src/commonMain/kotlin/Characteristic.kt @@ -26,3 +26,8 @@ public data class DiscoveredCharacteristic internal constructor( override val characteristicUuid: Uuid, public val descriptors: List, ) : Characteristic + +internal fun List.first( + characteristicUuid: Uuid +): T = firstOrNull { it.characteristicUuid == characteristicUuid } + ?: throw IOException("Characteristic $characteristicUuid not found") diff --git a/core/src/commonMain/kotlin/Descriptor.kt b/core/src/commonMain/kotlin/Descriptor.kt index d598b8f90..f8dc47a65 100644 --- a/core/src/commonMain/kotlin/Descriptor.kt +++ b/core/src/commonMain/kotlin/Descriptor.kt @@ -24,3 +24,12 @@ public data class LazyDescriptor( public override val characteristicUuid: Uuid, public override val descriptorUuid: Uuid, ) : Descriptor + +internal fun List.first( + descriptorUuid: Uuid +): T = firstOrNull(descriptorUuid) + ?: throw IOException("Descriptor $descriptorUuid not found") + +internal fun List.firstOrNull( + descriptorUuid: Uuid +): T? = firstOrNull { it.descriptorUuid == descriptorUuid } diff --git a/core/src/commonMain/kotlin/Service.kt b/core/src/commonMain/kotlin/Service.kt index b10a44569..e8779e80a 100644 --- a/core/src/commonMain/kotlin/Service.kt +++ b/core/src/commonMain/kotlin/Service.kt @@ -10,3 +10,9 @@ public data class DiscoveredService internal constructor( override val serviceUuid: Uuid, public val characteristics: List, ) : Service + +/** @throws IOException if service is not found. */ +internal fun List.first( + serviceUuid: Uuid +): T = firstOrNull { it.serviceUuid == serviceUuid } + ?: throw IOException("Service $serviceUuid not found") diff --git a/core/src/jsMain/kotlin/Peripheral.kt b/core/src/jsMain/kotlin/Peripheral.kt index 61be5c6f3..9ef63fc21 100644 --- a/core/src/jsMain/kotlin/Peripheral.kt +++ b/core/src/jsMain/kotlin/Peripheral.kt @@ -6,8 +6,6 @@ import com.juul.kable.WriteType.WithResponse import com.juul.kable.WriteType.WithoutResponse import com.juul.kable.external.BluetoothAdvertisingEvent import com.juul.kable.external.BluetoothDevice -import com.juul.kable.external.BluetoothRemoteGATTCharacteristic -import com.juul.kable.external.BluetoothRemoteGATTDescriptor import com.juul.kable.external.BluetoothRemoteGATTServer import com.juul.kable.external.string import kotlinx.coroutines.CancellationException @@ -52,9 +50,12 @@ public class JsPeripheral internal constructor( private val _state = MutableStateFlow(null) public override val state: Flow = _state.filterNotNull() - private var platformServices: List? = null + private var _platformServices: List? = null + private val platformServices: List + get() = checkNotNull(_platformServices) { "Services have not been discovered for $this" } + public override val services: List? - get() = platformServices?.map { it.toDiscoveredService() } + get() = _platformServices?.map { it.toDiscoveredService() } private val supportsAdvertisements = js("BluetoothDevice.prototype.watchAdvertisements") != null @@ -138,7 +139,7 @@ public class JsPeripheral internal constructor( val services = gatt.getPrimaryServices() .await() .map { it.toPlatformService() } - platformServices = services + _platformServices = services return services } @@ -199,33 +200,6 @@ public class JsPeripheral internal constructor( ): Flow = observeDataView(characteristic) .map { it.buffer.toByteArray() } - internal fun bluetoothRemoteGATTCharacteristicFrom( - characteristic: Characteristic - ): BluetoothRemoteGATTCharacteristic { - val services = checkNotNull(platformServices) { "Services have not been discovered for $this" } - val characteristics = services - .first { it.serviceUuid == characteristic.serviceUuid } - .characteristics - return characteristics - .first { it.characteristicUuid == characteristic.characteristicUuid } - .bluetoothRemoteGATTCharacteristic - } - - private fun bluetoothRemoteGATTDescriptorFrom( - descriptor: Descriptor - ): BluetoothRemoteGATTDescriptor { - val services = checkNotNull(platformServices) { "Services have not been discovered for $this" } - val characteristics = services - .first { service -> service.serviceUuid == descriptor.serviceUuid } - .characteristics - val descriptors = characteristics - .first { it.characteristicUuid == descriptor.characteristicUuid } - .descriptors - return descriptors - .first { it.descriptorUuid == descriptor.descriptorUuid } - .bluetoothRemoteGATTDescriptor - } - private var isDisconnectedListenerRegistered = false private val disconnectedListener: (JsEvent) -> Unit = { event -> console.dir(event) @@ -246,5 +220,13 @@ public class JsPeripheral internal constructor( bluetoothDevice.removeEventListener(GATT_SERVER_DISCONNECTED, disconnectedListener) } + internal fun bluetoothRemoteGATTCharacteristicFrom( + characteristic: Characteristic + ) = platformServices.findCharacteristic(characteristic).bluetoothRemoteGATTCharacteristic + + private fun bluetoothRemoteGATTDescriptorFrom( + descriptor: Descriptor + ) = platformServices.findDescriptor(descriptor).bluetoothRemoteGATTDescriptor + override fun toString(): String = "Peripheral(bluetoothDevice=${bluetoothDevice.string()})" } diff --git a/core/src/jsMain/kotlin/PlatformService.kt b/core/src/jsMain/kotlin/PlatformService.kt index 60ba757f8..799e4dc2b 100644 --- a/core/src/jsMain/kotlin/PlatformService.kt +++ b/core/src/jsMain/kotlin/PlatformService.kt @@ -30,3 +30,39 @@ internal suspend fun BluetoothRemoteGATTService.toPlatformService(): PlatformSer bluetoothRemoteGATTService = this, ) } + +/** @throws IOException if service or characteristic is not found. */ +internal fun List.findCharacteristic( + characteristic: Characteristic +) = findCharacteristic( + serviceUuid = characteristic.serviceUuid, + characteristicUuid = characteristic.characteristicUuid +) + +/** @throws IOException if service or characteristic is not found. */ +private fun List.findCharacteristic( + serviceUuid: Uuid, + characteristicUuid: Uuid +): PlatformCharacteristic = this + .first(serviceUuid) + .characteristics + .first(characteristicUuid) + +/** @throws IOException if service, characteristic or descriptor is not found. */ +internal fun List.findDescriptor( + descriptor: Descriptor +) = findDescriptor( + serviceUuid = descriptor.serviceUuid, + characteristicUuid = descriptor.characteristicUuid, + descriptorUuid = descriptor.descriptorUuid +) + +/** @throws IOException if service, characteristic or descriptor is not found. */ +private fun List.findDescriptor( + serviceUuid: Uuid, + characteristicUuid: Uuid, + descriptorUuid: Uuid +): PlatformDescriptor = + this.findCharacteristic(serviceUuid, characteristicUuid) + .descriptors + .first(descriptorUuid) diff --git a/core/src/macosX64Main/kotlin/Peripheral.kt b/core/src/macosX64Main/kotlin/Peripheral.kt index 714a50516..a5cfcf746 100644 --- a/core/src/macosX64Main/kotlin/Peripheral.kt +++ b/core/src/macosX64Main/kotlin/Peripheral.kt @@ -48,11 +48,9 @@ import kotlinx.coroutines.flow.takeWhile import kotlinx.coroutines.job import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.withContext -import platform.CoreBluetooth.CBCharacteristic import platform.CoreBluetooth.CBCharacteristicWriteType import platform.CoreBluetooth.CBCharacteristicWriteWithResponse import platform.CoreBluetooth.CBCharacteristicWriteWithoutResponse -import platform.CoreBluetooth.CBDescriptor import platform.CoreBluetooth.CBErrorConnectionFailed import platform.CoreBluetooth.CBErrorConnectionLimitReached import platform.CoreBluetooth.CBErrorConnectionTimeout @@ -91,14 +89,14 @@ public class ApplePeripheral internal constructor( private val observers = Observers(this) - internal val platformServices: List? - get() = cbPeripheral.services?.map { service -> - service as CBService - service.toPlatformService() + private val _platformServices = atomic?>(null) + private val platformServices: List + get() = checkNotNull(_platformServices.value) { + "Services have not been discovered for $this" } public override val services: List? - get() = platformServices?.map { it.toDiscoveredService() } + get() = _platformServices.value?.map { it.toDiscoveredService() } private val _connection = atomic(null) private val connection: Connection @@ -194,6 +192,10 @@ public class ApplePeripheral internal constructor( centralManager.discoverCharacteristics(cbPeripheral, cbService as CBService) } } + + _platformServices.value = cbPeripheral.services?.map { service -> + (service as CBService).toPlatformService() + } } @Throws(CancellationException::class, IOException::class, NotReadyException::class) @@ -290,38 +292,15 @@ public class ApplePeripheral internal constructor( } } - override fun toString(): String = "Peripheral(cbPeripheral=$cbPeripheral)" -} + private fun cbCharacteristicFrom( + characteristic: Characteristic + ) = platformServices.findCharacteristic(characteristic).cbCharacteristic -internal fun ApplePeripheral.cbCharacteristicFrom( - characteristic: Characteristic, -): CBCharacteristic { - val services = checkNotNull(platformServices) { - "Services have not been discovered for $this" - } - val characteristics = services - .first { it.serviceUuid == characteristic.serviceUuid } - .characteristics - return characteristics - .first { it.characteristicUuid == characteristic.characteristicUuid } - .cbCharacteristic -} + private fun cbDescriptorFrom( + descriptor: Descriptor + ) = platformServices.findDescriptor(descriptor).cbDescriptor -private fun ApplePeripheral.cbDescriptorFrom( - descriptor: Descriptor, -): CBDescriptor { - val services = checkNotNull(platformServices) { - "Services have not been discovered for $this" - } - val characteristics = services - .first { it.serviceUuid == descriptor.serviceUuid } - .characteristics - val descriptors = characteristics - .first { it.characteristicUuid == descriptor.characteristicUuid } - .descriptors - return descriptors - .first { it.descriptorUuid == descriptor.descriptorUuid } - .cbDescriptor + override fun toString(): String = "Peripheral(cbPeripheral=$cbPeripheral)" } private suspend fun Peripheral.suspendUntilConnected() { diff --git a/core/src/macosX64Main/kotlin/PlatformService.kt b/core/src/macosX64Main/kotlin/PlatformService.kt index 2a7dca04c..e92f034b9 100644 --- a/core/src/macosX64Main/kotlin/PlatformService.kt +++ b/core/src/macosX64Main/kotlin/PlatformService.kt @@ -28,3 +28,39 @@ internal fun CBService.toPlatformService(): PlatformService { cbService = this, ) } + +/** @throws IOException if service or characteristic is not found. */ +internal fun List.findCharacteristic( + characteristic: Characteristic +) = findCharacteristic( + serviceUuid = characteristic.serviceUuid, + characteristicUuid = characteristic.characteristicUuid +) + +/** @throws IOException if service or characteristic is not found. */ +private fun List.findCharacteristic( + serviceUuid: Uuid, + characteristicUuid: Uuid +): PlatformCharacteristic = this + .first(serviceUuid) + .characteristics + .first(characteristicUuid) + +/** @throws IOException if service, characteristic or descriptor is not found. */ +internal fun List.findDescriptor( + descriptor: Descriptor +) = findDescriptor( + serviceUuid = descriptor.serviceUuid, + characteristicUuid = descriptor.characteristicUuid, + descriptorUuid = descriptor.descriptorUuid +) + +/** @throws IOException if service, characteristic or descriptor is not found. */ +private fun List.findDescriptor( + serviceUuid: Uuid, + characteristicUuid: Uuid, + descriptorUuid: Uuid +): PlatformDescriptor = + this.findCharacteristic(serviceUuid, characteristicUuid) + .descriptors + .first(descriptorUuid) From 39e3d2492c5c9ebbf87a9b921b8aa5b2c0d57d36 Mon Sep 17 00:00:00 2001 From: Travis Wyatt Date: Wed, 13 Jan 2021 13:41:40 -0800 Subject: [PATCH 2/4] IOException -> NoSuchElementException --- core/src/commonMain/kotlin/Characteristic.kt | 2 +- core/src/commonMain/kotlin/Descriptor.kt | 2 +- core/src/commonMain/kotlin/Service.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/commonMain/kotlin/Characteristic.kt b/core/src/commonMain/kotlin/Characteristic.kt index 798dc7b3f..2379289ce 100644 --- a/core/src/commonMain/kotlin/Characteristic.kt +++ b/core/src/commonMain/kotlin/Characteristic.kt @@ -30,4 +30,4 @@ public data class DiscoveredCharacteristic internal constructor( internal fun List.first( characteristicUuid: Uuid ): T = firstOrNull { it.characteristicUuid == characteristicUuid } - ?: throw IOException("Characteristic $characteristicUuid not found") + ?: throw NoSuchElementException("Characteristic $characteristicUuid not found") diff --git a/core/src/commonMain/kotlin/Descriptor.kt b/core/src/commonMain/kotlin/Descriptor.kt index f8dc47a65..5a3fa79de 100644 --- a/core/src/commonMain/kotlin/Descriptor.kt +++ b/core/src/commonMain/kotlin/Descriptor.kt @@ -28,7 +28,7 @@ public data class LazyDescriptor( internal fun List.first( descriptorUuid: Uuid ): T = firstOrNull(descriptorUuid) - ?: throw IOException("Descriptor $descriptorUuid not found") + ?: throw NoSuchElementException("Descriptor $descriptorUuid not found") internal fun List.firstOrNull( descriptorUuid: Uuid diff --git a/core/src/commonMain/kotlin/Service.kt b/core/src/commonMain/kotlin/Service.kt index e8779e80a..89693fd2e 100644 --- a/core/src/commonMain/kotlin/Service.kt +++ b/core/src/commonMain/kotlin/Service.kt @@ -15,4 +15,4 @@ public data class DiscoveredService internal constructor( internal fun List.first( serviceUuid: Uuid ): T = firstOrNull { it.serviceUuid == serviceUuid } - ?: throw IOException("Service $serviceUuid not found") + ?: throw NoSuchElementException("Service $serviceUuid not found") From 9ae60f65c833c525b80afc3a22f878a0e2d95311 Mon Sep 17 00:00:00 2001 From: Travis Wyatt Date: Wed, 13 Jan 2021 13:56:10 -0800 Subject: [PATCH 3/4] Fix code style in PlatformService classes --- .../src/androidMain/kotlin/PlatformService.kt | 43 ++++++++++--------- core/src/jsMain/kotlin/PlatformService.kt | 43 ++++++++++--------- .../macosX64Main/kotlin/PlatformService.kt | 43 ++++++++++--------- 3 files changed, 69 insertions(+), 60 deletions(-) diff --git a/core/src/androidMain/kotlin/PlatformService.kt b/core/src/androidMain/kotlin/PlatformService.kt index 682ebf22a..0c8c23f9f 100644 --- a/core/src/androidMain/kotlin/PlatformService.kt +++ b/core/src/androidMain/kotlin/PlatformService.kt @@ -27,38 +27,41 @@ internal fun BluetoothGattService.toPlatformService(): PlatformService { ) } -/** @throws IOException if service or characteristic is not found. */ +/** @throws NoSuchElementException if service or characteristic is not found. */ internal fun List.findCharacteristic( characteristic: Characteristic -) = findCharacteristic( - serviceUuid = characteristic.serviceUuid, - characteristicUuid = characteristic.characteristicUuid -) +): PlatformCharacteristic = + findCharacteristic( + serviceUuid = characteristic.serviceUuid, + characteristicUuid = characteristic.characteristicUuid + ) -/** @throws IOException if service or characteristic is not found. */ +/** @throws NoSuchElementException if service or characteristic is not found. */ private fun List.findCharacteristic( serviceUuid: Uuid, characteristicUuid: Uuid -): PlatformCharacteristic = this - .first(serviceUuid) - .characteristics - .first(characteristicUuid) +): PlatformCharacteristic = + first(serviceUuid) + .characteristics + .first(characteristicUuid) -/** @throws IOException if service, characteristic or descriptor is not found. */ +/** @throws NoSuchElementException if service, characteristic or descriptor is not found. */ internal fun List.findDescriptor( descriptor: Descriptor -) = findDescriptor( - serviceUuid = descriptor.serviceUuid, - characteristicUuid = descriptor.characteristicUuid, - descriptorUuid = descriptor.descriptorUuid -) +): PlatformDescriptor = + findDescriptor( + serviceUuid = descriptor.serviceUuid, + characteristicUuid = descriptor.characteristicUuid, + descriptorUuid = descriptor.descriptorUuid + ) -/** @throws IOException if service, characteristic or descriptor is not found. */ +/** @throws NoSuchElementException if service, characteristic or descriptor is not found. */ private fun List.findDescriptor( serviceUuid: Uuid, characteristicUuid: Uuid, descriptorUuid: Uuid ): PlatformDescriptor = - this.findCharacteristic(serviceUuid, characteristicUuid) - .descriptors - .first(descriptorUuid) + findCharacteristic( + serviceUuid = serviceUuid, + characteristicUuid = characteristicUuid + ).descriptors.first(descriptorUuid) diff --git a/core/src/jsMain/kotlin/PlatformService.kt b/core/src/jsMain/kotlin/PlatformService.kt index 799e4dc2b..b87a92dad 100644 --- a/core/src/jsMain/kotlin/PlatformService.kt +++ b/core/src/jsMain/kotlin/PlatformService.kt @@ -31,38 +31,41 @@ internal suspend fun BluetoothRemoteGATTService.toPlatformService(): PlatformSer ) } -/** @throws IOException if service or characteristic is not found. */ +/** @throws NoSuchElementException if service or characteristic is not found. */ internal fun List.findCharacteristic( characteristic: Characteristic -) = findCharacteristic( - serviceUuid = characteristic.serviceUuid, - characteristicUuid = characteristic.characteristicUuid -) +): PlatformCharacteristic = + findCharacteristic( + serviceUuid = characteristic.serviceUuid, + characteristicUuid = characteristic.characteristicUuid + ) -/** @throws IOException if service or characteristic is not found. */ +/** @throws NoSuchElementException if service or characteristic is not found. */ private fun List.findCharacteristic( serviceUuid: Uuid, characteristicUuid: Uuid -): PlatformCharacteristic = this - .first(serviceUuid) - .characteristics - .first(characteristicUuid) +): PlatformCharacteristic = + first(serviceUuid) + .characteristics + .first(characteristicUuid) -/** @throws IOException if service, characteristic or descriptor is not found. */ +/** @throws NoSuchElementException if service, characteristic or descriptor is not found. */ internal fun List.findDescriptor( descriptor: Descriptor -) = findDescriptor( - serviceUuid = descriptor.serviceUuid, - characteristicUuid = descriptor.characteristicUuid, - descriptorUuid = descriptor.descriptorUuid -) +): PlatformDescriptor = + findDescriptor( + serviceUuid = descriptor.serviceUuid, + characteristicUuid = descriptor.characteristicUuid, + descriptorUuid = descriptor.descriptorUuid + ) -/** @throws IOException if service, characteristic or descriptor is not found. */ +/** @throws NoSuchElementException if service, characteristic or descriptor is not found. */ private fun List.findDescriptor( serviceUuid: Uuid, characteristicUuid: Uuid, descriptorUuid: Uuid ): PlatformDescriptor = - this.findCharacteristic(serviceUuid, characteristicUuid) - .descriptors - .first(descriptorUuid) + findCharacteristic( + serviceUuid = serviceUuid, + characteristicUuid = characteristicUuid + ).descriptors.first(descriptorUuid) diff --git a/core/src/macosX64Main/kotlin/PlatformService.kt b/core/src/macosX64Main/kotlin/PlatformService.kt index e92f034b9..3c4a1ce6b 100644 --- a/core/src/macosX64Main/kotlin/PlatformService.kt +++ b/core/src/macosX64Main/kotlin/PlatformService.kt @@ -29,38 +29,41 @@ internal fun CBService.toPlatformService(): PlatformService { ) } -/** @throws IOException if service or characteristic is not found. */ +/** @throws NoSuchElementException if service or characteristic is not found. */ internal fun List.findCharacteristic( characteristic: Characteristic -) = findCharacteristic( - serviceUuid = characteristic.serviceUuid, - characteristicUuid = characteristic.characteristicUuid -) +): PlatformCharacteristic = + findCharacteristic( + serviceUuid = characteristic.serviceUuid, + characteristicUuid = characteristic.characteristicUuid + ) -/** @throws IOException if service or characteristic is not found. */ +/** @throws NoSuchElementException if service or characteristic is not found. */ private fun List.findCharacteristic( serviceUuid: Uuid, characteristicUuid: Uuid -): PlatformCharacteristic = this - .first(serviceUuid) - .characteristics - .first(characteristicUuid) +): PlatformCharacteristic = + first(serviceUuid) + .characteristics + .first(characteristicUuid) -/** @throws IOException if service, characteristic or descriptor is not found. */ +/** @throws NoSuchElementException if service, characteristic or descriptor is not found. */ internal fun List.findDescriptor( descriptor: Descriptor -) = findDescriptor( - serviceUuid = descriptor.serviceUuid, - characteristicUuid = descriptor.characteristicUuid, - descriptorUuid = descriptor.descriptorUuid -) +): PlatformDescriptor = + findDescriptor( + serviceUuid = descriptor.serviceUuid, + characteristicUuid = descriptor.characteristicUuid, + descriptorUuid = descriptor.descriptorUuid + ) -/** @throws IOException if service, characteristic or descriptor is not found. */ +/** @throws NoSuchElementException if service, characteristic or descriptor is not found. */ private fun List.findDescriptor( serviceUuid: Uuid, characteristicUuid: Uuid, descriptorUuid: Uuid ): PlatformDescriptor = - this.findCharacteristic(serviceUuid, characteristicUuid) - .descriptors - .first(descriptorUuid) + findCharacteristic( + serviceUuid = serviceUuid, + characteristicUuid = characteristicUuid + ).descriptors.first(descriptorUuid) From aa811d3f185c63bc43bb794cb0730443b515f44b Mon Sep 17 00:00:00 2001 From: Travis Wyatt Date: Wed, 13 Jan 2021 13:58:33 -0800 Subject: [PATCH 4/4] Minor code clean up --- core/src/androidMain/kotlin/Peripheral.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/androidMain/kotlin/Peripheral.kt b/core/src/androidMain/kotlin/Peripheral.kt index 0a15a5cf0..16ea480e6 100644 --- a/core/src/androidMain/kotlin/Peripheral.kt +++ b/core/src/androidMain/kotlin/Peripheral.kt @@ -240,7 +240,8 @@ public class AndroidPeripheral internal constructor( if (bluetoothGattDescriptor != null) { write(bluetoothGattDescriptor, value) } else if (writeObserveDescriptor == Always) { - error("Unable to start observation for characteristic ${characteristic.characteristicUuid}, config descriptor not found.") + val uuid = characteristic.characteristicUuid + error("Unable to start observation for characteristic $uuid, config descriptor not found.") } }