Support for extended errors added
This commit is contained in:
parent
300dadf124
commit
7ee6b3258a
|
@ -38,6 +38,7 @@ import no.nordicsemi.android.dfu.internal.ArchiveInputStream;
|
||||||
import no.nordicsemi.android.dfu.internal.exception.DeviceDisconnectedException;
|
import no.nordicsemi.android.dfu.internal.exception.DeviceDisconnectedException;
|
||||||
import no.nordicsemi.android.dfu.internal.exception.DfuException;
|
import no.nordicsemi.android.dfu.internal.exception.DfuException;
|
||||||
import no.nordicsemi.android.dfu.internal.exception.RemoteDfuException;
|
import no.nordicsemi.android.dfu.internal.exception.RemoteDfuException;
|
||||||
|
import no.nordicsemi.android.dfu.internal.exception.RemoteDfuExtendedErrorException;
|
||||||
import no.nordicsemi.android.dfu.internal.exception.UnknownResponseException;
|
import no.nordicsemi.android.dfu.internal.exception.UnknownResponseException;
|
||||||
import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
|
import no.nordicsemi.android.dfu.internal.exception.UploadAbortedException;
|
||||||
import no.nordicsemi.android.error.SecureDfuError;
|
import no.nordicsemi.android.error.SecureDfuError;
|
||||||
|
@ -59,7 +60,6 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
private static final int OP_CODE_PACKET_RECEIPT_NOTIF_REQ_KEY = 0x02;
|
private static final int OP_CODE_PACKET_RECEIPT_NOTIF_REQ_KEY = 0x02;
|
||||||
private static final int OP_CODE_CALCULATE_CHECKSUM_KEY = 0x03;
|
private static final int OP_CODE_CALCULATE_CHECKSUM_KEY = 0x03;
|
||||||
private static final int OP_CODE_EXECUTE_KEY = 0x04;
|
private static final int OP_CODE_EXECUTE_KEY = 0x04;
|
||||||
private static final int OP_CODE_READ_ERROR_KEY = 0x05;
|
|
||||||
private static final int OP_CODE_SELECT_OBJECT_KEY = 0x06;
|
private static final int OP_CODE_SELECT_OBJECT_KEY = 0x06;
|
||||||
private static final int OP_CODE_RESPONSE_CODE_KEY = 0x60;
|
private static final int OP_CODE_RESPONSE_CODE_KEY = 0x60;
|
||||||
private static final byte[] OP_CODE_CREATE_COMMAND = new byte[]{OP_CODE_CREATE_KEY, OBJECT_COMMAND, 0x00, 0x00, 0x00, 0x00 };
|
private static final byte[] OP_CODE_CREATE_COMMAND = new byte[]{OP_CODE_CREATE_KEY, OBJECT_COMMAND, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
@ -67,7 +67,6 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
private static final byte[] OP_CODE_PACKET_RECEIPT_NOTIF_REQ = new byte[]{OP_CODE_PACKET_RECEIPT_NOTIF_REQ_KEY, 0x00, 0x00 /* param PRN uint16 in Little Endian */};
|
private static final byte[] OP_CODE_PACKET_RECEIPT_NOTIF_REQ = new byte[]{OP_CODE_PACKET_RECEIPT_NOTIF_REQ_KEY, 0x00, 0x00 /* param PRN uint16 in Little Endian */};
|
||||||
private static final byte[] OP_CODE_CALCULATE_CHECKSUM = new byte[]{OP_CODE_CALCULATE_CHECKSUM_KEY};
|
private static final byte[] OP_CODE_CALCULATE_CHECKSUM = new byte[]{OP_CODE_CALCULATE_CHECKSUM_KEY};
|
||||||
private static final byte[] OP_CODE_EXECUTE = new byte[]{OP_CODE_EXECUTE_KEY};
|
private static final byte[] OP_CODE_EXECUTE = new byte[]{OP_CODE_EXECUTE_KEY};
|
||||||
private static final byte[] OP_CODE_READ_ERROR = new byte[]{OP_CODE_READ_ERROR_KEY};
|
|
||||||
private static final byte[] OP_CODE_SELECT_OBJECT = new byte[]{OP_CODE_SELECT_OBJECT_KEY, 0x00 /* type */};
|
private static final byte[] OP_CODE_SELECT_OBJECT = new byte[]{OP_CODE_SELECT_OBJECT_KEY, 0x00 /* type */};
|
||||||
|
|
||||||
private BluetoothGattCharacteristic mControlPointCharacteristic;
|
private BluetoothGattCharacteristic mControlPointCharacteristic;
|
||||||
|
@ -101,9 +100,8 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
/*
|
/*
|
||||||
* If the DFU target device is in invalid state (f.e. the Init Packet is required but has not been selected), the target will send DFU_STATUS_INVALID_STATE error
|
* If the DFU target device is in invalid state (e.g. the Init Packet is required but has not been selected), the target will send DFU_STATUS_INVALID_STATE error
|
||||||
* for each firmware packet that was send. We are interested may ignore all but the first one.
|
* for each firmware packet that was send. We are interested may ignore all but the first one.
|
||||||
* After obtaining a remote DFU error the OP_CODE_RESET_KEY will be sent.
|
|
||||||
*/
|
*/
|
||||||
if (mRemoteErrorOccurred)
|
if (mRemoteErrorOccurred)
|
||||||
break;
|
break;
|
||||||
|
@ -221,20 +219,10 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, String.format("Remote DFU error: %s", 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.
|
// For the Extended Error more details can be obtained on some devices.
|
||||||
if (e.getErrorNumber() == SecureDfuError.EXTENDED_ERROR) {
|
if (e instanceof RemoteDfuExtendedErrorException) {
|
||||||
try {
|
final RemoteDfuExtendedErrorException ee = (RemoteDfuExtendedErrorException) e;
|
||||||
final ErrorMessage details = readExtendedError();
|
logi("Extended Error details: " + SecureDfuError.parseExtendedError(ee.getExtendedErrorNumber()));
|
||||||
if (details != null) {
|
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, "Details: " + SecureDfuError.parseExtendedError(ee.getExtendedErrorNumber()) + " (Code = " + ee.getExtendedErrorNumber() + ")");
|
||||||
logi("Error details: " + details.message + " (Code = " + details.code + ")");
|
|
||||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, "Details: " + details.message + " (Code = " + details.code + ")");
|
|
||||||
} else {
|
|
||||||
logi("Reading error details not supported");
|
|
||||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_WARNING, "Reading error details not supported");
|
|
||||||
}
|
|
||||||
} catch (final Exception e1) {
|
|
||||||
loge("Reading error details failed", e1);
|
|
||||||
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_WARNING, "Reading error details failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mService.terminateConnection(gatt, error);
|
mService.terminateConnection(gatt, error);
|
||||||
}
|
}
|
||||||
|
@ -631,6 +619,8 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
// Read response
|
// Read response
|
||||||
final byte[] response = readNotificationResponse();
|
final byte[] response = readNotificationResponse();
|
||||||
final int status = getStatusCode(response, OP_CODE_PACKET_RECEIPT_NOTIF_REQ_KEY);
|
final int status = getStatusCode(response, OP_CODE_PACKET_RECEIPT_NOTIF_REQ_KEY);
|
||||||
|
if (status == SecureDfuError.EXTENDED_ERROR)
|
||||||
|
throw new RemoteDfuExtendedErrorException("Sending the number of packets failed", response[3]);
|
||||||
if (status != DFU_STATUS_SUCCESS)
|
if (status != DFU_STATUS_SUCCESS)
|
||||||
throw new RemoteDfuException("Sending the number of packets failed", status);
|
throw new RemoteDfuException("Sending the number of packets failed", status);
|
||||||
}
|
}
|
||||||
|
@ -671,58 +661,12 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
|
|
||||||
final byte[] response = readNotificationResponse();
|
final byte[] response = readNotificationResponse();
|
||||||
final int status = getStatusCode(response, OP_CODE_CREATE_KEY);
|
final int status = getStatusCode(response, OP_CODE_CREATE_KEY);
|
||||||
|
if (status == SecureDfuError.EXTENDED_ERROR)
|
||||||
|
throw new RemoteDfuExtendedErrorException("Creating Command object failed", response[3]);
|
||||||
if (status != DFU_STATUS_SUCCESS)
|
if (status != DFU_STATUS_SUCCESS)
|
||||||
throw new RemoteDfuException("Creating Command object failed", status);
|
throw new RemoteDfuException("Creating Command object failed", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the last error message from the device. This can be executed after a {@link SecureDfuError#EXTENDED_ERROR} status is received
|
|
||||||
* from any Execute operation.
|
|
||||||
*
|
|
||||||
* @return the error details or null if this feature is not supported
|
|
||||||
* @throws DeviceDisconnectedException
|
|
||||||
* @throws DfuException
|
|
||||||
* @throws UploadAbortedException
|
|
||||||
* @throws RemoteDfuException thrown when the returned status code is not equal to {@link #DFU_STATUS_SUCCESS}
|
|
||||||
*/
|
|
||||||
private ErrorMessage readExtendedError() throws DeviceDisconnectedException, DfuException, UploadAbortedException, RemoteDfuException, UnknownResponseException {
|
|
||||||
if (!mConnected)
|
|
||||||
throw new DeviceDisconnectedException("Unable to read object info: device disconnected");
|
|
||||||
|
|
||||||
mRemoteErrorOccurred = false;
|
|
||||||
final BluetoothGattCharacteristic characteristic = mControlPointCharacteristic;
|
|
||||||
writeOpCode(characteristic, OP_CODE_READ_ERROR);
|
|
||||||
|
|
||||||
final byte[] response = readNotificationResponse();
|
|
||||||
final int status = getStatusCode(response, OP_CODE_READ_ERROR_KEY);
|
|
||||||
|
|
||||||
if (status == DFU_STATUS_SUCCESS) {
|
|
||||||
final int code = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 3);
|
|
||||||
int length = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 5);
|
|
||||||
if (code == 0 && length == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append(characteristic.getStringValue(7));
|
|
||||||
|
|
||||||
while (length - builder.length() > 0) {
|
|
||||||
writeOpCode(characteristic, OP_CODE_READ_ERROR);
|
|
||||||
readNotificationResponse();
|
|
||||||
builder.append(characteristic.getStringValue(3));
|
|
||||||
|
|
||||||
// Finish if byte 0 is received at the end
|
|
||||||
if (characteristic.getValue()[characteristic.getValue().length - 1] == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ErrorMessage error = new ErrorMessage();
|
|
||||||
error.code = code;
|
|
||||||
error.message = builder.toString();
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the current object and reads its metadata. The object info contains the max object size, and the offset and CRC32 of the whole object until now.
|
* Selects the current object and reads its metadata. The object info contains the max object size, and the offset and CRC32 of the whole object until now.
|
||||||
*
|
*
|
||||||
|
@ -741,6 +685,8 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
|
|
||||||
final byte[] response = readNotificationResponse();
|
final byte[] response = readNotificationResponse();
|
||||||
final int status = getStatusCode(response, OP_CODE_SELECT_OBJECT_KEY);
|
final int status = getStatusCode(response, OP_CODE_SELECT_OBJECT_KEY);
|
||||||
|
if (status == SecureDfuError.EXTENDED_ERROR)
|
||||||
|
throw new RemoteDfuExtendedErrorException("Selecting object failed", response[3]);
|
||||||
if (status != DFU_STATUS_SUCCESS)
|
if (status != DFU_STATUS_SUCCESS)
|
||||||
throw new RemoteDfuException("Selecting object failed", status);
|
throw new RemoteDfuException("Selecting object failed", status);
|
||||||
|
|
||||||
|
@ -768,6 +714,8 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
|
|
||||||
final byte[] response = readNotificationResponse();
|
final byte[] response = readNotificationResponse();
|
||||||
final int status = getStatusCode(response, OP_CODE_CALCULATE_CHECKSUM_KEY);
|
final int status = getStatusCode(response, OP_CODE_CALCULATE_CHECKSUM_KEY);
|
||||||
|
if (status == SecureDfuError.EXTENDED_ERROR)
|
||||||
|
throw new RemoteDfuExtendedErrorException("Receiving Checksum failed", response[3]);
|
||||||
if (status != DFU_STATUS_SUCCESS)
|
if (status != DFU_STATUS_SUCCESS)
|
||||||
throw new RemoteDfuException("Receiving Checksum failed", status);
|
throw new RemoteDfuException("Receiving Checksum failed", status);
|
||||||
|
|
||||||
|
@ -796,6 +744,8 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
|
|
||||||
final byte[] response = readNotificationResponse();
|
final byte[] response = readNotificationResponse();
|
||||||
final int status = getStatusCode(response, OP_CODE_EXECUTE_KEY);
|
final int status = getStatusCode(response, OP_CODE_EXECUTE_KEY);
|
||||||
|
if (status == SecureDfuError.EXTENDED_ERROR)
|
||||||
|
throw new RemoteDfuExtendedErrorException("Executing object failed", response[3]);
|
||||||
if (status != DFU_STATUS_SUCCESS)
|
if (status != DFU_STATUS_SUCCESS)
|
||||||
throw new RemoteDfuException("Executing object failed", status);
|
throw new RemoteDfuException("Executing object failed", status);
|
||||||
}
|
}
|
||||||
|
@ -808,9 +758,4 @@ import no.nordicsemi.android.error.SecureDfuError;
|
||||||
protected int offset;
|
protected int offset;
|
||||||
protected int CRC32;
|
protected int CRC32;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ErrorMessage {
|
|
||||||
protected int code;
|
|
||||||
protected String message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,18 +35,12 @@ public final class LegacyDfuError {
|
||||||
|
|
||||||
public static String parse(final int error) {
|
public static String parse(final int error) {
|
||||||
switch (error & (~DfuBaseService.ERROR_REMOTE_MASK)) {
|
switch (error & (~DfuBaseService.ERROR_REMOTE_MASK)) {
|
||||||
case INVALID_STATE:
|
case INVALID_STATE: return "REMOTE DFU INVALID STATE";
|
||||||
return "REMOTE DFU INVALID STATE";
|
case NOT_SUPPORTED: return "REMOTE DFU NOT SUPPORTED";
|
||||||
case NOT_SUPPORTED:
|
case DATA_SIZE_EXCEEDS_LIMIT: return "REMOTE DFU DATA SIZE EXCEEDS LIMIT";
|
||||||
return "REMOTE DFU NOT SUPPORTED";
|
case CRC_ERROR: return "REMOTE DFU INVALID CRC ERROR";
|
||||||
case DATA_SIZE_EXCEEDS_LIMIT:
|
case OPERATION_FAILED: return "REMOTE DFU OPERATION FAILED";
|
||||||
return "REMOTE DFU DATA SIZE EXCEEDS LIMIT";
|
default: return "UNKNOWN (" + error + ")";
|
||||||
case CRC_ERROR:
|
|
||||||
return "REMOTE DFU INVALID CRC ERROR";
|
|
||||||
case OPERATION_FAILED:
|
|
||||||
return "REMOTE DFU OPERATION FAILED";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN (" + error + ")";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,27 +36,49 @@ public final class SecureDfuError {
|
||||||
public static final int OPERATION_FAILED = 10; // 0xA
|
public static final int OPERATION_FAILED = 10; // 0xA
|
||||||
public static final int EXTENDED_ERROR = 11; // 0xB
|
public static final int EXTENDED_ERROR = 11; // 0xB
|
||||||
|
|
||||||
|
// public static final int EXT_ERROR_NO_ERROR = 0x00; // that's not an error
|
||||||
|
public static final int EXT_ERROR_WRONG_COMMAND_FORMAT = 0x02;
|
||||||
|
public static final int EXT_ERROR_UNKNOWN_COMMAND = 0x03;
|
||||||
|
public static final int EXT_ERROR_INIT_COMMAND_INVALID = 0x04;
|
||||||
|
public static final int EXT_ERROR_FW_VERSION_FAILURE = 0x05;
|
||||||
|
public static final int EXT_ERROR_HW_VERSION_FAILURE = 0x06;
|
||||||
|
public static final int EXT_ERROR_SD_VERSION_FAILURE = 0x07;
|
||||||
|
public static final int EXT_ERROR_SIGNATURE_MISSING = 0x08;
|
||||||
|
public static final int EXT_ERROR_WRONG_HASH_TYPE = 0x09;
|
||||||
|
public static final int EXT_ERROR_HASH_FAILED = 0x0A;
|
||||||
|
public static final int EXT_ERROR_WRONG_SIGNATURE_TYPE = 0x0B;
|
||||||
|
public static final int EXT_ERROR_VERIFICATION_FAILED = 0x0C;
|
||||||
|
public static final int EXT_ERROR_INSUFFICIENT_SPACE = 0x0D;
|
||||||
|
|
||||||
public static String parse(final int error) {
|
public static String parse(final int error) {
|
||||||
switch (error & (~DfuBaseService.ERROR_REMOTE_MASK)) {
|
switch (error & (~DfuBaseService.ERROR_REMOTE_MASK)) {
|
||||||
case OP_CODE_NOT_SUPPORTED:
|
case OP_CODE_NOT_SUPPORTED: return "REMOTE DFU OP CODE NOT SUPPORTED";
|
||||||
return "REMOTE DFU OP CODE NOT SUPPORTED";
|
case INVALID_PARAM: return "REMOTE DFU INVALID PARAM";
|
||||||
case INVALID_PARAM:
|
case INSUFFICIENT_RESOURCES: return "REMOTE DFU INSUFFICIENT RESOURCES";
|
||||||
return "REMOTE DFU INVALID PARAM";
|
case INVALID_OBJECT: return "REMOTE DFU INVALID OBJECT";
|
||||||
case INSUFFICIENT_RESOURCES:
|
case UNSUPPORTED_TYPE: return "REMOTE DFU UNSUPPORTED TYPE";
|
||||||
return "REMOTE DFU INSUFFICIENT RESOURCES";
|
case OPERATION_NOT_PERMITTED: return "REMOTE DFU OPERATION NOT PERMITTED";
|
||||||
case INVALID_OBJECT:
|
case OPERATION_FAILED: return "REMOTE DFU OPERATION FAILED";
|
||||||
return "REMOTE DFU INVALID OBJECT";
|
case EXTENDED_ERROR: return "REMOTE DFU EXTENDED ERROR";
|
||||||
case UNSUPPORTED_TYPE:
|
default: return "UNKNOWN (" + error + ")";
|
||||||
return "REMOTE DFU UNSUPPORTED TYPE";
|
}
|
||||||
case OPERATION_NOT_PERMITTED:
|
}
|
||||||
return "REMOTE DFU OPERATION NOT PERMITTED";
|
|
||||||
case OPERATION_FAILED:
|
public static String parseExtendedError(final int error) {
|
||||||
return "REMOTE DFU OPERATION FAILED";
|
switch (error) {
|
||||||
case EXTENDED_ERROR:
|
case EXT_ERROR_WRONG_COMMAND_FORMAT: return "Wrong command format";
|
||||||
// The error details can be read using Read Error operation
|
case EXT_ERROR_UNKNOWN_COMMAND: return "Unknown command";
|
||||||
return "REMOTE DFU EXTENDED ERROR";
|
case EXT_ERROR_INIT_COMMAND_INVALID: return "Init command invalid";
|
||||||
default:
|
case EXT_ERROR_FW_VERSION_FAILURE: return "FW version failure";
|
||||||
return "UNKNOWN (" + error + ")";
|
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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue