[PATCH 7/6] Be much saner about merging dive computer data

Linus Torvalds torvalds at linux-foundation.org
Sun Nov 25 12:52:18 PST 2012


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Sun, 25 Nov 2012 12:39:08 -0800
Subject: [PATCH 7/6] 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 at linux-foundation.org>
---

Ok, so this actually uses the device ID field, and seems to work ok. I'm 
not going to claim that it is *hugely* tested, but it's absolutely a step 
in the right direction.

So with this, I can have two dives that use two different dive computers, 
and merge them, and it merges those dive computers separately (so the 
resulting dive also has two separate dive computer entries, correctly 
matched up and with the proper offset merge of the original two pairs of 
dual dive computers).

This is obviously on top of my previous six-patch series.

 dive.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 109 insertions(+), 34 deletions(-)

diff --git a/dive.c b/dive.c
index 43cafacbf31a..faab9f259f34 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;
 }
-- 
1.8.0.dirty



More information about the subsurface mailing list