2
2
3
3
package no.nordicsemi.android.ble.ktx
4
4
5
+ import android.util.Log
5
6
import kotlinx.coroutines.ExperimentalCoroutinesApi
6
7
import kotlinx.coroutines.channels.awaitClose
8
+ import kotlinx.coroutines.channels.onFailure
9
+ import kotlinx.coroutines.channels.trySendBlocking
7
10
import kotlinx.coroutines.flow.Flow
11
+ import kotlinx.coroutines.flow.buffer
8
12
import kotlinx.coroutines.flow.callbackFlow
9
13
import no.nordicsemi.android.ble.ValueChangedCallback
10
14
import no.nordicsemi.android.ble.callback.profile.ProfileReadResponse
@@ -17,6 +21,11 @@ import no.nordicsemi.android.ble.response.ReadResponse
17
21
* Usage:
18
22
*
19
23
* val hrmMeasurementsData = setNotificationCallback(hrmCharacteristic).asFlow() // Flow<Data>
24
+ *
25
+ * Use the [buffer] operator on the resulting flow to specify a user-defined value and to control
26
+ * what happens when data is produced faster than consumed, i.e. to control the back-pressure behavior.
27
+ *
28
+ * val hrmMeasurementsData = setNotificationCallback(hrmCharacteristic).asFlow().buffer()
20
29
* @return The flow.
21
30
* @since 2.3.0
22
31
*/
@@ -25,7 +34,8 @@ fun ValueChangedCallback.asFlow(): Flow<Data> = callbackFlow {
25
34
// Make sure the callbacks are called without unnecessary delay.
26
35
setHandler(null )
27
36
with { _, data ->
28
- trySend(data)
37
+ trySendBlocking(data)
38
+ .onFailure { t -> Log .w(" ValueChangeCallback" , " Sending data to Flow failed with: $t " ) }
29
39
}
30
40
awaitClose {
31
41
// There's no way to unregister the callback from here.
@@ -41,6 +51,9 @@ fun ValueChangedCallback.asFlow(): Flow<Data> = callbackFlow {
41
51
* val hrmMeasurementsData: Flow<HeartRateMeasurementResponse> =
42
52
* setNotificationCallback(hrmCharacteristic)
43
53
* .asResponseFlow()
54
+ *
55
+ * Use the [buffer] operator on the resulting flow to specify a user-defined value and to control
56
+ * what happens when data is produced faster than consumed, i.e. to control the back-pressure behavior.
44
57
* @return The flow.
45
58
* @since 2.4.0
46
59
*/
@@ -49,7 +62,10 @@ inline fun <reified T: ReadResponse> ValueChangedCallback.asResponseFlow(): Flow
49
62
// Make sure the callbacks are called without unnecessary delay.
50
63
setHandler(null )
51
64
with { device, data ->
52
- trySend(T ::class .java.getDeclaredConstructor().newInstance().apply { onDataReceived(device, data) })
65
+ val response = T ::class .java.getDeclaredConstructor().newInstance()
66
+ .apply { onDataReceived(device, data) }
67
+ trySendBlocking(response)
68
+ .onFailure { t -> Log .w(" ValueChangeCallback" , " Sending response to Flow failed with: $t " ) }
53
69
}
54
70
awaitClose {
55
71
// There's no way to unregister the callback from here.
@@ -66,6 +82,9 @@ inline fun <reified T: ReadResponse> ValueChangedCallback.asResponseFlow(): Flow
66
82
* val hrmMeasurementsData: Flow<HeartRateMeasurementResponse> =
67
83
* setNotificationCallback(hrmCharacteristic)
68
84
* .asValidResponseFlow()
85
+ *
86
+ * Use the [buffer] operator on the resulting flow to specify a user-defined value and to control
87
+ * what happens when data is produced faster than consumed, i.e. to control the back-pressure behavior.
69
88
* @return The flow.
70
89
* @since 2.4.0
71
90
*/
@@ -74,10 +93,12 @@ inline fun <reified T: ProfileReadResponse> ValueChangedCallback.asValidResponse
74
93
// Make sure the callbacks are called without unnecessary delay.
75
94
setHandler(null )
76
95
with { device, data ->
77
- T ::class .java.getDeclaredConstructor().newInstance()
96
+ val response = T ::class .java.getDeclaredConstructor().newInstance()
78
97
.apply { onDataReceived(device, data) }
79
- .takeIf { it.isValid }
80
- ?.let { trySend(it) }
98
+ if (response.isValid) {
99
+ trySendBlocking(response)
100
+ .onFailure { t -> Log .w(" ValueChangeCallback" , " Sending response to Flow failed with: $t " ) }
101
+ }
81
102
}
82
103
awaitClose {
83
104
// There's no way to unregister the callback from here.
0 commit comments