Android-DFU-Library
Android-DFU-Library copied to clipboard
DFU problems on Huawei devices
Hi,
I'm developing an app using the nordic android DFU library, and I try to update the user device's bootloader + firmware without user interaction.
The issue I'm facing is that it is partially functional: I get many 133 and 129 Bluetooth errors while testing, but also the "DFU CHARACTERISTICS NOT FOUND" one (4102) on Huawei devices. The other devices I've tested don't have that much errors.
Is there a known problem with Huawei devices Bluetooth or did I do something wrong?
My code for both updates below:
Code to start the Bootloader update:
private fun startBootloaderDFUProcess() {
Log.i(TAG, "Starting Bootloader DFU update")
val starter = DfuServiceInitiator(deviceMacAddress!!)
.setDeviceName(deviceName!!)
.setKeepBond(true)
starter.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true)
starter.setZip(bootloaderPathName!!)
starter.start(context!!, DfuService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
DfuServiceInitiator.createDfuNotificationChannel(context!!)
}
}
Code for the DfuProgressListener
for the Bootloader:
private val dfuBootloaderProgressListener = object : DfuProgressListenerAdapter() {
override fun onEnablingDfuMode(deviceAddress: String) {
super.onEnablingDfuMode(deviceAddress)
dfu_description.text = getString(R.string.dfu_initializing_update)
}
override fun onProgressChanged(
deviceAddress: String,
percent: Int,
speed: Float,
avgSpeed: Float,
currentPart: Int,
partsTotal: Int
) {
super.onProgressChanged(deviceAddress, percent, speed, avgSpeed, currentPart, partsTotal)
mPercent = percent / 2
dfu_loading_bar.progress = mPercent
tv_update_percent.text = getString(R.string.dfu_percent, mPercent)
}
override fun onError(deviceAddress: String, error: Int, errorType: Int, message: String?) {
super.onError(deviceAddress, error, errorType, message)
Log.v(TAG, "onError : $error type : $errorType message : $message")
when (error) {
BOOTLOADER_FW_VERSION_FAILURE -> {
viewModel.launchScanForDfuTarg()
}
DFU_DISCONNECTED -> {
startBootloaderDFUProcess()
}
else -> {
PrefEnovap.saveIsBackBlockedToPref(false)
displayErrorOnSnackbarLong(dfu_base, getString(R.string.dfu_error_disconnection))
(activity as MainActivity).onBackPressed()
}
}
}
override fun onDfuAborted(deviceAddress: String) {
super.onDfuAborted(deviceAddress)
Log.v(TAG, "dfu aborted")
}
override fun onFirmwareValidating(deviceAddress: String) {
super.onFirmwareValidating(deviceAddress)
Log.v(TAG, "onFirmwareValidating")
}
override fun onDeviceDisconnected(deviceAddress: String) {
super.onDeviceDisconnected(deviceAddress)
Log.v(TAG, "onDeviceDisconnected")
}
override fun onDeviceConnected(deviceAddress: String) {
super.onDeviceConnected(deviceAddress)
Log.v(TAG, "onDeviceConnected")
}
override fun onDfuProcessStarting(deviceAddress: String) {
super.onDfuProcessStarting(deviceAddress)
Log.v(TAG, "onDfuProcessStartingBootloader")
if (!enovap_button_dfu.isAnimating) {
enovap_button_dfu.startAnimation()
}
dfu_description.text = getString(R.string.dfu_updating)
mPercent = 0
dfu_loading_bar.progress = mPercent
tv_update_percent.text = getString(R.string.dfu_percent, mPercent)
}
override fun onDfuProcessStarted(deviceAddress: String) {
super.onDfuProcessStarted(deviceAddress)
Log.v(TAG, "onDfuProcessStarted")
}
override fun onDeviceConnecting(deviceAddress: String) {
super.onDeviceConnecting(deviceAddress)
Log.v(TAG, "onDeviceConnecting")
}
override fun onDfuCompleted(deviceAddress: String) {
super.onDfuCompleted(deviceAddress)
Log.v(TAG, "onDfuCompleted")
startFirmwareDFUProcess()
}
}
Code to start the Firmware update:
private fun startFirmwareDFUProcess() {
Log.i(TAG, "Starting Firmware DFU update")
DfuServiceListenerHelper.registerProgressListener(context!!, dfuFirmwareProgressListener)
val starter = DfuServiceInitiator(deviceMacAddress!!)
.setDeviceName(deviceName!!)
.setKeepBond(true)
starter.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true)
starter.setZip(firmwarePathName!!)
starter.start(context!!, DfuService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
DfuServiceInitiator.createDfuNotificationChannel(context!!)
}
}
Code for the DfuProgressListener
for the Firmware:
private val dfuFirmwareProgressListener = object : DfuProgressListenerAdapter() {
override fun onProgressChanged(
deviceAddress: String,
percent: Int,
speed: Float,
avgSpeed: Float,
currentPart: Int,
partsTotal: Int
) {
super.onProgressChanged(deviceAddress, percent, speed, avgSpeed, currentPart, partsTotal)
enovap_button_dfu.startAnimation()
mPercent = FIRMWARE_START_PERCENT + percent / 2
dfu_loading_bar.progress = mPercent
tv_update_percent.text = getString(R.string.dfu_percent, mPercent)
}
override fun onError(deviceAddress: String, error: Int, errorType: Int, message: String?) {
super.onError(deviceAddress, error, errorType, message)
Log.v(TAG, "onError : $error message : $message")
when (error) {
BOOTLOADER_FW_VERSION_FAILURE -> {
viewModel.launchScanForDfuTarg()
}
else -> {
DfuServiceListenerHelper.unregisterProgressListener(context!!, this)
PrefEnovap.saveIsBackBlockedToPref(false)
displayErrorOnSnackbarLong(dfu_base, getString(R.string.dfu_error_disconnection))
(activity as MainActivity).onBackPressed()
}
}
}
override fun onDfuAborted(deviceAddress: String) {
super.onDfuAborted(deviceAddress)
Log.v(TAG, "dfu aborted")
}
override fun onFirmwareValidating(deviceAddress: String) {
super.onFirmwareValidating(deviceAddress)
Log.v(TAG, "onFirmwareValidating")
}
override fun onDeviceDisconnected(deviceAddress: String) {
super.onDeviceDisconnected(deviceAddress)
Log.v(TAG, "onDeviceDisconnected")
}
override fun onDeviceConnected(deviceAddress: String) {
super.onDeviceConnected(deviceAddress)
Log.v(TAG, "onDeviceConnected")
}
override fun onDfuProcessStarting(deviceAddress: String) {
super.onDfuProcessStarting(deviceAddress)
Log.v(TAG, "onDfuProcessStarting")
dfu_loading_bar.progress = FIRMWARE_START_PERCENT
tv_update_percent.text = getString(R.string.dfu_percent, FIRMWARE_START_PERCENT)
}
override fun onDfuProcessStarted(deviceAddress: String) {
super.onDfuProcessStarted(deviceAddress)
Log.v(TAG, "onDfuProcessStarted")
}
override fun onDeviceConnecting(deviceAddress: String) {
super.onDeviceConnecting(deviceAddress)
Log.v(TAG, "onDeviceConnecting")
}
override fun onDfuCompleted(deviceAddress: String) {
super.onDfuCompleted(deviceAddress)
DfuServiceListenerHelper.unregisterProgressListener(context!!, this)
activity?.runOnUiThread {
PrefEnovap.saveIsBackBlockedToPref(false)
dfu_description.gone()
dfu_icon.fadeOut {}
dfu_icon.gone()
dfu_title.fadeOut {}
dfu_title.gone()
dfu_subtitle.fadeOut {}
dfu_subtitle.gone()
tv_update_percent.fadeOut {}
tv_update_percent.gone()
dfu_loading_bar.fadeOut {}
dfu_loading_bar.gone()
enovap_button_dfu.fadeOut {}
enovap_button_dfu.gone()
enovap_button_dfu.revertAnimation()
dfu_icon.setImageDrawable(getDrawable(context!!, R.drawable.ic_up_to_date))
dfu_title.text = getString(R.string.enovap_up_to_date)
dfu_subtitle.text = getString(R.string.dfu_up_to_date_description)
Handler().postDelayed({
dfu_icon.visible()
dfu_icon.fadeIn {}
dfu_title.visible()
dfu_title.fadeIn {}
dfu_subtitle.visible()
dfu_subtitle.fadeIn {}
enovap_button_dfu_finish.visible()
enovap_button_dfu_finish.fadeIn {}
}, 400)
}
}
}
I have the same problem, i am testing on Huawei y9 Prime: E/DfuBaseService: Connection state change error: 133 newState: 0 E/DfuBaseService: Device not reachable. Check if the device with address EA:87:46:6D:DC:B8 is in range, is advertising and is connectable.
Set the device Bluetooth in mode DFU. In this mode on my device BLE the name of device and mac change (device.45667[EA:87:46:6D:DC:B8] --> device.45267[EA:87:46:6E:DC:B8]), so, when start the DfuServiceInitiator object, set the new DeviceName and MAC.
Is required set the device in DFU mode.
.setPacketsReceiptNotificationsEnabled(true)
it work fine now,but i find other problems on Huawei devices
setPacketsReceiptNotificationsEnabled
I have the same problem. Where do I set .setPacketsReceiptNotificationsEnabled(true)?
In the DfuServiceInitiator
instance: https://github.com/NordicSemiconductor/Android-DFU-Library/blob/5c2d28e9db2ba28b3df67fd61d01a2ce1419fcf0/dfu/src/main/java/no/nordicsemi/android/dfu/DfuServiceInitiator.java#L221
@philips77 When setting setPacketsReceiptNotificationsEnabled to true, what changes that fixes the issue users reported above? What I'm wondering when setting that to true do you have to ensure a notification is received before doing more work, If so, is this on the controller application to implement the notification is received?
Also, I'm curious is it be common practice to set a retry policy?
The library will do this automatically. Also, if your using non modified DFU bootloader it will send those notifications automatically.