From 2ced18870dbd0e8b1f290b85e96e0bbeebec6686 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 15 Nov 2017 22:47:23 +0100 Subject: [PATCH] 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. --- src/shearwater_common.c | 31 +++++++++++++++++++++---------- src/shearwater_common.h | 5 ++++- src/shearwater_petrel.c | 36 ++++++++++++++++++++++++++++++++++-- src/shearwater_predator.c | 7 ++++++- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/shearwater_common.c b/src/shearwater_common.c index c6dafbb..d4b8297 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -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; } diff --git a/src/shearwater_common.h b/src/shearwater_common.h index 2283154..4253a00 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -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); diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 3b60bf4..46a7582 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -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); diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index 3cc79f1..a47d414 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -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); }