summaryrefslogtreecommitdiffstats
path: root/dive.c
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2012-11-25 12:39:08 -0800
committerGravatar Dirk Hohndel <dirk@hohndel.org>2012-11-25 13:05:32 -0800
commit42240a83ff8e5cfb636dcc31aa2faf99bb19f417 (patch)
treebb0c0d1a432c19b9372eac358783cf22a2bfc55b /dive.c
parent7bfc8de55e0476b5604496839d920db597490a83 (diff)
downloadsubsurface-42240a83ff8e5cfb636dcc31aa2faf99bb19f417.tar.gz
Be much saner about merging dive computer data
Now that we have dive computer device ID fields etc, we can do a much better job of merging the dive computer data. The rule is - if we actually merge two disjoint dives (ie extended surface interval causing the dive computer to think the dive ended and turning two of those dives into one), find the *matching* dive computer from the other dive to combine with. - if we are merging dives at the same time, discard old-style data with no dive computer info (ie act like a re-download) - if we have new-style dive computers with identifiers, take them all. which seems to work fairly well. There's more tweaking to be done, but I think this is getting to the point where it largely works. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'dive.c')
-rw-r--r--dive.c143
1 files changed, 109 insertions, 34 deletions
diff --git a/dive.c b/dive.c
index 43cafacbf..faab9f259 100644
--- a/dive.c
+++ b/dive.c
@@ -1147,6 +1147,110 @@ static void remove_redundant_dc(struct divecomputer *dc)
} while (dc);
}
+static void clear_dc(struct divecomputer *dc)
+{
+ memset(dc, 0, sizeof(*dc));
+}
+
+static struct divecomputer *find_matching_computer(struct divecomputer *match, struct divecomputer *list)
+{
+ struct divecomputer *p;
+
+ while ((p = list) != NULL) {
+ list = list->next;
+
+ /* No dive computer model? That matches anything */
+ if (!match->model || !p->model)
+ break;
+
+ /* Otherwise at least the model names have to match */
+ if (strcasecmp(match->model, p->model))
+ continue;
+
+ /* No device ID? Match */
+ if (!match->deviceid || !p->deviceid)
+ break;
+
+ if (match->deviceid == p->deviceid)
+ break;
+ }
+ return p;
+}
+
+/*
+ * Join dive computers with a specific time offset between
+ * them.
+ *
+ * Use the dive computer ID's (or names, if ID's are missing)
+ * to match them up. If we find a matching dive computer, we
+ * merge them. If not, we just take the data from 'a'.
+ */
+static void interleave_dive_computers(struct divecomputer *res,
+ struct divecomputer *a, struct divecomputer *b, int offset)
+{
+ do {
+ struct divecomputer *match;
+
+ res->model = strdup(a->model);
+ res->deviceid = a->deviceid;
+ res->diveid = a->diveid;
+ res->next = NULL;
+
+ match = find_matching_computer(a, b);
+ if (match) {
+ merge_events(res, a, match, offset);
+ merge_samples(res, a, match, offset);
+ } else {
+ res->sample = a->sample;
+ res->samples = a->samples;
+ res->events = a->events;
+ a->sample = NULL;
+ a->samples = 0;
+ a->events = NULL;
+ }
+ a = a->next;
+ if (!a)
+ break;
+ res->next = calloc(1, sizeof(struct divecomputer));
+ res = res->next;
+ } while (res);
+}
+
+
+/*
+ * Join dive computer information.
+ *
+ * If we have old-style dive computer information (no model
+ * name etc), we will prefer a new-style one and just throw
+ * away the old. We're assuming it's a re-download.
+ *
+ * Otherwise, we'll just try to keep all the information.
+ */
+static void join_dive_computers(struct divecomputer *res, struct divecomputer *a, struct divecomputer *b)
+{
+ if (a->model && !b->model) {
+ *res = *a;
+ clear_dc(a);
+ return;
+ }
+ if (b->model && !a->model) {
+ *res = *b;
+ clear_dc(b);
+ return;
+ }
+
+ *res = *a;
+ clear_dc(a);
+ while (res->next)
+ res = res->next;
+
+ res->next = calloc(1, sizeof(*res));
+ *res->next = *b;
+ clear_dc(b);
+
+ remove_redundant_dc(res);
+}
+
struct dive *merge_dives(struct dive *a, struct dive *b, int offset, gboolean prefer_downloaded)
{
struct dive *res = alloc_dive();
@@ -1188,41 +1292,12 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, gboolean pr
* we free it - so make sure the source
* dive computer data is cleared out.
*/
- memset(&dl->dc, 0, sizeof(dl->dc));
- } else if (offset) {
- struct divecomputer *a_dc = &a->dc;
- struct divecomputer *b_dc = &b->dc;
- struct divecomputer *res_dc = &res->dc;
+ clear_dc(&dl->dc);
+ } else if (offset)
+ interleave_dive_computers(&res->dc, &a->dc, &b->dc, offset);
+ else
+ join_dive_computers(&res->dc, &a->dc, &b->dc);
- /*
- * FIXME! We should try to match these things up some way,
- * now we just depend on the merged dives having the same
- * dive computers in the same order!
- */
- for (;;) {
- merge_events(res_dc, a_dc, b_dc, offset);
- merge_samples(res_dc, a_dc, b_dc, offset);
- a_dc = a_dc->next;
- b_dc = b_dc->next;
- if (!a_dc || !b_dc)
- break;
- res_dc->next = calloc(1, sizeof(*res_dc));
- res_dc = res_dc->next;
- if (!res_dc)
- break;
- }
- } else {
- struct divecomputer *dc;
- res->dc = a->dc;
- memset(&a->dc, 0, sizeof(a->dc));
- dc = &res->dc;
- while (dc->next)
- dc = dc->next;
- dc->next = calloc(1, sizeof(*dc));
- *dc->next = b->dc;
- memset(&b->dc, 0,sizeof(b->dc));
- remove_redundant_dc(&res->dc);
- }
fixup_dive(res);
return res;
}