Optional delay before each data packet

This commit is contained in:
Aleksander Nowakowski 2020-02-12 11:35:14 +01:00
parent 6febfc72fb
commit 8e0a7aa88a
3 changed files with 40 additions and 6 deletions

View File

@ -265,6 +265,11 @@ public abstract class DfuBaseService extends IntentService implements DfuProgres
* It is recommended to use this new service when SDK 13 (or later) is out.
*/
public static final String EXTRA_UNSAFE_EXPERIMENTAL_BUTTONLESS_DFU = "no.nordicsemi.android.dfu.extra.EXTRA_UNSAFE_EXPERIMENTAL_BUTTONLESS_DFU";
/**
* The duration of a delay that will be added before sending each data packet in Secure DFU,
* in milliseconds. This defaults to 0 for backwards compatibility reason.
*/
public static final String EXTRA_DATA_OBJECT_DELAY = "no.nordicsemi.android.dfu.extra.EXTRA_DATA_OBJECT_DELAY";
/**
* This property must contain a boolean value.
* <p>

View File

@ -82,6 +82,7 @@ public final class DfuServiceInitiator {
private boolean disableResume = false;
private int numberOfRetries = 0; // 0 to be backwards compatible
private int mbrSize = DEFAULT_MBR_SIZE;
private long dataObjectDelay = 0; // initially disabled
private Boolean packetReceiptNotificationsEnabled;
private int numberOfPackets = 12;
@ -183,6 +184,30 @@ public final class DfuServiceInitiator {
return this;
}
/**
* This method sets the duration of a delay, that the service will wait before sending each
* data object in Secure DFU. The delay will be done after a data object is created, and before
* any data byte is sent. The default value is 0, which disables this feature.
* <p>
* It has been found, that a delay of at least 300ms reduces the risk of packet lose (the
* bootloader needs some time to prepare flash memory) on DFU bootloader from SDK 15 and 16.
* The delay does not have to be longer than 400 ms, as according to performed tests, such delay
* is sufficient.
* <p>
* The longer the delay, the more time DFU will take to complete (delay will be repeated for
* each data object (4096 bytes)). However, with too small delay a packet lose may occur,
* causing the service to enable PRN and set them to 1 making DFU process very, very slow
* (but reliable).
*
* @param delay the initial delay that the service will wait before sending each data object.
* @since 1.10
* @return the builder
*/
public DfuServiceInitiator setPrepareDataObjectDelay(final long delay) {
this.dataObjectDelay = delay;
return this;
}
/**
* Enables or disables the Packet Receipt Notification (PRN) procedure.
* <p>
@ -759,6 +784,7 @@ public final class DfuServiceInitiator {
intent.putExtra(DfuBaseService.EXTRA_DISABLE_RESUME, disableResume);
intent.putExtra(DfuBaseService.EXTRA_MAX_DFU_ATTEMPTS, numberOfRetries);
intent.putExtra(DfuBaseService.EXTRA_MBR_SIZE, mbrSize);
intent.putExtra(DfuBaseService.EXTRA_DATA_OBJECT_DELAY, dataObjectDelay);
if (mtu > 0)
intent.putExtra(DfuBaseService.EXTRA_MTU, mtu);
intent.putExtra(DfuBaseService.EXTRA_CURRENT_MTU, currentMtu);

View File

@ -82,6 +82,8 @@ class SecureDfuImpl extends BaseCustomDfuImpl {
private BluetoothGattCharacteristic mControlPointCharacteristic;
private BluetoothGattCharacteristic mPacketCharacteristic;
private long prepareObjectDelay;
private final SecureBluetoothCallback mBluetoothCallback = new SecureBluetoothCallback();
protected class SecureBluetoothCallback extends BaseCustomBluetoothCallback {
@ -224,6 +226,8 @@ class SecureDfuImpl extends BaseCustomDfuImpl {
requestMtu(requiredMtu);
}
prepareObjectDelay = intent.getLongExtra(DfuBaseService.EXTRA_DATA_OBJECT_DELAY, 0);
try {
// Enable notifications
enableCCCD(mControlPointCharacteristic, NOTIFICATIONS);
@ -580,8 +584,7 @@ class SecureDfuImpl extends BaseCustomDfuImpl {
mProgressInfo.setBytesSent(0);
}
final long initialDelay = 400; // ms
final long startTime = SystemClock.elapsedRealtime() + initialDelay;
final long startTime = SystemClock.elapsedRealtime();
if (info.offset < mImageSizeInBytes) {
int attempt = 1;
@ -594,10 +597,10 @@ class SecureDfuImpl extends BaseCustomDfuImpl {
writeCreateRequest(OBJECT_DATA, availableObjectSizeInBytes);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION,
"Data object (" + (currentChunk + 1) + "/" + chunkCount + ") created");
if (currentChunk == 0) {
// Waiting until the device is ready to receive first data object.
mService.waitFor(initialDelay);
}
// Waiting until the device is ready to receive the data object.
// If prepare data object delay was set in the initiator, the delay will be used
// for all data objects.
mService.waitFor(prepareObjectDelay > 0 ? prepareObjectDelay : chunkCount == 0 ? 400 : 0);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION,
"Uploading firmware...");
} else {