Splitting implementation into 2 methods

This commit is contained in:
Aleksander Nowakowski 2016-06-10 14:02:23 +02:00
parent 258a6ade64
commit 8b8932fd57
1 changed files with 315 additions and 274 deletions

View File

@ -207,17 +207,75 @@ import no.nordicsemi.android.error.SecureDfuError;
// End // End
try { try {
sendInitPacket(gatt);
sendFirmware(gatt);
// The device will reset so we don't have to send Disconnect signal.
mProgressInfo.setProgress(DfuBaseService.PROGRESS_DISCONNECTING);
mService.waitUntilDisconnected();
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_INFO, "Disconnected by the remote device");
// We are ready with DFU, the device is disconnected, let's close it and finalize the operation.
finalize(intent, false);
} catch (final UnknownResponseException e) {
final int error = DfuBaseService.ERROR_INVALID_RESPONSE;
loge(e.getMessage());
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());
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, String.format("Remote DFU error: %s", SecureDfuError.parse(error)));
try {
final ErrorMessage details = readLastError();
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, "Details: " + details.message + " (Code = " + details.code + ")");
logi("Error details: " + details.message + " (Code = " + details.code + ")");
} catch (final Exception e1) {
loge("Reading error details failed", e1);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_WARNING, "Reading error details failed");
}
mService.terminateConnection(gatt, error);
}
}
/**
* This method does the following:
* <ol>
* <li>Reads Command Object Info - this returns the maximum acceptable size of a command object, and the offset and CRC32 of the command
* that is already stored in the device (in case the DFU was started in a previous connection and disconnected before it has finished).</li>
* <li>If the offset received is greater than 0 and less or equal to the size of the Init file that is to be sent, it will compare the
* received CRC with the local one and, if they match:
* <ul>
* <li>If offset < init file size - it will continue sending the Init file from the point it stopped before,</li>
* <li>If offset == init file size - it will send the Calculate Checksum request to obtain a CRC of a current object.
* <ul>
* <li>If the received CRC is the same as above ones, it will send Execute command to execute the Init file, as it may have not been executed before.</li>
* <li>If the received CRC is different, that means that the Data Object has already been created in the previous connection and this method will return.</li>
* </ul>
* </li>
* </ul>
* </li>
* <li>If the CRCs don't match, or the received offset is > init file size, it create the Command Object and send the whole Init file as the previous one
* was different.</li>
* </ol>
* Sending of the Init packet is done without using PRNs (Packet Receipt Notifications), so they are disabled prior to sending the data.
* @param gatt the target GATT device
* @throws RemoteDfuException
* @throws DeviceDisconnectedException
* @throws DfuException
* @throws UploadAbortedException
* @throws UnknownResponseException
*/
private void sendInitPacket(final BluetoothGatt gatt) throws RemoteDfuException, DeviceDisconnectedException, DfuException, UploadAbortedException, UnknownResponseException {
final CRC32 crc32 = new CRC32(); // Used to calculate CRC32 of the Init packet final CRC32 crc32 = new CRC32(); // Used to calculate CRC32 of the Init packet
ObjectChecksum checksum; ObjectChecksum checksum;
ObjectInfo info;
byte[] response;
int status;
// First, read the Command Object Info. This give information about the maximum command size and whether there is already // First, read the Command Object Info. This give information about the maximum command size and whether there is already
// one saved from a previous connection. It offset and CRC returned are not equal zero, we can compare it with the current init file // one saved from a previous connection. It offset and CRC returned are not equal zero, we can compare it with the current init file
// and skip sending it for the second time. // and skip sending it for the second time.
logi("Sending Read Command Object Info command (Op Code = 6, Type = 1)"); logi("Sending Read Command Object Info command (Op Code = 6, Type = 1)");
info = readObjectInfo(OBJECT_COMMAND); final ObjectInfo info = readObjectInfo(OBJECT_COMMAND);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Command object info received (Max size = %d, Offset = %d, CRC = %08X)", info.maxSize, info.offset, info.CRC32)); mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Command object info received (Max size = %d, Offset = %d, CRC = %08X)", info.maxSize, info.offset, info.CRC32));
if (mInitPacketSizeInBytes > info.maxSize) { if (mInitPacketSizeInBytes > info.maxSize) {
// Ignore this. DFU target will send an error if init packet is too large after sending the 'Create object' command // Ignore this. DFU target will send an error if init packet is too large after sending the 'Create object' command
@ -227,7 +285,7 @@ import no.nordicsemi.android.error.SecureDfuError;
// and resume sending the init packet, or even skip sending it if the whole file was sent before. // and resume sending the init packet, or even skip sending it if the whole file was sent before.
boolean skipSendingInitPacket = false; boolean skipSendingInitPacket = false;
boolean resumeSendingInitPacket = false; boolean resumeSendingInitPacket = false;
if (info.offset > 0) { if (info.offset > 0 && info.offset <= mInitPacketSizeInBytes) {
try { try {
// Read the same number of bytes from the current init packet to calculate local CRC32 // Read the same number of bytes from the current init packet to calculate local CRC32
final byte[] buffer = new byte[info.offset]; final byte[] buffer = new byte[info.offset];
@ -251,7 +309,7 @@ import no.nordicsemi.android.error.SecureDfuError;
} }
} else { } else {
// A different Init packet was sent before, or the error occurred while sending. // A different Init packet was sent before, or the error occurred while sending.
// We have to send the while Init packet again. // We have to send the whole Init packet again.
mInitPacketStream.reset(); mInitPacketStream.reset();
crc32.reset(); crc32.reset();
} }
@ -352,7 +410,18 @@ import no.nordicsemi.android.error.SecureDfuError;
// It looks like we have started sending the Data already, let's continue // It looks like we have started sending the Data already, let's continue
} }
} }
}
/**
* This method enables
* @param gatt the target GATT device
* @throws RemoteDfuException
* @throws DeviceDisconnectedException
* @throws DfuException
* @throws UploadAbortedException
* @throws UnknownResponseException
*/
private void sendFirmware(final BluetoothGatt gatt) throws RemoteDfuException, DeviceDisconnectedException, DfuException, UploadAbortedException, UnknownResponseException {
// Send the number of packets of firmware before receiving a receipt notification // Send the number of packets of firmware before receiving a receipt notification
final int numberOfPacketsBeforeNotification = mPacketsBeforeNotification; final int numberOfPacketsBeforeNotification = mPacketsBeforeNotification;
if (numberOfPacketsBeforeNotification > 0) { if (numberOfPacketsBeforeNotification > 0) {
@ -366,7 +435,7 @@ import no.nordicsemi.android.error.SecureDfuError;
logi("Sending Read Data Object Info command (Op Code = 6, Type = 2)"); logi("Sending Read Data Object Info command (Op Code = 6, Type = 2)");
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Reading data object info..."); mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Reading data object info...");
info = readObjectInfo(OBJECT_DATA); final ObjectInfo info = readObjectInfo(OBJECT_DATA);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Data object info received (Max size = %d, Offset = %d, CRC = %08X)", info.maxSize, info.offset, info.CRC32)); mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Data object info received (Max size = %d, Offset = %d, CRC = %08X)", info.maxSize, info.offset, info.CRC32));
mProgressInfo.setMaxObjectSizeInBytes(info.maxSize); mProgressInfo.setMaxObjectSizeInBytes(info.maxSize);
@ -442,7 +511,7 @@ import no.nordicsemi.android.error.SecureDfuError;
// Calculate Checksum // Calculate Checksum
logi("Sending Calculate Checksum command (Op Code = 3)"); logi("Sending Calculate Checksum command (Op Code = 3)");
checksum = readChecksum(); final ObjectChecksum checksum = readChecksum();
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Checksum received (Offset = %d, CRC = %08X)", checksum.offset, checksum.CRC32)); mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, String.format(Locale.US, "Checksum received (Offset = %d, CRC = %08X)", checksum.offset, checksum.CRC32));
logi(String.format(Locale.US, "Checksum received (Offset = %d, CRC = %08X)", checksum.offset, checksum.CRC32)); logi(String.format(Locale.US, "Checksum received (Offset = %d, CRC = %08X)", checksum.offset, checksum.CRC32));
@ -481,34 +550,6 @@ import no.nordicsemi.android.error.SecureDfuError;
final long endTime = SystemClock.elapsedRealtime(); final long endTime = SystemClock.elapsedRealtime();
logi("Transfer of " + mProgressInfo.getBytesSent() + " bytes has taken " + (endTime - startTime) + " ms"); logi("Transfer of " + mProgressInfo.getBytesSent() + " bytes has taken " + (endTime - startTime) + " ms");
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Upload completed in " + (endTime - startTime) + " ms"); mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_APPLICATION, "Upload completed in " + (endTime - startTime) + " ms");
// The device will reset so we don't have to send Disconnect signal.
mProgressInfo.setProgress(DfuBaseService.PROGRESS_DISCONNECTING);
mService.waitUntilDisconnected();
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_INFO, "Disconnected by the remote device");
// We are ready with DFU, the device is disconnected, let's close it and finalize the operation.
finalize(intent, false);
} catch (final UnknownResponseException e) {
final int error = DfuBaseService.ERROR_INVALID_RESPONSE;
loge(e.getMessage());
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());
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, String.format("Remote DFU error: %s", SecureDfuError.parse(error)));
try {
final ErrorMessage details = readLastError();
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_ERROR, "Details: " + details.message + " (Code = " + details.code + ")");
logi("Error details: " + details.message + " (Code = " + details.code + ")");
} catch (final Exception e1) {
loge("Reading error details failed", e1);
mService.sendLogBroadcast(DfuBaseService.LOG_LEVEL_WARNING, "Reading error details failed");
}
mService.terminateConnection(gatt, error);
}
} }
/** /**