diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/BaseDfuImpl.java b/dfu/src/main/java/no/nordicsemi/android/dfu/BaseDfuImpl.java index 9d86e13..a5788af 100644 --- a/dfu/src/main/java/no/nordicsemi/android/dfu/BaseDfuImpl.java +++ b/dfu/src/main/java/no/nordicsemi/android/dfu/BaseDfuImpl.java @@ -707,6 +707,10 @@ import no.nordicsemi.android.dfu.internal.scanner.BootloaderScannerFactory; if (newAddress != null) intent.putExtra(DfuBaseService.EXTRA_DEVICE_ADDRESS, newAddress); + + // Reset the DFU attempt counter + intent.putExtra(DfuBaseService.EXTRA_DFU_ATTEMPT, 0); + mService.startService(intent); } diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/DfuBaseService.java b/dfu/src/main/java/no/nordicsemi/android/dfu/DfuBaseService.java index 64b2c40..f9941cc 100644 --- a/dfu/src/main/java/no/nordicsemi/android/dfu/DfuBaseService.java +++ b/dfu/src/main/java/no/nordicsemi/android/dfu/DfuBaseService.java @@ -1347,9 +1347,19 @@ public abstract class DfuBaseService extends IntentService implements DfuProgres mProgressInfo.setProgress(PROGRESS_ABORTED); } catch (final DeviceDisconnectedException e) { sendLogBroadcast(LOG_LEVEL_ERROR, "Device has disconnected"); - // TODO reconnect n times? loge(e.getMessage()); close(gatt); + + final int attempt = intent.getIntExtra(EXTRA_DFU_ATTEMPT, 0); + final int limit = intent.getIntExtra(EXTRA_MAX_DFU_ATTEMPTS, 0); + if (attempt < limit) { + logi("Restarting the service (" + (attempt + 1) + " /" + limit + ")"); + final Intent newIntent = new Intent(); + newIntent.fillIn(intent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_PACKAGE); + newIntent.putExtra(EXTRA_DFU_ATTEMPT, attempt + 1); + startService(newIntent); + return; + } report(ERROR_DEVICE_DISCONNECTED); } catch (final DfuException e) { int error = e.getErrorNumber(); diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/DfuServiceInitiator.java b/dfu/src/main/java/no/nordicsemi/android/dfu/DfuServiceInitiator.java index e719756..b5438a4 100644 --- a/dfu/src/main/java/no/nordicsemi/android/dfu/DfuServiceInitiator.java +++ b/dfu/src/main/java/no/nordicsemi/android/dfu/DfuServiceInitiator.java @@ -79,6 +79,7 @@ public class DfuServiceInitiator { private boolean forceDfu = false; private boolean enableUnsafeExperimentalButtonlessDfu = false; private boolean disableResume = false; + private int numberOfRetries = 0; // 0 to be backwards compatible private Boolean packetReceiptNotificationsEnabled; private int numberOfPackets = 12; @@ -269,6 +270,28 @@ public class DfuServiceInitiator { return this; } + /** + * Sets the number of retries that the DFU service will use to complete DFU. The default + * value is 0, for backwards compatibility reason. + *

+ * If the given value is greater than 0, the service will restart itself at most {@code max} + * times in case of an undesired disconnection during DFU operation. This attempt counter + * is independent from another counter, for reconnection attempts, which is equal to 3. + * The latter one will be used when connection will fail with an error (possible packet + * collision or any other reason). After successful connection, the reconnection counter is + * reset, while the retry counter is cleared after a DFU finishes with success. + *

+ * The service will not try to retry DFU in case of any other error, for instance an error + * sent from the target device. + * + * @param max Maximum number of retires to complete DFU. Usually around 2. + * @return the builder + */ + public DfuServiceInitiator setNumberOfRetries(@IntRange(from = 0) final int max) { + this.numberOfRetries = max; + return this; + } + /** * Sets the Maximum Transfer Unit (MTU) value that the Secure DFU service will try to request * before performing DFU. By default, value 517 will be used, which is the highest supported @@ -704,6 +727,7 @@ public class DfuServiceInitiator { intent.putExtra(DfuBaseService.EXTRA_RESTORE_BOND, restoreBond); intent.putExtra(DfuBaseService.EXTRA_FORCE_DFU, forceDfu); intent.putExtra(DfuBaseService.EXTRA_DISABLE_RESUME, disableResume); + intent.putExtra(DfuBaseService.EXTRA_MAX_DFU_ATTEMPTS, numberOfRetries); if (mtu > 0) intent.putExtra(DfuBaseService.EXTRA_MTU, mtu); intent.putExtra(DfuBaseService.EXTRA_CURRENT_MTU, currentMtu); diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/LegacyDfuImpl.java b/dfu/src/main/java/no/nordicsemi/android/dfu/LegacyDfuImpl.java index a675c69..424d404 100644 --- a/dfu/src/main/java/no/nordicsemi/android/dfu/LegacyDfuImpl.java +++ b/dfu/src/main/java/no/nordicsemi/android/dfu/LegacyDfuImpl.java @@ -474,7 +474,6 @@ import no.nordicsemi.android.error.LegacyDfuError; } catch (final DeviceDisconnectedException e) { loge("Disconnected while sending data"); throw e; - // TODO reconnect? } final long endTime = SystemClock.elapsedRealtime(); diff --git a/dfu/src/main/java/no/nordicsemi/android/dfu/SecureDfuImpl.java b/dfu/src/main/java/no/nordicsemi/android/dfu/SecureDfuImpl.java index 87b2752..fa20f4c 100644 --- a/dfu/src/main/java/no/nordicsemi/android/dfu/SecureDfuImpl.java +++ b/dfu/src/main/java/no/nordicsemi/android/dfu/SecureDfuImpl.java @@ -391,8 +391,13 @@ class SecureDfuImpl extends BaseCustomDfuImpl { mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Command object created"); } // Write Init data to the Packet Characteristic - logi("Sending " + (mInitPacketSizeInBytes - info.offset) + " bytes of init packet..."); - writeInitData(mPacketCharacteristic, crc32); + try { + logi("Sending " + (mInitPacketSizeInBytes - info.offset) + " bytes of init packet..."); + writeInitData(mPacketCharacteristic, crc32); + } catch (final DeviceDisconnectedException e) { + loge("Disconnected while sending init packet"); + throw e; + } final int crc = (int) (crc32.getValue() & 0xFFFFFFFFL); mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Command object sent (CRC = %08X)", crc));