@@ -31,6 +31,8 @@ import kotlinx.coroutines.experimental.channels.BroadcastChannel
31
31
import java.util.UUID
32
32
import kotlin.coroutines.experimental.CoroutineContext
33
33
34
+ class GattClosed (message : String ) : IllegalStateException(message)
35
+
34
36
class CoroutinesGatt (
35
37
private val bluetoothGatt : BluetoothGatt ,
36
38
private val messenger : Messenger
@@ -79,6 +81,7 @@ class CoroutinesGatt(
79
81
80
82
/* *
81
83
* @throws [RemoteException] if underlying [BluetoothGatt.discoverServices] returns `false`.
84
+ * @throws [GattClosed] if [Gatt] is closed while method is executing.
82
85
*/
83
86
override suspend fun discoverServices (): GattStatus {
84
87
Able .debug { " discoverServices → send(DiscoverServices)" }
@@ -93,13 +96,14 @@ class CoroutinesGatt(
93
96
}
94
97
95
98
Able .verbose { " discoverServices → Waiting for BluetoothGattCallback" }
96
- return messenger.callback.onServicesDiscovered.receive() .also { status ->
99
+ return messenger.callback.onServicesDiscovered.receiveOrNull()? .also { status ->
97
100
Able .info { " discoverServices, status=${status.asGattStatusString()} " }
98
- }
101
+ } ? : throw GattClosed ( " Gatt closed during discoverServices " )
99
102
}
100
103
101
104
/* *
102
105
* @throws [RemoteException] if underlying [BluetoothGatt.readCharacteristic] returns `false`.
106
+ * @throws [GattClosed] if [Gatt] is closed while method is executing.
103
107
*/
104
108
override suspend fun readCharacteristic (
105
109
characteristic : BluetoothGattCharacteristic
@@ -117,19 +121,20 @@ class CoroutinesGatt(
117
121
}
118
122
119
123
Able .verbose { " readCharacteristic → Waiting for BluetoothGattCallback" }
120
- return messenger.callback.onCharacteristicRead.receive() .also { (_, value, status) ->
124
+ return messenger.callback.onCharacteristicRead.receiveOrNull()? .also { (_, value, status) ->
121
125
Able .info {
122
126
val bytesString = value.size.bytesString
123
127
val statusString = status.asGattStatusString()
124
128
" ← readCharacteristic $uuid ($bytesString ), status=$statusString "
125
129
}
126
- }
130
+ } ? : throw GattClosed ( " Gatt closed during readCharacteristic[uuid= $uuid ] " )
127
131
}
128
132
129
133
/* *
130
134
* @param value applied to [characteristic] when characteristic is written.
131
135
* @param writeType applied to [characteristic] when characteristic is written.
132
136
* @throws [RemoteException] if underlying [BluetoothGatt.writeCharacteristic] returns `false`.
137
+ * @throws [GattClosed] if [Gatt] is closed while method is executing.
133
138
*/
134
139
override suspend fun writeCharacteristic (
135
140
characteristic : BluetoothGattCharacteristic ,
@@ -149,19 +154,20 @@ class CoroutinesGatt(
149
154
}
150
155
151
156
Able .verbose { " writeCharacteristic → Waiting for BluetoothGattCallback" }
152
- return messenger.callback.onCharacteristicWrite.receive() .also { (_, status) ->
157
+ return messenger.callback.onCharacteristicWrite.receiveOrNull()? .also { (_, status) ->
153
158
Able .info {
154
159
val bytesString = value.size.bytesString
155
160
val typeString = writeType.asWriteTypeString()
156
161
val statusString = status.asGattStatusString()
157
162
" → writeCharacteristic $uuid ($bytesString ), type=$typeString , status=$statusString "
158
163
}
159
- }
164
+ } ? : throw GattClosed ( " Gatt closed during writeCharacteristic[uuid= $uuid ] " )
160
165
}
161
166
162
167
/* *
163
168
* @param value applied to [descriptor] when descriptor is written.
164
169
* @throws [RemoteException] if underlying [BluetoothGatt.writeDescriptor] returns `false`.
170
+ * @throws [GattClosed] if [Gatt] is closed while method is executing.
165
171
*/
166
172
override suspend fun writeDescriptor (
167
173
descriptor : BluetoothGattDescriptor , value : ByteArray
@@ -179,17 +185,18 @@ class CoroutinesGatt(
179
185
}
180
186
181
187
Able .verbose { " writeDescriptor → Waiting for BluetoothGattCallback" }
182
- return messenger.callback.onDescriptorWrite.receive() .also { (_, status) ->
188
+ return messenger.callback.onDescriptorWrite.receiveOrNull()? .also { (_, status) ->
183
189
Able .info {
184
190
val bytesString = value.size.bytesString
185
191
val statusString = status.asGattStatusString()
186
192
" → writeDescriptor $uuid ($bytesString ), status=$statusString "
187
193
}
188
- }
194
+ } ? : throw GattClosed ( " Gatt closed during writeDescriptor[uuid= $uuid ] " )
189
195
}
190
196
191
197
/* *
192
198
* @throws [RemoteException] if underlying [BluetoothGatt.requestMtu] returns `false`.
199
+ * @throws [GattClosed] if [Gatt] is closed while method is executing.
193
200
*/
194
201
override suspend fun requestMtu (mtu : Int ): OnMtuChanged {
195
202
Able .debug { " requestMtu → send(RequestMtu[mtu=$mtu ])" }
@@ -204,9 +211,9 @@ class CoroutinesGatt(
204
211
}
205
212
206
213
Able .verbose { " requestMtu → Waiting for BluetoothGattCallback" }
207
- return messenger.callback.onMtuChanged.receive() .also { (mtu, status) ->
214
+ return messenger.callback.onMtuChanged.receiveOrNull()? .also { (mtu, status) ->
208
215
Able .info { " requestMtu $mtu , status=${status.asGattStatusString()} " }
209
- }
216
+ } ? : throw GattClosed ( " Gatt closed during requestMtu[mtu= $mtu ] " )
210
217
}
211
218
212
219
override fun setCharacteristicNotification (
0 commit comments