Bug fixed: #77
This commit is contained in:
parent
a3ae736357
commit
ff73f661eb
|
@ -9,6 +9,7 @@ import no.nordicsemi.android.dfu.internal.exception.DfuException;
|
|||
import no.nordicsemi.android.dfu.internal.exception.RemoteDfuException;
|
||||
import no.nordicsemi.android.dfu.internal.exception.UnknownResponseException;
|
||||
import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
|
||||
import no.nordicsemi.android.error.SecureDfuError;
|
||||
|
||||
/**
|
||||
* A base class for buttonless service implementations made for Secure and in the future for Non-Secure DFU.
|
||||
|
@ -16,8 +17,6 @@ import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
|
|||
/* package */ abstract class ButtonlessDfuImpl extends BaseButtonlessDfuImpl {
|
||||
|
||||
private static final int DFU_STATUS_SUCCESS = 1;
|
||||
private static final int ERROR_OP_CODE_NOT_SUPPORTED = 2;
|
||||
private static final int ERROR_OPERATION_FAILED = 4;
|
||||
|
||||
private static final int OP_CODE_ENTER_BOOTLOADER_KEY = 0x01;
|
||||
private static final int OP_CODE_RESPONSE_CODE_KEY = 0x20;
|
||||
|
@ -127,10 +126,10 @@ import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
|
|||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, e.getMessage());
|
||||
mService.terminateConnection(gatt, error);
|
||||
} catch (final RemoteDfuException e) {
|
||||
final int error = DfuBaseService.ERROR_REMOTE_MASK | e.getErrorNumber();
|
||||
final int error = DfuBaseService.ERROR_REMOTE_TYPE_SECURE_BUTTONLESS | e.getErrorNumber();
|
||||
loge(e.getMessage());
|
||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, String.format("Remote DFU error: %s", parse(error)));
|
||||
mService.terminateConnection(gatt, error);
|
||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, String.format("Remote DFU error: %s", SecureDfuError.parseButtonlessError(error)));
|
||||
mService.terminateConnection(gatt, error | DfuBaseService.ERROR_REMOTE_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,16 +143,8 @@ import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
|
|||
*/
|
||||
private int getStatusCode(final byte[] response, final int request) throws UnknownResponseException {
|
||||
if (response == null || response.length < 3 || response[0] != OP_CODE_RESPONSE_CODE_KEY || response[1] != request ||
|
||||
(response[2] != DFU_STATUS_SUCCESS && response[2] != ERROR_OP_CODE_NOT_SUPPORTED && response[2] != ERROR_OPERATION_FAILED))
|
||||
(response[2] != DFU_STATUS_SUCCESS && response[2] != SecureDfuError.BUTTONLESS_ERROR_OP_CODE_NOT_SUPPORTED && response[2] != SecureDfuError.BUTTONLESS_ERROR_OPERATION_FAILED))
|
||||
throw new UnknownResponseException("Invalid response received", response, OP_CODE_RESPONSE_CODE_KEY, request);
|
||||
return response[2];
|
||||
}
|
||||
|
||||
private static String parse(final int error) {
|
||||
switch (error & (~DfuBaseService.ERROR_REMOTE_MASK)) {
|
||||
case ERROR_OP_CODE_NOT_SUPPORTED: return "REMOTE DFU OP CODE NOT SUPPORTED";
|
||||
case ERROR_OPERATION_FAILED: return "REMOTE DFU OPERATION FAILED";
|
||||
default: return "UNKNOWN (" + error + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -422,7 +422,7 @@ public abstract class DfuBaseService extends IntentService implements DfuProgres
|
|||
/**
|
||||
* The broadcast error message contains the following extras:
|
||||
* <ul>
|
||||
* <li>{@link #EXTRA_DATA} - the error number. Use {@link GattError#parse(int)} to get String representation</li>
|
||||
* <li>{@link #EXTRA_DATA} - the error number. Use {@link GattError#parse(int)} to get String representation.</li>
|
||||
* <li>{@link #EXTRA_DEVICE_ADDRESS} - the target device address</li>
|
||||
* </ul>
|
||||
*/
|
||||
|
@ -463,12 +463,6 @@ public abstract class DfuBaseService extends IntentService implements DfuProgres
|
|||
* Thrown when the service discovery has finished but the DFU service has not been found. The device does not support DFU of is not in DFU mode.
|
||||
*/
|
||||
public static final int ERROR_SERVICE_NOT_FOUND = ERROR_MASK | 0x06;
|
||||
/**
|
||||
* Thrown when the required DFU service has been found but at least one of the DFU characteristics is absent.
|
||||
* @deprecated This error will no longer be thrown. {@link #ERROR_SERVICE_NOT_FOUND} will be thrown instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int ERROR_CHARACTERISTICS_NOT_FOUND = ERROR_MASK | 0x07;
|
||||
/**
|
||||
* Thrown when unknown response has been obtained from the target. The DFU target must follow specification.
|
||||
*/
|
||||
|
@ -498,9 +492,14 @@ public abstract class DfuBaseService extends IntentService implements DfuProgres
|
|||
*/
|
||||
public static final int ERROR_DEVICE_NOT_BONDED = ERROR_MASK | 0x0E;
|
||||
/**
|
||||
* Flag set when the DFU target returned a DFU error. Look for DFU specification to get error codes.
|
||||
* Flag set when the DFU target returned a DFU error. Look for DFU specification to get error codes. The error code is binary OR-ed with one of:
|
||||
* {@link #ERROR_REMOTE_TYPE_LEGACY}, {@link #ERROR_REMOTE_TYPE_SECURE} or {@link #ERROR_REMOTE_TYPE_SECURE_EXTENDED}.
|
||||
*/
|
||||
public static final int ERROR_REMOTE_MASK = 0x2000;
|
||||
public static final int ERROR_REMOTE_TYPE_LEGACY = 0x0100;
|
||||
public static final int ERROR_REMOTE_TYPE_SECURE = 0x0200;
|
||||
public static final int ERROR_REMOTE_TYPE_SECURE_EXTENDED = 0x0400;
|
||||
public static final int ERROR_REMOTE_TYPE_SECURE_BUTTONLESS = 0x0800;
|
||||
/**
|
||||
* The flag set when one of {@link android.bluetooth.BluetoothGattCallback} methods was called with status other than {@link android.bluetooth.BluetoothGatt#GATT_SUCCESS}.
|
||||
*/
|
||||
|
|
|
@ -247,6 +247,12 @@ public class DfuServiceListenerHelper {
|
|||
if (deviceListener != null)
|
||||
deviceListener.onError(address, error, errorType, GattError.parseConnectionError(error));
|
||||
break;
|
||||
case DfuBaseService.ERROR_TYPE_DFU_REMOTE:
|
||||
if (globalListener != null)
|
||||
globalListener.onError(address, error, errorType, GattError.parseDfuRemoteError(error));
|
||||
if (deviceListener != null)
|
||||
deviceListener.onError(address, error, errorType, GattError.parseDfuRemoteError(error));
|
||||
break;
|
||||
default:
|
||||
if (globalListener != null)
|
||||
globalListener.onError(address, error, errorType, GattError.parse(error));
|
||||
|
|
|
@ -530,14 +530,14 @@ import no.nordicsemi.android.error.LegacyDfuError;
|
|||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Reset request sent");
|
||||
mService.terminateConnection(gatt, error);
|
||||
} catch (final RemoteDfuException e) {
|
||||
final int error = DfuBaseService.ERROR_REMOTE_MASK | e.getErrorNumber();
|
||||
loge(e.getMessage());
|
||||
final int error = DfuBaseService.ERROR_REMOTE_TYPE_LEGACY | e.getErrorNumber();
|
||||
loge(e.getMessage() + ": " + LegacyDfuError.parse(error));
|
||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, String.format("Remote DFU error: %s", LegacyDfuError.parse(error)));
|
||||
|
||||
logi("Sending Reset command (Op Code = 6)");
|
||||
writeOpCode(mControlPointCharacteristic, OP_CODE_RESET);
|
||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Reset request sent");
|
||||
mService.terminateConnection(gatt, error);
|
||||
mService.terminateConnection(gatt, error | DfuBaseService.ERROR_REMOTE_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -223,19 +223,19 @@ import no.nordicsemi.android.error.SecureDfuError;
|
|||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, e.getMessage());
|
||||
mService.terminateConnection(gatt, error);
|
||||
} catch (final RemoteDfuException e) {
|
||||
final int error = DfuBaseService.ERROR_REMOTE_MASK | e.getErrorNumber();
|
||||
loge(e.getMessage());
|
||||
final int error = DfuBaseService.ERROR_REMOTE_TYPE_SECURE | e.getErrorNumber();
|
||||
loge(e.getMessage() + ": " + SecureDfuError.parse(error));
|
||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, String.format("Remote DFU error: %s", SecureDfuError.parse(error)));
|
||||
|
||||
// For the Extended Error more details can be obtained on some devices.
|
||||
if (e instanceof RemoteDfuExtendedErrorException) {
|
||||
final RemoteDfuExtendedErrorException ee = (RemoteDfuExtendedErrorException) e;
|
||||
final int extendedError = ee.getExtendedErrorNumber();
|
||||
logi("Extended Error details: " + SecureDfuError.parseExtendedError(extendedError));
|
||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, "Details: " + SecureDfuError.parseExtendedError(extendedError) + " (Code = " + extendedError + ")");
|
||||
mService.terminateConnection(gatt, extendedError & DfuBaseService.ERROR_REMOTE_MASK);
|
||||
final int extendedError = DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | ee.getExtendedErrorNumber();
|
||||
loge("Extended Error details: " + SecureDfuError.parseExtendedError(extendedError));
|
||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, "Details: " + SecureDfuError.parseExtendedError(extendedError) + " (Code = " + ee.getExtendedErrorNumber() + ")");
|
||||
mService.terminateConnection(gatt, extendedError | DfuBaseService.ERROR_REMOTE_MASK);
|
||||
} else {
|
||||
mService.terminateConnection(gatt, error);
|
||||
mService.terminateConnection(gatt, error | DfuBaseService.ERROR_REMOTE_MASK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,6 @@ public class RemoteDfuExtendedErrorException extends RemoteDfuException {
|
|||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return super.getMessage() + " (error " + SecureDfuError.EXTENDED_ERROR + "." + mError + ")";
|
||||
return super.getMessage() + " (extended error " + mError + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import no.nordicsemi.android.dfu.DfuBaseService;
|
|||
/**
|
||||
* Parses the error numbers according to the <b>gatt_api.h</b> file from bluedroid stack.
|
||||
* See: https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h (and other versions) for details.
|
||||
* See also: https://android.googlesource.com/platform/external/libnfc-nci/+/master/src/include/hcidefs.h#447 for other possible HCI errors.
|
||||
*/
|
||||
public class GattError {
|
||||
// Starts at line 106 of gatt_api.h file
|
||||
|
@ -161,8 +162,6 @@ public class GattError {
|
|||
case DfuBaseService.ERROR_SERVICE_DISCOVERY_NOT_STARTED:
|
||||
return "DFU SERVICE DISCOVERY NOT STARTED";
|
||||
case DfuBaseService.ERROR_SERVICE_NOT_FOUND:
|
||||
return "DFU SERVICE NOT FOUND";
|
||||
case DfuBaseService.ERROR_CHARACTERISTICS_NOT_FOUND:
|
||||
return "DFU CHARACTERISTICS NOT FOUND";
|
||||
case DfuBaseService.ERROR_INVALID_RESPONSE:
|
||||
return "DFU INVALID RESPONSE";
|
||||
|
@ -171,17 +170,30 @@ public class GattError {
|
|||
case DfuBaseService.ERROR_BLUETOOTH_DISABLED:
|
||||
return "BLUETOOTH ADAPTER DISABLED";
|
||||
case DfuBaseService.ERROR_INIT_PACKET_REQUIRED:
|
||||
return "INIT PACKET REQUIRED";
|
||||
return "DFU INIT PACKET REQUIRED";
|
||||
case DfuBaseService.ERROR_FILE_SIZE_INVALID:
|
||||
return "DFU FILE NOT WORD ALIGNED";
|
||||
return "DFU INIT PACKET REQUIRED";
|
||||
case DfuBaseService.ERROR_CRC_ERROR:
|
||||
return "DFU CRC ERROR";
|
||||
case DfuBaseService.ERROR_DEVICE_NOT_BONDED:
|
||||
return "DFU DEVICE NOT BONDED";
|
||||
default:
|
||||
// Deprecated: use Legacy or SecureDfuError parser
|
||||
if ((DfuBaseService.ERROR_REMOTE_MASK & error) > 0) {
|
||||
return LegacyDfuError.parse(error);
|
||||
}
|
||||
}
|
||||
return "UNKNOWN (" + error + ")";
|
||||
}
|
||||
}
|
||||
|
||||
public static String parseDfuRemoteError(final int error) {
|
||||
switch (error & (DfuBaseService.ERROR_REMOTE_TYPE_LEGACY | DfuBaseService.ERROR_REMOTE_TYPE_SECURE | DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | DfuBaseService.ERROR_REMOTE_TYPE_SECURE_BUTTONLESS)) {
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_LEGACY:
|
||||
return LegacyDfuError.parse(error);
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE:
|
||||
return SecureDfuError.parse(error);
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED:
|
||||
return SecureDfuError.parseExtendedError(error);
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_BUTTONLESS:
|
||||
return SecureDfuError.parseButtonlessError(error);
|
||||
default:
|
||||
return "UNKNOWN (" + error + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,13 +34,14 @@ public final class LegacyDfuError {
|
|||
public static final int OPERATION_FAILED = 6;
|
||||
|
||||
public static String parse(final int error) {
|
||||
switch (error & (~DfuBaseService.ERROR_REMOTE_MASK)) {
|
||||
case INVALID_STATE: return "REMOTE DFU INVALID STATE";
|
||||
case NOT_SUPPORTED: return "REMOTE DFU NOT SUPPORTED";
|
||||
case DATA_SIZE_EXCEEDS_LIMIT: return "REMOTE DFU DATA SIZE EXCEEDS LIMIT";
|
||||
case CRC_ERROR: return "REMOTE DFU INVALID CRC ERROR";
|
||||
case OPERATION_FAILED: return "REMOTE DFU OPERATION FAILED";
|
||||
default: return "UNKNOWN (" + error + ")";
|
||||
switch (error) {
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_LEGACY | INVALID_STATE: return "INVALID STATE";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_LEGACY | NOT_SUPPORTED: return "NOT SUPPORTED";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_LEGACY | DATA_SIZE_EXCEEDS_LIMIT: return "DATA SIZE EXCEEDS LIMIT";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_LEGACY | CRC_ERROR: return "INVALID CRC ERROR";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_LEGACY | OPERATION_FAILED: return "OPERATION FAILED";
|
||||
default:
|
||||
return "UNKNOWN (" + error + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,35 +50,50 @@ public final class SecureDfuError {
|
|||
public static final int EXT_ERROR_VERIFICATION_FAILED = 0x0C;
|
||||
public static final int EXT_ERROR_INSUFFICIENT_SPACE = 0x0D;
|
||||
|
||||
// public static final int BUTTONLESS_SUCCESS = 1;
|
||||
public static final int BUTTONLESS_ERROR_OP_CODE_NOT_SUPPORTED = 2;
|
||||
public static final int BUTTONLESS_ERROR_OPERATION_FAILED = 4;
|
||||
|
||||
public static String parse(final int error) {
|
||||
switch (error & (~DfuBaseService.ERROR_REMOTE_MASK)) {
|
||||
case OP_CODE_NOT_SUPPORTED: return "REMOTE DFU OP CODE NOT SUPPORTED";
|
||||
case INVALID_PARAM: return "REMOTE DFU INVALID PARAM";
|
||||
case INSUFFICIENT_RESOURCES: return "REMOTE DFU INSUFFICIENT RESOURCES";
|
||||
case INVALID_OBJECT: return "REMOTE DFU INVALID OBJECT";
|
||||
case UNSUPPORTED_TYPE: return "REMOTE DFU UNSUPPORTED TYPE";
|
||||
case OPERATION_NOT_PERMITTED: return "REMOTE DFU OPERATION NOT PERMITTED";
|
||||
case OPERATION_FAILED: return "REMOTE DFU OPERATION FAILED";
|
||||
case EXTENDED_ERROR: return "REMOTE DFU EXTENDED ERROR";
|
||||
default: return "UNKNOWN (" + error + ")";
|
||||
switch (error) {
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE | OP_CODE_NOT_SUPPORTED: return "OP CODE NOT SUPPORTED";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE | INVALID_PARAM: return "INVALID PARAM";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE | INSUFFICIENT_RESOURCES: return "INSUFFICIENT RESOURCES";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE | INVALID_OBJECT: return "INVALID OBJECT";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE | UNSUPPORTED_TYPE: return "UNSUPPORTED TYPE";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE | OPERATION_NOT_PERMITTED: return "OPERATION NOT PERMITTED";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE | OPERATION_FAILED: return "OPERATION FAILED";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE | EXTENDED_ERROR: return "EXTENDED ERROR";
|
||||
default:
|
||||
return "UNKNOWN (" + error + ")";
|
||||
}
|
||||
}
|
||||
|
||||
public static String parseExtendedError(final int error) {
|
||||
switch (error) {
|
||||
case EXT_ERROR_WRONG_COMMAND_FORMAT: return "Wrong command format";
|
||||
case EXT_ERROR_UNKNOWN_COMMAND: return "Unknown command";
|
||||
case EXT_ERROR_INIT_COMMAND_INVALID: return "Init command invalid";
|
||||
case EXT_ERROR_FW_VERSION_FAILURE: return "FW version failure";
|
||||
case EXT_ERROR_HW_VERSION_FAILURE: return "HW version failure";
|
||||
case EXT_ERROR_SD_VERSION_FAILURE: return "SD version failure";
|
||||
case EXT_ERROR_SIGNATURE_MISSING : return "Signature mismatch";
|
||||
case EXT_ERROR_WRONG_HASH_TYPE: return "Wrong hash type";
|
||||
case EXT_ERROR_HASH_FAILED: return "Hash failed";
|
||||
case EXT_ERROR_WRONG_SIGNATURE_TYPE: return "Wring signature type";
|
||||
case EXT_ERROR_VERIFICATION_FAILED: return "Verification failed";
|
||||
case EXT_ERROR_INSUFFICIENT_SPACE: return "Insufficient space";
|
||||
default: return "Reserved for future use";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_WRONG_COMMAND_FORMAT: return "Wrong command format";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_UNKNOWN_COMMAND: return "Unknown command";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_INIT_COMMAND_INVALID: return "Init command invalid";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_FW_VERSION_FAILURE: return "FW version failure";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_HW_VERSION_FAILURE: return "HW version failure";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_SD_VERSION_FAILURE: return "SD version failure";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_SIGNATURE_MISSING : return "Signature mismatch";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_WRONG_HASH_TYPE: return "Wrong hash type";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_HASH_FAILED: return "Hash failed";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_WRONG_SIGNATURE_TYPE: return "Wring signature type";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_VERIFICATION_FAILED: return "Verification failed";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_EXTENDED | EXT_ERROR_INSUFFICIENT_SPACE: return "Insufficient space";
|
||||
default:
|
||||
return "Reserved for future use";
|
||||
}
|
||||
}
|
||||
|
||||
public static String parseButtonlessError(final int error) {
|
||||
switch (error) {
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_BUTTONLESS | BUTTONLESS_ERROR_OP_CODE_NOT_SUPPORTED: return "OP CODE NOT SUPPORTED";
|
||||
case DfuBaseService.ERROR_REMOTE_TYPE_SECURE_BUTTONLESS | BUTTONLESS_ERROR_OPERATION_FAILED: return "OPERATION FAILED";
|
||||
default:
|
||||
return "UNKNOWN (" + error + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue