mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
Improve on divecomputer data handling
This simplifies the vendor/product fields into just a single "model" string for the dive computer, since we can't really validly ever use it any other way anyway. Also, add 'deviceid' and 'diveid' fields: they are just 32-bit hex values that are unique for that particular dive computer model. For libdivecomputer, they are basically the first word of the SHA1 of the data that libdivecomputer gives us. (Trying to expose it in some other way is insane - different dive computers use different models for the ID, so don't try to do some kind of serial number or something like that) For the Uemis Zurich, which doesn't use the libdivecomputer import, we currently only set the model name. The computer does have some kind of device ID string, and we could/should just do the same "SHA1 over the ID" to give it a unique ID, but the pseudo-xml parsing confuses me, so I'll let Dirk fix that up. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
1b861ba20e
commit
1ca1fe7994
7 changed files with 105 additions and 14 deletions
2
Makefile
2
Makefile
|
@ -125,7 +125,7 @@ ifneq ($(strip $(LIBXSLT)),)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LIBS = $(LIBXML2) $(LIBXSLT) $(LIBGTK) $(LIBGCONF2) $(LIBDIVECOMPUTER) $(EXTRALIBS) $(LIBZIP) -lpthread -lm
|
LIBS = $(LIBXML2) $(LIBXSLT) $(LIBGTK) $(LIBGCONF2) $(LIBDIVECOMPUTER) $(EXTRALIBS) $(LIBZIP) -lpthread -lm -lssl -lcrypto
|
||||||
|
|
||||||
MSGLANGS=$(notdir $(wildcard po/*po))
|
MSGLANGS=$(notdir $(wildcard po/*po))
|
||||||
MSGOBJS=$(addprefix share/locale/,$(MSGLANGS:.po=.UTF-8/LC_MESSAGES/subsurface.mo))
|
MSGOBJS=$(addprefix share/locale/,$(MSGLANGS:.po=.UTF-8/LC_MESSAGES/subsurface.mo))
|
||||||
|
|
18
dive.h
18
dive.h
|
@ -2,11 +2,13 @@
|
||||||
#define DIVE_H
|
#define DIVE_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some silly typedefs to make our units very explicit.
|
* Some silly typedefs to make our units very explicit.
|
||||||
|
@ -239,9 +241,23 @@ struct event {
|
||||||
char name[];
|
char name[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE! The deviceid and diveid are model-specific *hashes* of
|
||||||
|
* whatever device identification that model may have. Different
|
||||||
|
* dive computers will have different identifying data, it could
|
||||||
|
* be a firmware number or a serial ID (in either string or in
|
||||||
|
* numeric format), and we do not care.
|
||||||
|
*
|
||||||
|
* The only thing we care about is that subsurface will hash
|
||||||
|
* that information the same way. So then you can check the ID
|
||||||
|
* of a dive computer by comparing the hashes for equality.
|
||||||
|
*
|
||||||
|
* A deviceid or diveid of zero is assumed to be "no ID".
|
||||||
|
*/
|
||||||
struct divecomputer {
|
struct divecomputer {
|
||||||
timestamp_t when;
|
timestamp_t when;
|
||||||
const char *vendor, *product;
|
const char *model;
|
||||||
|
uint32_t deviceid, diveid;
|
||||||
int samples, alloc_samples;
|
int samples, alloc_samples;
|
||||||
struct sample *sample;
|
struct sample *sample;
|
||||||
struct event *events;
|
struct event *events;
|
||||||
|
|
|
@ -186,9 +186,7 @@ static inline int match_dc(struct divecomputer *a, struct divecomputer *b)
|
||||||
{
|
{
|
||||||
if (a->when != b->when)
|
if (a->when != b->when)
|
||||||
return 0;
|
return 0;
|
||||||
if (a->vendor && b->vendor && strcasecmp(a->vendor, b->vendor))
|
if (a->model && b->model && strcasecmp(a->model, b->model))
|
||||||
return 0;
|
|
||||||
if (a->product && b->product && strcasecmp(a->product, b->product))
|
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -226,6 +224,39 @@ static inline int year(int year)
|
||||||
return year;
|
return year;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like g_strdup_printf(), but without the stupid g_malloc/g_free confusion.
|
||||||
|
* And we limit the string to some arbitrary size.
|
||||||
|
*/
|
||||||
|
static char *str_printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char buf[80];
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsnprintf(buf, sizeof(buf)-1, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
buf[sizeof(buf)-1] = 0;
|
||||||
|
return strdup(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The dive ID for libdivecomputer dives is the first word of the
|
||||||
|
* SHA1 of the fingerprint, if it exists.
|
||||||
|
*
|
||||||
|
* NOTE! This is byte-order dependent, and I don't care.
|
||||||
|
*/
|
||||||
|
static uint32_t calculate_diveid(const unsigned char *fingerprint, unsigned int fsize)
|
||||||
|
{
|
||||||
|
uint32_t csum[5];
|
||||||
|
|
||||||
|
if (!fingerprint || !fsize)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
SHA1(fingerprint, fsize, (unsigned char *)csum);
|
||||||
|
return csum[0];
|
||||||
|
}
|
||||||
|
|
||||||
static int dive_cb(const unsigned char *data, unsigned int size,
|
static int dive_cb(const unsigned char *data, unsigned int size,
|
||||||
const unsigned char *fingerprint, unsigned int fsize,
|
const unsigned char *fingerprint, unsigned int fsize,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
|
@ -258,8 +289,9 @@ static int dive_cb(const unsigned char *data, unsigned int size,
|
||||||
dc_parser_destroy(parser);
|
dc_parser_destroy(parser);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
dive->dc.vendor = strdup(devdata->vendor);
|
dive->dc.model = str_printf("%s %s", devdata->vendor, devdata->product);
|
||||||
dive->dc.product = strdup(devdata->product);
|
dive->dc.deviceid = devdata->deviceid;
|
||||||
|
dive->dc.diveid = calculate_diveid(fingerprint, fsize);
|
||||||
|
|
||||||
tm.tm_year = dt.year;
|
tm.tm_year = dt.year;
|
||||||
tm.tm_mon = dt.month-1;
|
tm.tm_mon = dt.month-1;
|
||||||
|
@ -345,6 +377,25 @@ static dc_status_t import_device_data(dc_device_t *device, device_data_t *device
|
||||||
return dc_device_foreach(device, dive_cb, devicedata);
|
return dc_device_foreach(device, dive_cb, devicedata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The device ID for libdivecomputer devices is the first 32-bit word
|
||||||
|
* of the SHA1 hash of the model/firmware/serial numbers.
|
||||||
|
*
|
||||||
|
* NOTE! This is byte-order-dependent. And I can't find it in myself to
|
||||||
|
* care.
|
||||||
|
*/
|
||||||
|
static uint32_t calculate_sha1(unsigned int model, unsigned int firmware, unsigned int serial)
|
||||||
|
{
|
||||||
|
SHA_CTX ctx;
|
||||||
|
uint32_t csum[5];
|
||||||
|
|
||||||
|
SHA1_Init(&ctx);
|
||||||
|
SHA1_Update(&ctx, &model, sizeof(model));
|
||||||
|
SHA1_Update(&ctx, &firmware, sizeof(firmware));
|
||||||
|
SHA1_Update(&ctx, &serial, sizeof(serial));
|
||||||
|
SHA1_Final((unsigned char *)csum, &ctx);
|
||||||
|
return csum[0];
|
||||||
|
}
|
||||||
|
|
||||||
static void event_cb(dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
|
static void event_cb(dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
|
||||||
{
|
{
|
||||||
|
@ -367,6 +418,7 @@ static void event_cb(dc_device_t *device, dc_event_type_t event, const void *dat
|
||||||
devinfo->model, devinfo->model,
|
devinfo->model, devinfo->model,
|
||||||
devinfo->firmware, devinfo->firmware,
|
devinfo->firmware, devinfo->firmware,
|
||||||
devinfo->serial, devinfo->serial);
|
devinfo->serial, devinfo->serial);
|
||||||
|
devdata->deviceid = calculate_sha1(devinfo->model, devinfo->firmware, devinfo->serial);
|
||||||
break;
|
break;
|
||||||
case DC_EVENT_CLOCK:
|
case DC_EVENT_CLOCK:
|
||||||
dev_info(devdata, _("Event: systime=%"PRId64", devtime=%u\n"),
|
dev_info(devdata, _("Event: systime=%"PRId64", devtime=%u\n"),
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
typedef struct device_data_t {
|
typedef struct device_data_t {
|
||||||
dc_descriptor_t *descriptor;
|
dc_descriptor_t *descriptor;
|
||||||
const char *vendor, *product, *devname;
|
const char *vendor, *product, *devname;
|
||||||
|
unsigned int deviceid, diveid;
|
||||||
dc_device_t *device;
|
dc_device_t *device;
|
||||||
dc_context_t *context;
|
dc_context_t *context;
|
||||||
progressbar_t progress;
|
progressbar_t progress;
|
||||||
|
|
15
parse-xml.c
15
parse-xml.c
|
@ -523,6 +523,13 @@ static void get_index(char *buffer, void *_i)
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hex_value(char *buffer, void *_i)
|
||||||
|
{
|
||||||
|
uint32_t *i = _i;
|
||||||
|
*i = strtol(buffer, NULL, 16);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
static void get_tripflag(char *buffer, void *_tf)
|
static void get_tripflag(char *buffer, void *_tf)
|
||||||
{
|
{
|
||||||
tripflag_t *tf = _tf;
|
tripflag_t *tf = _tf;
|
||||||
|
@ -715,9 +722,11 @@ static void try_to_fill_dc(struct divecomputer *dc, const char *name, char *buf)
|
||||||
return;
|
return;
|
||||||
if (MATCH(".time", divetime, &dc->when))
|
if (MATCH(".time", divetime, &dc->when))
|
||||||
return;
|
return;
|
||||||
if (MATCH(".vendor", utf8_string, &dc->vendor))
|
if (MATCH(".model", utf8_string, &dc->model))
|
||||||
return;
|
return;
|
||||||
if (MATCH(".product", utf8_string, &dc->product))
|
if (MATCH(".deviceid", hex_value, &dc->deviceid))
|
||||||
|
return;
|
||||||
|
if (MATCH(".diveid", hex_value, &dc->diveid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nonmatch("divecomputer", name, buf);
|
nonmatch("divecomputer", name, buf);
|
||||||
|
@ -1333,7 +1342,7 @@ static void divecomputer_start(void)
|
||||||
dc = dc->next;
|
dc = dc->next;
|
||||||
|
|
||||||
/* Did we already fill that in? */
|
/* Did we already fill that in? */
|
||||||
if (dc->samples || dc->vendor || dc->product || dc->when) {
|
if (dc->samples || dc->model || dc->when) {
|
||||||
struct divecomputer *newdc = calloc(1, sizeof(*newdc));
|
struct divecomputer *newdc = calloc(1, sizeof(*newdc));
|
||||||
if (newdc) {
|
if (newdc) {
|
||||||
dc->next = newdc;
|
dc->next = newdc;
|
||||||
|
|
10
save-xml.c
10
save-xml.c
|
@ -351,10 +351,12 @@ static void save_dc(FILE *f, struct dive *dive, struct divecomputer *dc)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
fprintf(f, " <divecomputer");
|
fprintf(f, " <divecomputer");
|
||||||
if (dc->vendor)
|
if (dc->model)
|
||||||
show_utf8(f, dc->vendor, " vendor='", "'", 1);
|
show_utf8(f, dc->model, " model='", "'", 1);
|
||||||
if (dc->product)
|
if (dc->deviceid)
|
||||||
show_utf8(f, dc->product, " product='", "'", 1);
|
fprintf(f, " deviceid='%08x'", dc->deviceid);
|
||||||
|
if (dc->diveid)
|
||||||
|
fprintf(f, " diveid='%08x'", dc->diveid);
|
||||||
if (dc->when && dc->when != dive->when)
|
if (dc->when && dc->when != dive->when)
|
||||||
show_date(f, dc->when);
|
show_date(f, dc->when);
|
||||||
fprintf(f, ">\n");
|
fprintf(f, ">\n");
|
||||||
|
|
11
uemis.c
11
uemis.c
|
@ -199,6 +199,17 @@ void uemis_parse_divelog_binary(char *base64, void *datap) {
|
||||||
else
|
else
|
||||||
dive->salinity = 10000; /* grams per 10l fresh water */
|
dive->salinity = 10000; /* grams per 10l fresh water */
|
||||||
|
|
||||||
|
dc->model = strdup("Uemis Zurich");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME:
|
||||||
|
* - make the deive ID the first word of the SHA1 sum of the deviceid string
|
||||||
|
* - do we want to have a dive ID? Without one, we'll just use the dive date,
|
||||||
|
* which is likely fine.
|
||||||
|
*/
|
||||||
|
dc->deviceid = 0;
|
||||||
|
dc->diveid = 0;
|
||||||
|
|
||||||
/* dive template in use:
|
/* dive template in use:
|
||||||
0 = air
|
0 = air
|
||||||
1 = nitrox (B)
|
1 = nitrox (B)
|
||||||
|
|
Loading…
Reference in a new issue