summaryrefslogtreecommitdiffstats
path: root/libdivecomputer.c
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2013-01-22 16:54:09 -0800
committerGravatar Dirk Hohndel <dirk@hohndel.org>2013-01-22 20:15:01 -0800
commit20ad07d4ac82dbef90b3184a5eed9eec3cb8775f (patch)
tree1b4535cb3f8fae6f35991d627fe6379e4722ba6d /libdivecomputer.c
parent713c845e5a04a5ea5a41d1d8de3dc5c16b0e8df5 (diff)
downloadsubsurface-20ad07d4ac82dbef90b3184a5eed9eec3cb8775f.tar.gz
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@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'libdivecomputer.c')
-rw-r--r--libdivecomputer.c58
1 files changed, 52 insertions, 6 deletions
diff --git a/libdivecomputer.c b/libdivecomputer.c
index 47bfd5c58..2672fb72a 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"),