![](/img/trans.png)
[英]Android BLE is NOT connecting again after BLE device timeout [Using RxAndroidBle ]
[英]Android BLE Write large file using RxAndroidBle in blocking way
我有一個使用 RxAndroidBle 作為 BLE 解決方案的 Android 應用程序,它非常棒,可以節省大量的工作時間。
但最近我必須實施更新固件功能,但我遇到了困難。
自定義 BLE 設備之一必須在寫入之前等待通知 ByteAray。 每 16 個包(每個包 20 個字節),設備將向某些特征發送通知 ByteAray。
所以我想做的是等待通知,然后發送那些固件包。 而且我發現我必須添加一個 160 毫秒的計時器,這樣設備就不會被這些包(背壓?)壓倒。
仍然沒有運氣。 設備將 go 無響應然后斷開一定量的數據后斷開連接,如 256 字節 * 12(文件大小范圍為 256 字節 * 330 ~ 785)。
這是當前的實現:
.flatMap { ifFrameCountAccepted ->
if (ifFrameCountAccepted) {
Timber.d("Wait 2 seconds cleaning up flash")
Flowable
.timer(3000, TimeUnit.MILLISECONDS)
.flatMap { sendFramesFlowable(firmware, isPic) }
} else {
Flowable.error(RuntimeException("MCU L2 frame count error."))
}
}
.toObservable()
.flatMap { isFirmwareTransmissionDone ->
if (isFirmwareTransmissionDone) {
waitUntilL2McuUpgradeFinish(isPic)
} else {
Observable.just(false)
}
}
private fun sendFramesFlowable(
firmware: FirmwareUpgradeData,
isPic: Boolean
): Flowable<Boolean> {
Timber.d("Firmware size: ${firmware.processed.size}")
val frameInvalidPublishSubject = PublishSubject.create<Boolean>()
val frameObservable = connection.toFlowable(BackpressureStrategy.BUFFER).flatMap { rxConnection ->
rxConnection.setupNotification(
RC_NOTIFICATION_CHARACTERISTIC,
NotificationSetupMode.DEFAULT
).toFlowable(BackpressureStrategy.BUFFER)
.concatMap { notification ->
notification.toFlowable(BackpressureStrategy.BUFFER)
}
}
.filter { it.size == 20 }
.filter { it.second.first().toUnsignedValue() == COMMAND_HEADER_L2_FRAME }
.map { reply ->
Timber.d("[A2] decoded: ${reply.second.toHex()}")
val payload = reply.second.dataPayload(reply.first)
val isValid = upgradeDataTransmission.resolveFrameCommand(payload)
Timber.d("MCU L2 upgrade frame is accepted: $isValid")
unless(!isValid) {
frameInvalidPublishSubject.onNext(true)
}
isValid
}
.zipWith(Flowable.range(1, firmware.frameCount), BiFunction { _: Boolean, frameCount: Int ->
frameCount
})
.doOnNext { frameCount ->
val base = if (isPic) 45.minus(25) else 99.minus(45)
val progress = base.div(firmware.frameCount.toFloat())
.times(frameCount).toInt()
.plus(if (isPic) 25 else 45)
_upgradeProgress.postValue(Event.success(progress))
}
.flatMap { frameCount ->
Timber.d("frame count now is:$frameCount")
if (frameCount == firmware.frameCount) {
triggerL2Upgrade(firmware.crcCheck)
} else {
Flowable.just(false)
}
}
Flowable.fromIterable(firmware.processed.withIndex())
.buffer(16)
.takeUntil(frameInvalidPublishSubject.toFlowable(BackpressureStrategy.BUFFER))
.concatMap { frame ->
Flowable.timer(160, TimeUnit.MILLISECONDS).concatMap {
Flowable.fromIterable(frame)
.concatMap { perPackage ->
connection.toFlowable(BackpressureStrategy.BUFFER)
.concatMap {
it.writeCharacteristic(RC_WRITE_CHARACTERISTIC, perPackage.value.toByteArray())
.toFlowable()
}
}
}
}
.forEachWhile {
true
}
return frameObservable
}
RxAndroidBle
中有一個內置的幫助器來處理這種情況:
RxBleConnection.createLongWriteBuilder()
您可以閱讀它為您提供的確切可能性,但使用writeOperationAckStrategy()
您可以推遲寫入下一個字節數組:
val notificationsEvery16thWrite: Observable<ByteArray> = (...)
rxBleConnection.createNewLongWriteBuilder()
.setWriteOperationAckStrategy { writeAcks ->
val emitEveryWriteAckApartEvery16th = writeAcks
.scan(0 to null as Boolean?) { acc, boolean ->
acc.first.plus(1) to boolean
}
.filter { it.first != 0 && it.first % 16 != 0 }
.map { it.second!! }
val emitEvery16thWriteAckAfterNotification = notificationsEvery16thWrite.zipWith(
writeAcks.buffer(16), // buffer 16 writes ACKs
BiFunction { _, writesCompleted -> writesCompleted.last() }) // use last when notification arrives
Observable.merge(
emitEveryWriteAckApartEvery16th,
emitEvery16thWriteAckAfterNotification
)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.