summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2012-11-11 14:29:26 +0100
committerGravatar Dirk Hohndel <dirk@hohndel.org>2012-11-11 14:29:26 +0100
commitfe4f13f184ffb97ee4b6dbd4138a9d8ae3aabd14 (patch)
treeae127ca3591cb72b86bd1b512134086902e140cd
parent78ad07c72ed37928020cdbf4842e24690ce35f81 (diff)
downloadsubsurface-fe4f13f184ffb97ee4b6dbd4138a9d8ae3aabd14.tar.gz
Add special download modes to force updates from the divecomputer
This will hopefully not be something we need often, but if we improve support for a divecomputer (either in libdivecomputer or in our native Uemis code or even in the way we handle (and potentially discard) events), then it is extremely useful to be able to say "re-download things from the divecomputer and for things that were not edited in Subsurface, don't try to merge the data (which gives BAD results if for example you fixed a bug in the depth calculation in libdivecomputer) but instead simply take the samples, the events and some of the other unedited data straight from the download". This commit implements just that - a "force download" checkbox in the download dialog that makes us reimport all dives from the dive computer, even the ones we already have, and an "always prefer downloaded dive" checkbox that then tells Subsurface not to merge but simply to take the data from the downloaded dive - without overwriting the things we have already edited in Subsurface (like location, buddy, equipment, etc). This, as a precaution, refuses to merge dives that don't have identical start times. So if you have edited the date / time of a dive or if you have previously merged your dive with a different dive computer (and therefore modified samples and events) you are out of luck. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r--display-gtk.h3
-rw-r--r--dive.c61
-rw-r--r--dive.h7
-rw-r--r--divelist.c4
-rw-r--r--gtk-gui.c27
-rw-r--r--libdivecomputer.c3
-rw-r--r--libdivecomputer.h1
-rw-r--r--main.c11
-rw-r--r--uemis-downloader.c8
9 files changed, 90 insertions, 35 deletions
diff --git a/display-gtk.h b/display-gtk.h
index d709696a6..4f156c7f7 100644
--- a/display-gtk.h
+++ b/display-gtk.h
@@ -113,6 +113,7 @@ typedef gint (*sort_func_t)(GtkTreeModel *model,
extern GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title,
data_func_t data_func, unsigned int flags);
-GError *uemis_download(const char *path, char **divenr, char **xml_buffer, progressbar_t *progress);
+GError *uemis_download(const char *path, char **divenr, char **xml_buffer,
+ progressbar_t *progress, gboolean force_download);
#endif
diff --git a/dive.c b/dive.c
index 295d14ae5..15038bd9e 100644
--- a/dive.c
+++ b/dive.c
@@ -590,6 +590,9 @@ struct dive *fixup_dive(struct dive *dive)
#define MERGE_TXT(res, a, b, n) res->n = merge_text(a->n, b->n)
#define MERGE_NONZERO(res, a, b, n) res->n = a->n ? a->n : b->n
+#define MERGE_MAX_PREFDL(res, dl, a, b, n) res->n = (dl && dl->n) ? dl->n : MAX(a->n, b->n)
+#define MERGE_MIN_PREFDL(res, dl, a, b, n) res->n = (dl && dl->n) ? dl->n : (a->n)?(b->n)?MIN(a->n, b->n):(a->n):(b->n)
+
static struct dive *add_sample(struct sample *sample, int time, struct dive *dive)
{
struct sample *p = prepare_sample(&dive);
@@ -684,6 +687,20 @@ add_sample_b:
}
}
+static struct dive *copy_samples(struct dive *res, struct dive *src)
+{
+ int samples = src->samples;
+ struct sample *s = src->sample;
+ while (samples) {
+ if (!res)
+ return NULL;
+ res = add_sample(s, s->time.seconds, res);
+ s++;
+ samples--;
+ }
+ return fixup_dive(res);
+}
+
static char *merge_text(const char *a, const char *b)
{
char *res;
@@ -1027,9 +1044,9 @@ static int find_sample_offset(struct dive *a, struct dive *b)
* merges almost exact duplicates - something that happens easily
* with overlapping dive downloads.
*/
-struct dive *try_to_merge(struct dive *a, struct dive *b)
+struct dive *try_to_merge(struct dive *a, struct dive *b, gboolean prefer_downloaded)
{
- int offset;
+ int offset = 0;
/*
* This assumes that the clocks on the dive computers are
@@ -1037,19 +1054,26 @@ struct dive *try_to_merge(struct dive *a, struct dive *b)
*/
if ((a->when >= b->when + 60) || (a->when <= b->when - 60))
return NULL;
-
- /* Dive 'a' is 'offset' seconds before dive 'b' */
- offset = find_sample_offset(a, b);
- if (offset > 120 || offset < -120)
+ if (prefer_downloaded && a->when != b->when)
return NULL;
-
- return merge_dives(a, b, offset);
+ if (!prefer_downloaded) {
+ /* Dive 'a' is 'offset' seconds before dive 'b' */
+ offset = find_sample_offset(a, b);
+ if (offset > 120 || offset < -120)
+ return NULL;
+ }
+ return merge_dives(a, b, offset, prefer_downloaded);
}
-struct dive *merge_dives(struct dive *a, struct dive *b, int offset)
+struct dive *merge_dives(struct dive *a, struct dive *b, int offset, gboolean prefer_downloaded)
{
struct dive *res = alloc_dive();
+ struct dive *dl = NULL;
+ if (a->downloaded)
+ dl = a;
+ else if (b->downloaded)
+ dl = b;
res->when = a->when;
res->selected = a->selected || b->selected;
merge_trip(res, a, b);
@@ -1062,16 +1086,21 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset)
MERGE_MAX(res, a, b, rating);
MERGE_TXT(res, a, b, suit);
MERGE_MAX(res, a, b, number);
- MERGE_MAX(res, a, b, maxdepth.mm);
+ MERGE_MAX_PREFDL(res, dl, a, b, maxdepth.mm);
res->meandepth.mm = 0;
MERGE_NONZERO(res, a, b, salinity);
MERGE_NONZERO(res, a, b, visibility);
MERGE_NONZERO(res, a, b, surface_pressure.mbar);
- MERGE_MAX(res, a, b, duration.seconds);
- MERGE_MAX(res, a, b, surfacetime.seconds);
- MERGE_MAX(res, a, b, airtemp.mkelvin);
- MERGE_MIN(res, a, b, watertemp.mkelvin);
+ MERGE_MAX_PREFDL(res, dl, a, b, duration.seconds);
+ MERGE_MAX_PREFDL(res, dl, a, b, surfacetime.seconds);
+ MERGE_MAX_PREFDL(res, dl, a, b, airtemp.mkelvin);
+ MERGE_MIN_PREFDL(res, dl, a, b, watertemp.mkelvin);
merge_equipment(res, a, b);
- merge_events(res, a, b, offset);
- return merge_samples(res, a, b, offset);
+ if (dl) {
+ res->events = dl->events;
+ return copy_samples(res, dl);
+ } else {
+ merge_events(res, a, b, offset);
+ return merge_samples(res, a, b, offset);
+ }
}
diff --git a/dive.h b/dive.h
index 481d8a17a..d4da7af07 100644
--- a/dive.h
+++ b/dive.h
@@ -261,6 +261,7 @@ struct dive {
tripflag_t tripflag;
dive_trip_t *divetrip;
int selected;
+ gboolean downloaded;
int start, end;
timestamp_t when;
char *location;
@@ -414,10 +415,10 @@ extern void delete_dive(struct dive *dive);
extern struct sample *prepare_sample(struct dive **divep);
extern void finish_sample(struct dive *dive);
-extern void report_dives(gboolean imported);
+extern void report_dives(gboolean imported, gboolean prefer_imported);
extern struct dive *fixup_dive(struct dive *dive);
-extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset);
-extern struct dive *try_to_merge(struct dive *a, struct dive *b);
+extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, gboolean prefer_downloaded);
+extern struct dive *try_to_merge(struct dive *a, struct dive *b, gboolean prefer_downloaded);
extern void renumber_dives(int nr);
diff --git a/divelist.c b/divelist.c
index fd55dcd60..10c1ce4b3 100644
--- a/divelist.c
+++ b/divelist.c
@@ -1417,7 +1417,7 @@ void add_dive_cb(GtkWidget *menuitem, gpointer data)
dive = alloc_dive();
if (add_new_dive(dive)) {
record_dive(dive);
- report_dives(TRUE);
+ report_dives(TRUE, FALSE);
return;
}
free(dive);
@@ -2088,7 +2088,7 @@ static void merge_dive_index(int i, struct dive *a)
struct dive *b = get_dive(i+1);
struct dive *res;
- res = merge_dives(a, b, b->when - a->when);
+ res = merge_dives(a, b, b->when - a->when, FALSE);
if (!res)
return;
diff --git a/gtk-gui.c b/gtk-gui.c
index a34f278b6..025cd1e45 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -43,6 +43,8 @@ static const char *default_dive_computer_vendor;
static const char *default_dive_computer_product;
static const char *default_dive_computer_device;
static char *uemis_max_dive_data;
+static gboolean force_download;
+static gboolean prefer_downloaded;
static int is_default_dive_computer(const char *vendor, const char *product)
{
@@ -350,7 +352,7 @@ static void file_open(GtkWidget *w, gpointer data)
}
g_free(filename);
g_slist_free(fn_glist);
- report_dives(FALSE);
+ report_dives(FALSE, FALSE);
}
gtk_widget_destroy(dialog);
}
@@ -510,6 +512,8 @@ OPTIONCALLBACK(autogroup_toggle, autogroup)
OPTIONCALLBACK(po2_toggle, partial_pressure_graphs.po2)
OPTIONCALLBACK(pn2_toggle, partial_pressure_graphs.pn2)
OPTIONCALLBACK(phe_toggle, partial_pressure_graphs.phe)
+OPTIONCALLBACK(force_toggle, force_download)
+OPTIONCALLBACK(prefer_dl_toggle, prefer_downloaded)
static void event_toggle(GtkWidget *w, gpointer _data)
{
@@ -1605,7 +1609,7 @@ void import_files(GtkWidget *w, gpointer data)
filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(fs_dialog));
if (filenames) {
g_slist_foreach(filenames, do_import_file, NULL);
- report_dives(TRUE);
+ report_dives(TRUE, FALSE);
g_slist_free(filenames);
}
}
@@ -1619,7 +1623,7 @@ static GError *setup_uemis_import(device_data_t *data)
GError *error = NULL;
char *buf = NULL;
- error = uemis_download(data->devname, &uemis_max_dive_data, &buf, &data->progress);
+ error = uemis_download(data->devname, &uemis_max_dive_data, &buf, &data->progress, data->force_download);
if (buf && strlen(buf) > 1) {
#ifdef DEBUGFILE
fprintf(debugfile, "xml buffer \"%s\"\n\n", buf);
@@ -1696,6 +1700,18 @@ void download_dialog(GtkWidget *w, gpointer data)
devicedata.progress.bar = gtk_progress_bar_new();
gtk_container_add(GTK_CONTAINER(hbox), devicedata.progress.bar);
+ force_download = FALSE;
+ button = gtk_check_button_new_with_label(_("Force download of all dives"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 6);
+ g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(force_toggle), NULL);
+
+ prefer_downloaded = FALSE;
+ button = gtk_check_button_new_with_label(_("Always prefer downloaded dive"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
+ gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 6);
+ g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(prefer_dl_toggle), NULL);
+
button = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
if (!gtk_combo_box_get_active_iter(computer, &iter))
gtk_widget_set_sensitive(button, FALSE);
@@ -1747,15 +1763,16 @@ repeat:
while (*(--ne) == ' ' || *ne == '\t')
*ne = '\0';
devicedata.devname = ns;
+ devicedata.force_download = force_download;
info = import_dive_computer(&devicedata, GTK_DIALOG(dialog));
free((void *)devname);
if (info)
goto repeat;
- report_dives(TRUE);
+ report_dives(TRUE, prefer_downloaded);
break;
default:
/* it's possible that some dives were downloaded */
- report_dives(TRUE);
+ report_dives(TRUE, prefer_downloaded);
break;
}
gtk_widget_destroy(dialog);
diff --git a/libdivecomputer.c b/libdivecomputer.c
index 6a9b07f80..f0c3c7549 100644
--- a/libdivecomputer.c
+++ b/libdivecomputer.c
@@ -311,9 +311,10 @@ static int dive_cb(const unsigned char *data, unsigned int size,
dc_parser_destroy(parser);
/* If we already saw this dive, abort. */
- if (find_dive(dive, devdata))
+ if (!devdata->force_download && find_dive(dive, devdata))
return 0;
+ dive->downloaded = TRUE;
record_dive(dive);
return 1;
}
diff --git a/libdivecomputer.h b/libdivecomputer.h
index 6430c8448..7497abf11 100644
--- a/libdivecomputer.h
+++ b/libdivecomputer.h
@@ -17,6 +17,7 @@ typedef struct device_data_t {
dc_context_t *context;
progressbar_t progress;
int preexisting;
+ gboolean force_download;
} device_data_t;
extern GError *do_import(device_data_t *data);
diff --git a/main.c b/main.c
index 88a28c8c2..1c4d33736 100644
--- a/main.c
+++ b/main.c
@@ -111,7 +111,7 @@ static gboolean imported = FALSE;
* This doesn't really report anything at all. We just sort the
* dives, the GUI does the reporting
*/
-void report_dives(gboolean is_imported)
+void report_dives(gboolean is_imported, gboolean prefer_imported)
{
int i;
int preexisting = dive_table.preexisting;
@@ -131,7 +131,7 @@ void report_dives(gboolean is_imported)
if (prev->when + prev->duration.seconds < dive->when)
continue;
- merged = try_to_merge(prev, dive);
+ merged = try_to_merge(prev, dive, prefer_imported);
if (!merged)
continue;
@@ -145,6 +145,9 @@ void report_dives(gboolean is_imported)
delete_single_dive(i+1);
delete_single_dive(i+1);
}
+ /* make sure no dives are still marked as downloaded */
+ for (i = 1; i < dive_table.nr; i++)
+ dive_table.dives[i]->downloaded = FALSE;
if (is_imported) {
/* Was the previous dive table state numbered? */
@@ -173,7 +176,7 @@ static void parse_argument(const char *arg)
if (strcmp(arg,"--import") == 0) {
/* mark the dives so far as the base,
* everything after is imported */
- report_dives(FALSE);
+ report_dives(FALSE, FALSE);
imported = TRUE;
return;
}
@@ -276,7 +279,7 @@ int main(int argc, char **argv)
set_filename(filename, FALSE);
free((void *)filename);
}
- report_dives(imported);
+ report_dives(imported, FALSE);
if (dive_table.nr == 0)
show_dive_info(NULL);
run_ui();
diff --git a/uemis-downloader.c b/uemis-downloader.c
index 6f85eca59..922aa90ae 100644
--- a/uemis-downloader.c
+++ b/uemis-downloader.c
@@ -44,6 +44,7 @@ struct argument_block {
char **max_dive_data;
char **xml_buffer;
progressbar_t *progress;
+ gboolean force_download;
};
static int import_thread_done = 0, import_thread_cancelled;
@@ -796,7 +797,7 @@ static char *do_uemis_download(struct argument_block *args)
* certainly want to start downloading from the first dive on
* the Uemis; otherwise check which was the last dive
* downloaded */
- if (dive_table.nr > 0)
+ if (!args->force_download && dive_table.nr > 0)
newmax = get_divenr(*max_dive_data, deviceid);
else
newmax = strdup("0");
@@ -874,11 +875,12 @@ static void *pthread_wrapper(void *_data)
return (void *)err_string;
}
-GError *uemis_download(const char *mountpath, char **max_dive_data, char **xml_buffer, progressbar_t *progress)
+GError *uemis_download(const char *mountpath, char **max_dive_data, char **xml_buffer, progressbar_t *progress,
+ gboolean force_download)
{
pthread_t pthread;
void *retval;
- struct argument_block args = {mountpath, max_dive_data, xml_buffer, progress};
+ struct argument_block args = {mountpath, max_dive_data, xml_buffer, progress, force_download};
/* I'm sure there is some better interface for waiting on a thread in a UI main loop */
import_thread_done = 0;