Issue #51 fixed: restarting legacy bootloader on Invalid State

This commit is contained in:
Aleksander Nowakowski 2017-03-21 14:43:02 +01:00
parent 113c312985
commit d5f487ed56
1 changed files with 51 additions and 22 deletions

View File

@ -411,32 +411,12 @@ import no.nordicsemi.android.error.LegacyDfuError;
*/
status = getStatusCode(response, OP_CODE_START_DFU_KEY);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Response received (Op Code = " + response[1] + " Status = " + status + ")");
// If upload was not completed in the previous connection the INVALID_STATE status will be reported.
// Theoretically, the connection could be resumed from that point, but there is no guarantee, that the same firmware
// is to be uploaded now. It's safer to reset the device and start DFU again.
if (status == LegacyDfuError.INVALID_STATE) {
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_WARNING, "Last upload interrupted. Restarting device...");
// Send 'jump to bootloader command' (Start DFU)
mProgressInfo.setProgress(DfuBaseService.PROGRESS_DISCONNECTING);
logi("Sending Reset command (Op Code = 6)");
writeOpCode(mControlPointCharacteristic, OP_CODE_RESET);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Reset request sent");
// The device will reset so we don't have to send Disconnect signal.
mService.waitUntilDisconnected();
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_INFO, "Disconnected by the remote device");
final BluetoothGattService gas = gatt.getService(GENERIC_ATTRIBUTE_SERVICE_UUID);
final boolean hasServiceChanged = gas != null && gas.getCharacteristic(SERVICE_CHANGED_UUID) != null;
mService.refreshDeviceCache(gatt, !hasServiceChanged);
// Close the device
mService.close(gatt);
logi("Restarting the service");
final Intent newIntent = new Intent();
newIntent.fillIn(intent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_PACKAGE);
restartService(newIntent, false);
resetAndRestart(gatt, intent);
return;
}
if (status != DFU_STATUS_SUCCESS)
@ -480,6 +460,14 @@ import no.nordicsemi.android.error.LegacyDfuError;
response = readNotificationResponse();
status = getStatusCode(response, OP_CODE_START_DFU_KEY);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Response received (Op Code = " + response[1] + " Status = " + status + ")");
// If upload was not completed in the previous connection the INVALID_STATE status will be reported.
// Theoretically, the connection could be resumed from that point, but there is no guarantee, that the same firmware
// is to be uploaded now. It's safer to reset the device and start DFU again.
if (status == LegacyDfuError.INVALID_STATE) {
resetAndRestart(gatt, intent);
return;
}
if (status != DFU_STATUS_SUCCESS)
throw new RemoteDfuException("Starting DFU failed", status);
} else
@ -512,6 +500,14 @@ import no.nordicsemi.android.error.LegacyDfuError;
response = readNotificationResponse();
status = getStatusCode(response, OP_CODE_START_DFU_KEY);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Response received (Op Code = " + response[1] + ", Status = " + status + ")");
// If upload was not completed in the previous connection the INVALID_STATE status will be reported.
// Theoretically, the connection could be resumed from that point, but there is no guarantee, that the same firmware
// is to be uploaded now. It's safer to reset the device and start DFU again.
if (status == LegacyDfuError.INVALID_STATE) {
resetAndRestart(gatt, intent);
return;
}
if (status != DFU_STATUS_SUCCESS)
throw new RemoteDfuException("Starting DFU failed", status);
} else
@ -845,4 +841,37 @@ import no.nordicsemi.android.error.LegacyDfuError;
if (!mConnected)
throw new DeviceDisconnectedException("Unable to write Image Sizes: device disconnected");
}
/**
* Sends Reset command to the target device to reset its state and restarts the DFU Service that will start again.
* @param gatt the GATT device
* @param intent intent used to start the service
* @throws DfuException
* @throws DeviceDisconnectedException
* @throws UploadAbortedException
*/
private void resetAndRestart(final BluetoothGatt gatt, final Intent intent) throws DfuException, DeviceDisconnectedException, UploadAbortedException {
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_WARNING, "Last upload interrupted. Restarting device...");
// Send 'jump to bootloader command' (Start DFU)
mProgressInfo.setProgress(DfuBaseService.PROGRESS_DISCONNECTING);
logi("Sending Reset command (Op Code = 6)");
writeOpCode(mControlPointCharacteristic, OP_CODE_RESET);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Reset request sent");
// The device will reset so we don't have to send Disconnect signal.
mService.waitUntilDisconnected();
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_INFO, "Disconnected by the remote device");
final BluetoothGattService gas = gatt.getService(GENERIC_ATTRIBUTE_SERVICE_UUID);
final boolean hasServiceChanged = gas != null && gas.getCharacteristic(SERVICE_CHANGED_UUID) != null;
mService.refreshDeviceCache(gatt, !hasServiceChanged);
// Close the device
mService.close(gatt);
logi("Restarting the service");
final Intent newIntent = new Intent();
newIntent.fillIn(intent, Intent.FILL_IN_COMPONENT | Intent.FILL_IN_PACKAGE);
restartService(newIntent, false);
}
}