[PATCH 1/2] Fix suunto serial number confusion in libdivecomputer

Linus Torvalds torvalds at linux-foundation.org
Tue Jan 22 17:04:39 PST 2013


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Tue, 22 Jan 2013 16:54:09 -0800
Subject: [PATCH 1/2] Fix suunto serial number confusion in libdivecomputer

libdivecomputer has started giving the Suunto serial numbers in a
different format, which means that we have the same device with two
different serial numbers, and then we need two different ways of turning
the numerical entity into a string.

Look at the number pattern to see figure out which version of the format
it is that libdivecomputer is reporting, and turn it back into the
original format so that we can reliably give the right string for it.
This also mean sthat the device ID stays the same regardless of
libdivecomputer version.

Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
---

Ugh. This is due to the recent changes to libdivecomputer that make it 
calculate Suunto serial numbers differently. This makes us agnostic wrt 
the libdivecomputer version.

 libdivecomputer.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 52 insertions(+), 6 deletions(-)

diff --git a/libdivecomputer.c b/libdivecomputer.c
index 47bfd5c58539..2672fb72a84d 100644
--- a/libdivecomputer.c
+++ b/libdivecomputer.c
@@ -527,15 +527,58 @@ static uint32_t calculate_sha1(unsigned int model, unsigned int firmware, unsign
 	return csum[0];
 }
 
-static void fixup_suunto_versions(device_data_t *devdata, const dc_event_devinfo_t *devinfo)
+/*
+ * libdivecomputer has returned two different serial numbers for the
+ * same device in different versions. First it used to just do the four
+ * bytes as one 32-bit number, then it turned it into a decimal number
+ * with each byte giving two digits (0-99).
+ *
+ * The only way we can tell is by looking at the format of the number,
+ * so we'll just fix it to the first format.
+ */
+static unsigned int undo_libdivecomputer_suunto_nr_changes(unsigned int serial)
+{
+	unsigned char b0, b1, b2, b3;
+
+	/*
+	 * The second format will never have more than 8 decimal
+	 * digits, so do a cheap check first
+	 */
+	if (serial >= 100000000)
+		return serial;
+
+	/* The original format seems to be four bytes of values 00-99 */
+	b0 = (serial >> 0) & 0xff;
+	b1 = (serial >> 8) & 0xff;
+	b2 = (serial >> 16) & 0xff;
+	b3 = (serial >> 24) & 0xff;
+
+	/* Looks like an old-style libdivecomputer serial number */
+	if ((b0 < 100) && (b1 < 100) && (b2 < 100) && (b3 < 100))
+		return serial;
+
+	/* Nope, it was converted. */
+	b0 = serial % 100; serial /= 100;
+	b1 = serial % 100; serial /= 100;
+	b2 = serial % 100; serial /= 100;
+	b3 = serial % 100; serial /= 100;
+
+	serial = b0 + (b1 << 8) + (b2 << 16) + (b3 << 24);
+	return serial;
+}
+
+static unsigned int fixup_suunto_versions(device_data_t *devdata, const dc_event_devinfo_t *devinfo)
 {
 	struct device_info *info;
+	unsigned int serial = devinfo->serial;
+
+	serial = undo_libdivecomputer_suunto_nr_changes(serial);
 
 	info = create_device_info(devdata->model, devdata->deviceid);
 	if (!info)
-		return;
+		return serial;
 
-	if (!info->serial_nr && devinfo->serial) {
+	if (!info->serial_nr && serial) {
 		char serial_nr[13];
 
 		snprintf(serial_nr, sizeof(serial_nr), "%02d%02d%02d%02d",
@@ -554,6 +597,7 @@ static void fixup_suunto_versions(device_data_t *devdata, const dc_event_devinfo
 			(devinfo->firmware >> 0)  & 0xff);
 		info->firmware = strdup(firmware);
 	}
+	return serial;
 }
 
 static void event_cb(dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
@@ -562,6 +606,7 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
 	const dc_event_devinfo_t *devinfo = data;
 	const dc_event_clock_t *clock = data;
 	device_data_t *devdata = userdata;
+	unsigned int serial;
 
 	switch (event) {
 	case DC_EVENT_WAITING:
@@ -577,14 +622,15 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
 			devinfo->model, devinfo->model,
 			devinfo->firmware, devinfo->firmware,
 			devinfo->serial, devinfo->serial);
-		devdata->deviceid = calculate_sha1(devinfo->model, devinfo->firmware, devinfo->serial);
-
 		/*
 		 * libdivecomputer doesn't give serial numbers in the proper string form,
 		 * so we have to see if we can do some vendor-specific munging.
 		 */
+		serial = devinfo->serial;
 		if (!strcmp(devdata->vendor, "Suunto"))
-			fixup_suunto_versions(devdata, devinfo);
+			serial = fixup_suunto_versions(devdata, devinfo);
+		devdata->deviceid = calculate_sha1(devinfo->model, devinfo->firmware, serial);
+
 		break;
 	case DC_EVENT_CLOCK:
 			dev_info(devdata, _("Event: systime=%"PRId64", devtime=%u\n"),
-- 
1.8.1.1.271.g02f55e6



More information about the subsurface mailing list