我有以下使用RxAndroidBle
的简单BLE设备设置过程的用例:
PublishSubject
发布已解析的数据。PublishSubject
从设备-公钥(通过通知特征到达,作为对我们写操作的响应)传递已解析的响应。Completable
,说明该过程是否成功完成。现在我的解决方案(不起作用)如下:
deviceService.connectToDevice(macAddress)
.andThen(Completable.defer { deviceService.setupCharacteristicNotification() })
.andThen(Completable.defer { deviceService.postNegotiateSecurity() })
.andThen(Completable.defer {
parser.notificationResultSubject
.flatMapCompletable { result ->
when (result) {
DevicePublicKeyReceived -> Completable.complete()
else -> Completable.error(Exception("Unexpected notification parse result: ${result::class}"))
}
}
})
.andThen(Completable.defer { deviceService.postSetSecurity() })
还有DeviceService
类:
class DeviceService {
/**
* Observable keeping shared RxBleConnection for reuse by different calls
*/
private var connectionObservable: Observable<RxBleConnection>? = null
fun connectToDevice(macAddress: String): Completable {
return Completable.fromAction {
connectionObservable =
rxBleClient.getBleDevice(macAddress)
.establishConnection(false)
.compose(ReplayingShare.instance())
}
}
fun setupCharacteristicNotification(): Completable =
connectionObservable?.let {
it
.switchMap { connection ->
connection.setupNotification(UUID_NOTIFICATION_CHARACTERISTIC)
.map { notificationObservable -> notificationObservable.doOnNext { bytes -> parser.parse(bytes) }.ignoreElements() }
.map { channel ->
Observable.merge(
Observable.never<RxBleConnection>().startWith(connection),
channel.toObservable()
)
}
.ignoreElements()
.toObservable<RxBleConnection>()
}
.doOnError { Timber.e(it, "setup characteristic") }
.take(1).ignoreElements()
} ?: Completable.error(CONNECTION_NOT_INITIALIZED)
fun postNegotiateSecurity(): Completable {
val postLength = negotiateSecurity.postNegotiateSecurityLength()
val postPGK = negotiateSecurity.postNegotiateSecurityPGKData()
return connectionObservable?.let {
it.take(1)
.flatMapCompletable { connection ->
postLength
.flatMapSingle { connection.write(it.bytes.toByteArray()) }
.doOnError { Timber.e(it, "post length") }
.flatMap {
postPGK
.flatMapSingle { connection.write(it.bytes.toByteArray()) }
.doOnError { Timber.e(it, "post PGK") }
}
.take(1).ignoreElements()
}
} ?: Completable.error(CONNECTION_NOT_INITIALIZED)
}
fun postSetSecurity(): Completable =
connectionObservable?.let {
it.take(1)
.flatMapCompletable { connection ->
negotiateSecurity.postSetSecurity()
.flatMapSingle { connection.write(it.bytes.toByteArray()) }
.take(1).ignoreElements()
}
} ?: Completable.error(CONNECTION_NOT_INITIALIZED)
}
private fun RxBleConnection.write(bytes: ByteArray): Single<ByteArray> =
writeCharacteristic(UUID_WRITE_CHARACTERISTIC, bytes)
问题在于它被卡在deviceService.postNegotiateSecurity()
中并且永远不会过去。我也没有在解析器中获得任何数据,所以我认为我在错误地订阅了通知特征。
negotiateSecurity.postNegotiateSecurityLength()
和negotiateSecurity.postNegotiateSecurityPGKData()
是准备要发送的数据并将其作为Observable<SendFragment>
传递的方法。由于数据帧大小的限制,一帧可能被编码为几个片段,然后由这些Observable
发出。
答案 0 :(得分:0)
postNegotiateSecurity()
从未完成negotiateSecurity.postNegotiateSecurityLength()
可能发射一次或多次negotiateSecurity.postNegotiateSecurityPGKData()
可能发射一次或多次it.take(1)
.flatMapCompletable { connection ->
postLength
.flatMapSingle { connection.write(it.bytes.toByteArray()) }
.flatMap {
postPGK // may emit more than one value
.flatMapSingle { connection.write(it.bytes.toByteArray()) }
}
.take(1) // first emission from the above `flatMap` will finish the upstream
.ignoreElements()
}
postLength
的每次发射都将开始特征写入。每次成功写入将开始订阅postPGK
。如果postLength
发出不止一次-将对postPGK
进行更多订阅。
每次订阅postPGK
极有可能导致多种排放。然后将每个发射平面映射到特征写入。每次成功写入都会发出一个值。
在上述特征写入的第一个发射之后,将处置上游(由于.take(1)
运算符)。
如果postNegotiateSecurity()
实际上已经启动,它也会完成或出错(假设postLength
和postPGK
都发出至少一个值),因为这里没有其他逻辑。 / p>
postNegotiateSecurity()
很可能会完成(但不是以预期的方式),因为来自postPGK
的第一个数据包会完成它。我假设外围设备在通知任何内容之前都希望有完整的数据,因此它正在等待PGK完全传输,而不会如上所示。
设置了RxBleLog.setLogLevel(RxBleLog.VERBOSE)
的应用程序日志可以帮助您了解实际发生的情况。