This repository has been archived by the owner on Aug 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathGattConnection.kt
69 lines (58 loc) · 2.08 KB
/
GattConnection.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*
* Copyright 2020 JUUL Labs, Inc.
*/
@file:Suppress("RedundantUnitReturnType")
package com.juul.able.gatt
import android.bluetooth.BluetoothGatt.GATT_SUCCESS
import android.bluetooth.BluetoothProfile
import android.bluetooth.BluetoothProfile.STATE_DISCONNECTED
import com.juul.able.Able
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.onEach
/**
* Represents the possible GATT connection statuses as defined in the Android source code.
*
* - [GATT_SUCCESS]
* - [GATT_CONN_L2C_FAILURE]
* - [GATT_CONN_L2C_FAILURE]
* - [GATT_CONN_TIMEOUT]
* - [GATT_CONN_TERMINATE_PEER_USER]
* - [GATT_CONN_TERMINATE_LOCAL_HOST]
* - [GATT_CONN_FAIL_ESTABLISH]
* - [GATT_CONN_LMP_TIMEOUT]
* - [GATT_CONN_CANCEL]
*/
typealias GattConnectionStatus = Int
/**
* Represents the possible GATT states as defined in [BluetoothProfile]:
*
* - [BluetoothProfile.STATE_DISCONNECTED]
* - [BluetoothProfile.STATE_CONNECTING]
* - [BluetoothProfile.STATE_CONNECTED]
* - [BluetoothProfile.STATE_DISCONNECTING]
*/
typealias GattConnectionState = Int
interface GattConnection {
@FlowPreview
val onConnectionStateChange: Flow<OnConnectionStateChange>
suspend fun disconnect(): Unit
}
class GattStatusFailure(
val event: OnConnectionStateChange
) : IllegalStateException("Received $event")
class ConnectionLost : Exception()
internal suspend fun GattConnection.suspendUntilConnectionState(state: GattConnectionState) {
Able.debug { "Suspending until ${state.asGattConnectionStateString()}" }
onConnectionStateChange
.onEach { event ->
Able.verbose { "← Received $event while waiting for ${state.asGattConnectionStateString()}" }
if (event.status != GATT_SUCCESS) throw GattStatusFailure(event)
if (event.newState == STATE_DISCONNECTED && state != STATE_DISCONNECTED) throw ConnectionLost()
}
.first { (_, newState) -> newState == state }
.also { (_, newState) ->
Able.info { "Reached ${newState.asGattConnectionStateString()}" }
}
}