Improve the progress events

At the moment the progress events are reported for each download
operation separately. Combined with the fact that the size of the dives
isn't known in advance, and thus the progress events are based on a
worst case value, the user experience is far from optimal. In practice,
the progress goes from 0 to 100% for every manifest, and it stays close
to zero while downloading the dives.

This is improved by combining the individual progress events into a
single progress for the entire download. This global progress simply
counts the number of individual download operations. Since each
operation is now subdivided into a fixed number of steps, regardless of
the size of the transfer, the perceived speed is no longer constant.
This commit is contained in:
Jef Driesen 2017-11-15 22:47:23 +01:00
parent 2d7d5152b4
commit 2ced18870d
4 changed files with 65 additions and 14 deletions

View File

@ -342,7 +342,7 @@ shearwater_common_transfer (shearwater_common_device_t *device, const unsigned c
dc_status_t
shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int address, unsigned int size, unsigned int compression)
shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int address, unsigned int size, unsigned int compression, dc_event_progress_t *progress)
{
dc_device_t *abstract = (dc_device_t *) device;
dc_status_t rc = DC_STATUS_SUCCESS;
@ -370,9 +370,11 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}
// Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
progress.maximum = 3 + size + 1;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
unsigned int initial = 0, current = 0, maximum = 3 + size + 1;
if (progress) {
initial = progress->current;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
}
// Transfer the init request.
rc = shearwater_common_transfer (device, req_init, sizeof (req_init), response, 3, &n);
@ -387,8 +389,11 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}
// Update and emit a progress event.
progress.current += 3;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
if (progress) {
current += 3;
progress->current = initial + STEP (current, maximum);
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
}
unsigned int done = 0;
unsigned char block = 1;
@ -415,8 +420,11 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}
// Update and emit a progress event.
progress.current += length;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
if (progress) {
current += length;
progress->current = initial + STEP (current, maximum);
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
}
if (compression) {
if (shearwater_common_decompress_lre (response + 2, length, buffer, &done) != 0) {
@ -454,8 +462,11 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}
// Update and emit a progress event.
progress.current += 1;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
if (progress) {
current += 1;
progress->current = initial + STEP (current, maximum);
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
}
return DC_STATUS_SUCCESS;
}

View File

@ -39,6 +39,9 @@ extern "C" {
#define PERDIX 5
#define PERDIXAI 6
#define NSTEPS 10000
#define STEP(i,n) ((NSTEPS * (i) + (n) / 2) / (n))
typedef struct shearwater_common_device_t {
dc_device_t base;
dc_serial_t *port;
@ -54,7 +57,7 @@ dc_status_t
shearwater_common_transfer (shearwater_common_device_t *device, const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize, unsigned int *actual);
dc_status_t
shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int address, unsigned int size, unsigned int compression);
shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int address, unsigned int size, unsigned int compression, dc_event_progress_t *progress);
dc_status_t
shearwater_common_identifier (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int id);

View File

@ -168,6 +168,11 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
return DC_STATUS_NOMEMORY;
}
// Enable progress notifications.
unsigned int current = 0, maximum = 0;
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
// Read the serial number.
rc = shearwater_common_identifier (&device->base, buffer, ID_SERIAL);
if (rc != DC_STATUS_SUCCESS) {
@ -240,8 +245,16 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
while (1) {
// Update the progress state.
// Assume the worst case scenario of a full manifest, and adjust the
// value with the actual number of dives after the manifest has been
// processed.
maximum += 1 + RECORD_COUNT;
// Download a manifest.
rc = shearwater_common_download (&device->base, buffer, MANIFEST_ADDR, MANIFEST_SIZE, 0);
progress.current = NSTEPS * current;
progress.maximum = NSTEPS * maximum;
rc = shearwater_common_download (&device->base, buffer, MANIFEST_ADDR, MANIFEST_SIZE, 0, &progress);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to download the manifest.");
dc_buffer_free (buffer);
@ -270,6 +283,10 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
count++;
}
// Update the progress state.
current += 1;
maximum -= RECORD_COUNT - count;
// Append the manifest records to the main buffer.
if (!dc_buffer_append (manifests, data, count * RECORD_SIZE)) {
ERROR (abstract->context, "Insufficient buffer space available.");
@ -283,6 +300,11 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
break;
}
// Update and emit a progress event.
progress.current = NSTEPS * current;
progress.maximum = NSTEPS * maximum;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
// Cache the buffer pointer and size.
unsigned char *data = dc_buffer_get_data (manifests);
unsigned int size = dc_buffer_get_size (manifests);
@ -293,7 +315,9 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
unsigned int address = array_uint32_be (data + offset + 20);
// Download the dive.
rc = shearwater_common_download (&device->base, buffer, DIVE_ADDR + address, DIVE_SIZE, 1);
progress.current = NSTEPS * current;
progress.maximum = NSTEPS * maximum;
rc = shearwater_common_download (&device->base, buffer, DIVE_ADDR + address, DIVE_SIZE, 1, &progress);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to download the dive.");
dc_buffer_free (buffer);
@ -301,6 +325,9 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
return rc;
}
// Update the progress state.
current += 1;
unsigned char *buf = dc_buffer_get_data (buffer);
unsigned int len = dc_buffer_get_size (buffer);
if (callback && !callback (buf, len, buf + 12, sizeof (device->fingerprint), userdata))
@ -309,6 +336,11 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
offset += RECORD_SIZE;
}
// Update and emit a progress event.
progress.current = NSTEPS * current;
progress.maximum = NSTEPS * maximum;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
dc_buffer_free (manifests);
dc_buffer_free (buffer);

View File

@ -133,7 +133,12 @@ shearwater_predator_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
return DC_STATUS_NOMEMORY;
}
return shearwater_common_download (device, buffer, 0xDD000000, SZ_MEMORY, 0);
// Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
progress.current = 0;
progress.maximum = NSTEPS;
return shearwater_common_download (device, buffer, 0xDD000000, SZ_MEMORY, 0, &progress);
}