summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2012-11-28 17:11:19 -0700
committerGravatar Dirk Hohndel <dirk@hohndel.org>2012-11-30 13:41:58 -0700
commit4c4dff76835a94c571f97dd0730168738501524e (patch)
tree9947139f905fb2b016b465f536483d24f5ec8b0e
parenta79b74ed36f6a52db947ff24761a3fd331c75cdc (diff)
downloadsubsurface-4c4dff76835a94c571f97dd0730168738501524e.tar.gz
Convert Uemis downloader to directly create dives
The initial downloader reused the XML parsing of SDA files that was implemented early in order to support the information extracted from the SDA with the java applet. But creating this intermediary XML file and handing it off to the XML import function always seemed like an ugly way to do things. This became even more obvious when adding more features to the Uemis downloader. This commit completely changes the downloader to instead create dives and record them directly. This also adds support for divespots (which are stored in a seperate database that needs to be queried after the divelog and dive entries have been combined - the Uemis firmware clearly was written by monkeys on crack - oh wait: I'm trusting these same people to get the deco right?). This commit leaves the SDA import capability in the XML parser intact. I'll remove that later. Because of this it actually adds a few lines of code, but the overall change will be a substantial code deletion. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r--display-gtk.h3
-rw-r--r--dive.h10
-rw-r--r--gtk-gui.c18
-rw-r--r--uemis-downloader.c500
-rw-r--r--uemis.c77
-rw-r--r--uemis.h4
6 files changed, 316 insertions, 296 deletions
diff --git a/display-gtk.h b/display-gtk.h
index b524f5e50..f88d96633 100644
--- a/display-gtk.h
+++ b/display-gtk.h
@@ -113,7 +113,6 @@ typedef gint (*sort_func_t)(GtkTreeModel *model,
extern GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title,
data_func_t data_func, unsigned int flags);
-GError *uemis_download(const char *path, char **xml_buffer,
- progressbar_t *progress, GtkDialog *dialog, gboolean force_download);
+GError *uemis_download(const char *path, progressbar_t *progress, GtkDialog *dialog, gboolean force_download);
#endif
diff --git a/dive.h b/dive.h
index 4eb81752f..e03399ec1 100644
--- a/dive.h
+++ b/dive.h
@@ -405,6 +405,16 @@ static inline struct dive *get_dive(int nr)
return dive_table.dives[nr];
}
+static inline struct dive *get_dive_by_diveid(int diveid, int deviceid)
+{
+ int i;
+ for (i = 0; i < dive_table.nr; i++)
+ if (dive_table.dives[i]->dc.diveid == diveid &&
+ dive_table.dives[i]->dc.deviceid == deviceid)
+ return dive_table.dives[i];
+ return NULL;
+}
+
/*
* Iterate over each dive, with the first parameter being the index
* iterator variable, and the second one being the dive one.
diff --git a/gtk-gui.c b/gtk-gui.c
index 81f93ca1e..6f08255bd 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -1644,22 +1644,6 @@ void import_files(GtkWidget *w, gpointer data)
restore_tree_state();
}
-static GError *setup_uemis_import(device_data_t *data)
-{
- GError *error = NULL;
- char *buf = NULL;
-
- error = uemis_download(data->devname, &buf, &data->progress, data->dialog, data->force_download);
- if (buf && strlen(buf) > 1) {
-#if UEMIS_DEBUG > 3
- fprintf(debugfile, "xml buffer \"%s\"\n\n", buf);
-#endif
- parse_xml_buffer("Uemis Download", buf, strlen(buf), TRUE, &error);
- mark_divelist_changed(TRUE);
- }
- return error;
-}
-
static GtkWidget *import_dive_computer(device_data_t *data, GtkDialog *dialog)
{
GError *error;
@@ -1667,7 +1651,7 @@ static GtkWidget *import_dive_computer(device_data_t *data, GtkDialog *dialog)
/* HACK to simply include the Uemis Zurich in the list */
if (! strcmp(data->vendor, "Uemis") && ! strcmp(data->product, "Zurich")) {
- error = setup_uemis_import(data);
+ error = uemis_download(data->devname, &data->progress, data->dialog, data->force_download);
} else {
error = do_import(data);
}
diff --git a/uemis-downloader.c b/uemis-downloader.c
index 9577c48cc..c80b1e929 100644
--- a/uemis-downloader.c
+++ b/uemis-downloader.c
@@ -44,11 +44,12 @@ static int mbuf_size = 0;
struct argument_block {
const char *mountpath;
- char **xml_buffer;
progressbar_t *progress;
gboolean force_download;
};
+static int nr_divespots = 0;
+
static int import_thread_done = 0, import_thread_cancelled;
static const char *progress_bar_text = "";
static double progress_bar_fraction = 0.0;
@@ -66,6 +67,72 @@ static GError *error(const char *fmt, ...)
return error;
}
+/* helper function to parse the Uemis data structures */
+static void uemis_ts(char *buffer, void *_when)
+{
+ struct tm tm;
+ timestamp_t *when = _when;
+
+ memset(&tm, 0, sizeof(tm));
+ sscanf(buffer,"%d-%d-%dT%d:%d:%d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+ tm.tm_mon -= 1;
+ tm.tm_year -= 1900;
+ *when = utc_mktime(&tm);
+}
+
+/* float minutes */
+static void uemis_duration(char *buffer, duration_t *duration)
+{
+ duration->seconds = atof(buffer) * 60 + 0.5;
+}
+
+/* int cm */
+static void uemis_depth(char *buffer, depth_t *depth)
+{
+ depth->mm = atoi(buffer) * 10;
+}
+
+static void uemis_get_index(char *buffer, int *idx)
+{
+ *idx = atoi(buffer);
+}
+
+/* space separated */
+static void uemis_add_string(char *buffer, char **text)
+{
+ if (!buffer || !*buffer)
+ return;
+ if (!*text) {
+ *text = strdup(buffer);
+ } else {
+ char *buf = malloc(strlen(buffer) + strlen(*text) + 2);
+ strcpy(buf, *text);
+ strcat(buf, " ");
+ strcat(buf, buffer);
+ free(*text);
+ *text = buf;
+ }
+}
+
+/* still unclear if it ever reports lbs */
+static void uemis_get_weight(char *buffer, weightsystem_t *weight, int diveid)
+{
+ weight->weight.grams = uemis_get_weight_unit(diveid) ?
+ lbs_to_grams(atof(buffer)) : atof(buffer) * 1000;
+ weight->description = strdup("unknown");
+}
+
+static struct dive *uemis_start_dive(int deviceid)
+{
+ struct dive *dive = alloc_dive();
+ dive->downloaded = TRUE;
+ dive->dc.model = strdup("Uemis Zurich");
+ dive->dc.deviceid = deviceid;
+ return dive;
+}
+
/* send text to the importer progress bar */
static void uemis_info(const char *fmt, ...)
{
@@ -136,16 +203,7 @@ static gboolean uemis_init(const char *path)
close (reqtxt_file);
/* It would be nice if we could simply go back to the first set of
- * ANS files. Something like the below - unfortunately this is known
- * to fail - more information from Uemis is needed here.
- * Without code like this it is very easy when downloading large amounts
- * of dives to run out of space on the dive computer - which can only
- * be fixed by unmounting and rebooting the DC
- * reqtxt_file = g_open(reqtxt_path, O_RDWR | O_CREAT | O_TRUNC, 0666);
- * write(reqtxt_file, "n0001", 5);
- * close(reqtxt_file);
- * filenr = 1;
- */
+ * ANS files. But with a FAT filesystem that isn't possible */
ans_path = g_build_filename(path, "ANS", NULL);
number_of_files = number_of_file(ans_path);
g_free(ans_path);
@@ -246,184 +304,6 @@ static void buffer_add(char **buffer, int *buffer_size, char *buf)
#endif
}
-#define PATTERN1 "<val key=\"%s\">%s"
-#define PATTERN2 "\n<int>%d</int>"
-static gboolean get_tag_int_value(char *buffer, char *tag, int *value, char **next_ptr)
-{
- char *ptr = buffer;
- int len;
- char *format;
-
- if (!ptr || !value)
- return FALSE;
- len = strlen(PATTERN1) + strlen(PATTERN2) + strlen(tag);
- format = malloc(len);
- snprintf(format, len, PATTERN1, tag, "");
- ptr = strstr(ptr, format);
- if (!ptr)
- return FALSE;
- snprintf(format, len, PATTERN1, tag, PATTERN2);
- if (sscanf(ptr, format, value) != 1)
- return FALSE;
- if (next_ptr)
- *next_ptr = ptr + 1;
- return TRUE;
-}
-
-static gboolean get_tag_string_value(char *buffer, char *tag, char **value)
-{
- char *eptr, *ptr = buffer;
- int len;
- char *format;
-
- if (!ptr || !value)
- return FALSE;
- len = strlen(PATTERN1) + strlen(tag);
- format = malloc(len);
- snprintf(format, len, PATTERN1, tag, "");
- ptr = strstr(ptr, format);
- if (!ptr)
- return FALSE;
- eptr = strstr(ptr, "</string>");
- if (!eptr)
- return FALSE;
- *eptr = '\0';
- *value = strdup(ptr + strlen(format) + 9);
- *eptr = '<';
- return TRUE;
-}
-
-#define PATTERN4 "\n<float>%lf</float>"
-static gboolean get_tag_double_value(char *buffer, char *tag, double *value, char **next_ptr)
-{
- char *ptr = buffer;
- int len;
- char *format;
-
- if (!ptr || !value)
- return FALSE;
- len = strlen(PATTERN1) + strlen(PATTERN4) + strlen(tag);
- format = malloc(len);
- snprintf(format, len, PATTERN1, tag, "");
- ptr = strstr(ptr, format);
- if (!ptr)
- return FALSE;
- snprintf(format, len, PATTERN1, tag, PATTERN4);
- if (sscanf(ptr, format, value) != 1)
- return FALSE;
- if (next_ptr)
- *next_ptr = ptr + 1;
- return TRUE;
-}
-
-static char *get_xml_for_int(char *buf, char *tag)
-{
- int value;
- char *xml;
- if (get_tag_int_value(buf, tag, &value, NULL)) {
- int len = 20 + 2 * strlen(tag);
- xml = malloc(len);
- snprintf(xml, len, "<%s>%d</%s>\n", tag, value, tag);
- }
- return xml;
-}
-
-static const char *suit[] = { "", "wetsuit", "semidry", "drysuit" };
-static const char *suit_type[] = { "", "shorty", "vest", "long john", "jacket", "full suit", "2 pcs full suit" };
-static const char *suit_thickness[] = { "", "0.5-2mm", "2-3mm", "3-5mm", "5-7mm", "8mm+", "membrane" };
-static char *convert_dive_details(char *buf, uint8_t *hdr)
-{
- char *conv_buffer = NULL;
- int conv_size = 0;
- char *ptr, *eptr;
- double doublevalue;
- double weight;
- char *stringvalue;
- char textbuf[200];
- int suit_idx, suit_type_idx, suit_thickness_idx;
-
- /* we want to throw away what is duplicate and clean up and
- * parse the userful entries */
- ptr = strstr(buf, "<val key=\"logfilenr\">");
- if (!ptr)
- return NULL;
- eptr = strstr(ptr + 1, "<val");
- *eptr = '\0';
- buffer_add(&conv_buffer, &conv_size, ptr);
- *eptr = '<';
- buffer_add(&conv_buffer, &conv_size, get_xml_for_int(eptr, "altitude"));
- buffer_add(&conv_buffer, &conv_size, get_xml_for_int(eptr, "decoindex"));
- buffer_add(&conv_buffer, &conv_size, get_xml_for_int(eptr, "consumption"));
- if (get_tag_double_value(eptr, "f32Weight", &doublevalue, NULL)) {
- weight = hdr[24] ? lbs_to_grams(doublevalue) / 1000.0 : doublevalue;
- snprintf(textbuf, sizeof(textbuf),
- "<weightsystem weight='%.3lf' description='unknown' />\n", weight);
- buffer_add(&conv_buffer, &conv_size, textbuf);
- }
- if (get_tag_string_value(eptr, "notes", &stringvalue)) {
- buffer_add(&conv_buffer, &conv_size, "<notes>");
- buffer_add(&conv_buffer, &conv_size, stringvalue);
- buffer_add(&conv_buffer, &conv_size, "</notes>\n");
- }
- if (get_tag_int_value(eptr, "u8DiveSuit", &suit_idx, NULL) &&
- get_tag_int_value(eptr, "u8DiveSuitType", &suit_type_idx, NULL) &&
- get_tag_int_value(eptr, "u8SuitThickness", &suit_thickness_idx, NULL) &&
- suit_idx >= 0 && suit_idx < sizeof(suit) &&
- suit_type_idx >= 0 && suit_type_idx < sizeof(suit_type) &&
- suit_thickness_idx >= 0 && suit_thickness_idx < sizeof(suit_thickness)) {
- snprintf(textbuf, sizeof(textbuf), "<suit>%s %s %s</suit>\n",
- suit[suit_idx], suit_type[suit_type_idx], suit_thickness[suit_thickness_idx]);
- buffer_add(&conv_buffer, &conv_size, textbuf);
- }
- return conv_buffer;
-}
-
-/* this is more interesting - insert the additional data in the dive
- * it belongs to - no idea why Uemis splits out the dive data in this
- * odd way, but we have to re-assemble it here */
-static void buffer_insert(char **buffer, int *buffer_size, char *buf)
-{
- char *ptr, *endptr, *b64, *cbuf;
- int obj_dive;
- int obj_log;
- int offset, len;
- uint8_t hdr[27];
-
- /* since we want to insert into the buffer... if there's
- * nothing there, this makes absolutely no sense so just
- * bail */
- if (!buf || !*buffer)
- return;
- endptr = *buffer + strlen(*buffer);
- /* now figure out the object_id of buf and find the matching
- * spot in buffer */
- if (!get_tag_int_value(buf, "logfilenr", &obj_dive, NULL))
- return;
- ptr = *buffer;
- while (ptr < endptr) {
- if (!get_tag_int_value(ptr, "object_id", &obj_log, &ptr))
- return;
- if (obj_dive == obj_log)
- break;
- }
- ptr = strstr(ptr, "<val key=\"file_content\">");
- if (!ptr)
- return;
- /* this is where the base64 data starts; we need to extract
- * some info from that in order to make sense of the data in
- * the dive info */
- b64 = strstr(ptr, "<bin>") + 5;
- decode(b64, hdr, 36);
- cbuf = convert_dive_details(buf, hdr);
- offset = ptr - *buffer;
- len = strlen(cbuf);
- *buffer_size += len;
- *buffer = realloc(*buffer, *buffer_size);
- ptr = *buffer + offset;
- memmove(ptr + len, ptr, strlen(*buffer) - offset + 1);
- memmove(ptr, cbuf, len);
-}
-
/* are there more ANS files we can check? */
static gboolean next_file(int max)
{
@@ -436,12 +316,12 @@ static gboolean next_file(int max)
/* ultra-simplistic; it doesn't deal with the case when the object_id is
* split across two chunks. It also doesn't deal with the discrepancy between
* object_id and dive number as understood by the dive computer */
-static void show_progress(char *buf)
+static void show_progress(char *buf, char *what)
{
char *object;
object = strstr(buf, "object_id");
if (object) {
- /* let the user know which dive we are working on */
+ /* let the user know what we are working on */
char tmp[10];
char *p = object + 14;
char *t = tmp;
@@ -450,7 +330,7 @@ static void show_progress(char *buf)
while (*p != '{' && t < tmp + 9)
*t++ = *p++;
*t = '\0';
- uemis_info(_("Reading dive %s"), tmp);
+ uemis_info(_("Reading %s %s"), what, tmp);
}
}
}
@@ -470,6 +350,7 @@ static gboolean uemis_get_answer(const char *path, char *request, int n_param_in
char sb[BUFLEN];
char fl[13];
char tmp[101];
+ char *what = _("data");
gboolean searching = TRUE;
gboolean assembling_mbuf = FALSE;
gboolean ismulti = FALSE;
@@ -485,9 +366,16 @@ static gboolean uemis_get_answer(const char *path, char *request, int n_param_in
str_append_with_delim(sb, request);
for (i = 0; i < n_param_in; i++)
str_append_with_delim(sb, param_buff[i]);
- if (! strcmp(request, "getDivelogs") || ! strcmp(request, "getDeviceData") || ! strcmp(request, "getDirectory")) {
+ if (! strcmp(request, "getDivelogs") || ! strcmp(request, "getDeviceData") || ! strcmp(request, "getDirectory") ||
+ ! strcmp(request, "getDivespot") || strcmp(request, "getDive")) {
answer_in_mbuf = TRUE;
str_append_with_delim(sb, "");
+ if (! strcmp(request, "getDivelogs"))
+ what = _("divelog entry id");
+ else if (!strcmp(request, "getDivespot"))
+ what = _("divespot data id");
+ else if (!strcmp(request, "getDive"))
+ what = _("additional data dive id");
}
str_append_with_delim(sb, "");
file_length = strlen(sb);
@@ -567,9 +455,9 @@ static gboolean uemis_get_answer(const char *path, char *request, int n_param_in
char *buf = malloc(size - 2);
lseek(ans_file, 3, SEEK_CUR);
read(ans_file, buf, size - 3);
- buf[size -3 ] = '\0';
+ buf[size - 3] = '\0';
buffer_add(&mbuf, &mbuf_size, buf);
- show_progress(buf);
+ show_progress(buf, what);
free(buf);
param_buff[3]++;
}
@@ -592,6 +480,8 @@ static gboolean uemis_get_answer(const char *path, char *request, int n_param_in
lseek(ans_file, 3, SEEK_CUR);
read(ans_file, buf, size - 3);
buf[size - 3] = '\0';
+ buffer_add(&mbuf, &mbuf_size, buf);
+ show_progress(buf, what);
#if UEMIS_DEBUG > 3
fprintf(debugfile, "::r %s \"%s\"\n", ans_path, buf);
#endif
@@ -618,22 +508,105 @@ static gboolean uemis_get_answer(const char *path, char *request, int n_param_in
return found_answer;
}
-/* Turn what we get from the dive computer into something that we can
- * pass to the parse_xml function. If this is a divelog, then the
- * last 'object_id' that we see is returned as our current
- * approximation of a last dive number */
-static char *process_raw_buffer(char *inbuf, char **max_divenr)
+static void parse_divespot(char *buf)
+{
+ char *bp = buf + 1;
+ char *tp = next_token(&bp);
+ char *tag, *type, *val;
+ char locationstring[255] = "";
+ int divespot, len;
+ double latitude, longitude;
+
+
+ if (strcmp(tp, "divespot"))
+ return;
+ do
+ tag = next_token(&bp);
+ while (*tag && strcmp(tag, "object_id"));
+ if (! *tag)
+ return;
+ type = next_token(&bp);
+ val = next_token(&bp);
+ divespot = atoi(val);
+ do {
+ tag = next_token(&bp);
+ type = next_token(&bp);
+ val = next_token(&bp);
+ if (!strcmp(type, "string") && *val && strcmp(val, " ")) {
+ len = strlen(locationstring);
+ snprintf(locationstring + len, sizeof(locationstring) - len,
+ "%s%s", len ? ", " : "", val);
+ } else if (!strcmp(type, "float")) {
+ if (!strcmp(tag, "longitude"))
+ longitude = atof(val);
+ else if (!strcmp(tag, "latitude"))
+ latitude = atof(val);
+ }
+ } while (tag && *tag);
+ uemis_set_divelocation(divespot, strdup(locationstring), latitude, longitude);
+}
+
+static void track_divespot(char *val, int diveid, char **location, double *latitude, double *longitude)
+{
+ int id = atoi(val);
+ if (id >= 0 && id > nr_divespots)
+ nr_divespots = id;
+ uemis_mark_divelocation(diveid, id, location, latitude, longitude);
+ return;
+}
+
+static char *suit[] = { "", "wetsuit", "semidry", "drysuit" };
+static char *suit_type[] = { "", "shorty", "vest", "long john", "jacket", "full suit", "2 pcs full suit" };
+static char *suit_thickness[] = { "", "0.5-2mm", "2-3mm", "3-5mm", "5-7mm", "8mm+", "membrane" };
+
+static void parse_tag(struct dive *dive, char *tag, char *val)
+{
+ /* we can ignore computer_id, water and gas as those are redundant
+ * with the binary data and would just get overwritten */
+ if (! strcmp(tag, "date"))
+ uemis_ts(val, &dive->when);
+ else if (!strcmp(tag, "duration"))
+ uemis_duration(val, &dive->duration);
+ else if (!strcmp(tag, "depth"))
+ uemis_depth(val, &dive->maxdepth);
+ else if (!strcmp(tag, "file_content"))
+ uemis_parse_divelog_binary(val, dive);
+ else if (!strcmp(tag, "altitude"))
+ uemis_get_index(val, &dive->surface_pressure.mbar);
+ else if (!strcmp(tag, "f32Weight"))
+ uemis_get_weight(val, &dive->weightsystem[0], dive->dc.diveid);
+ else if (!strcmp(tag, "notes"))
+ uemis_add_string(val, &dive->notes);
+ else if (!strcmp(tag, "u8DiveSuit"))
+ uemis_add_string(suit[atoi(val)], &dive->suit);
+ else if (!strcmp(tag, "u8DiveSuitType"))
+ uemis_add_string(suit_type[atoi(val)], &dive->suit);
+ else if (!strcmp(tag, "u8SuitThickness"))
+ uemis_add_string(suit_thickness[atoi(val)], &dive->suit);
+}
+
+/* This function is called for both divelog and dive information that we get
+ * from the SDA (what an insane design, btw). The object_id in the divelog
+ * matches the logfilenr in the dive information (which has its own, often
+ * different object_id) - we use this as the diveid.
+ * We create the dive when parsing the divelog and then later, when we parse
+ * the dive information we locate the already created dive via its diveid.
+ * Most things just get parsed and converted into our internal data structures,
+ * but the dive location API is even more crazy. We just get an id that is an
+ * index into yet another data store that we read out later. In order to
+ * correctly populate the location and gps data from that we need to remember
+ * the adresses of those fields for every dive that references the divespot. */
+static void process_raw_buffer(int deviceid, char *inbuf, char **max_divenr)
{
char *buf = strdup(inbuf);
char *tp, *bp, *tag, *type, *val;
gboolean done = FALSE;
int inbuflen = strlen(inbuf);
char *endptr = buf + inbuflen;
- char *conv_buffer = NULL;
- int conv_buffer_size = 0;
gboolean log = FALSE;
char *sections[10];
int s, nr_sections = 0;
+ struct dive *dive = NULL;
bp = buf + 1;
tp = next_token(&bp);
@@ -642,23 +615,19 @@ static char *process_raw_buffer(char *inbuf, char **max_divenr)
log = TRUE;
tp = next_token(&bp);
if (strcmp(tp,"1.0") != 0)
- return NULL;
+ return;
} else if (strcmp(tp, "dive") == 0) {
/* this is dive detail */
tp = next_token(&bp);
if (strcmp(tp,"1.0") != 0)
- return NULL;
+ return;
} else {
/* don't understand the buffer */
- return NULL;
+ return;
}
if (log)
- buffer_add(&conv_buffer, &conv_buffer_size,
- "<dive type=\"uemis\" ref=\"divelog\" version=\"1.0\">\n");
+ dive = uemis_start_dive(deviceid);
while (!done) {
- char *tmp;
- int tmp_size;
-
/* the valid buffer ends with a series of delimiters */
if (bp >= endptr - 2 || !strcmp(bp, "{{"))
break;
@@ -687,36 +656,38 @@ static char *process_raw_buffer(char *inbuf, char **max_divenr)
if (log && ! strcmp(tag, "object_id")) {
free(*max_divenr);
*max_divenr = strdup(val);
+ dive->dc.diveid = atoi(val);
+ } else if (!log && ! strcmp(tag, "logfilenr")) {
+ /* this one tells us which dive we are adding data to */
+ dive = get_dive_by_diveid(atoi(val), deviceid);
+ } else if (!log && dive && ! strcmp(tag, "divespot_id")) {
+ track_divespot(val, dive->dc.diveid, &dive->location, &dive->latitude, &dive->longitude);
+ } else if (dive) {
+ parse_tag(dive, tag, val);
}
- if (! strcmp(tag, "file_content")) {
- tmp_size = 45 + strlen(tag) + strlen(val);
+ if (log && ! strcmp(tag, "file_content"))
done = TRUE;
- } else {
- tmp_size = 28 + strlen(tag) + 2 * strlen(type) + strlen(val);
- }
- tmp = malloc(tmp_size);
- snprintf(tmp, tmp_size, "<val key=\"%s\">\n<%s>%s</%s>\n</val>\n",
- tag, type, val, type);
- buffer_add(&conv_buffer, &conv_buffer_size, tmp);
- free(tmp);
/* done with one dive (got the file_content tag), but there could be more:
* a '{' indicates the end of the record - but we need to see another "{{"
* later in the buffer to know that the next record is complete (it could
* be a short read because of some error */
if (done && ++bp < endptr && *bp != '{' && strstr(bp, "{{")) {
done = FALSE;
- buffer_add(&conv_buffer, &conv_buffer_size,
- "</dive>\n<dive type=\"uemis\" ref=\"divelog\" version=\"1.0\">\n");
+ record_dive(dive);
+ mark_divelist_changed(TRUE);
+ dive = uemis_start_dive(deviceid);
}
}
if (log) {
- buffer_add(&conv_buffer, &conv_buffer_size, "</dive>\n");
+ if (dive->dc.diveid) {
+ record_dive(dive);
+ mark_divelist_changed(TRUE);
+ } else { /* partial dive */
+ free(dive);
+ }
}
free(buf);
-#if UEMIS_DEBUG > 3
- fprintf(debugfile,"converted to \"%s\"\n", conv_buffer);
-#endif
- return strdup(conv_buffer);
+ return;
}
static char *get_divenr(char *deviceidstr)
@@ -724,38 +695,34 @@ static char *get_divenr(char *deviceidstr)
int deviceid, i, maxdiveid = 0;
char divenr[10];
- if (sscanf(deviceidstr, "%d", &deviceid) != 1)
- return "0";
+ deviceid = atoi(deviceidstr);
for (i = 0; i < dive_table.nr; i++) {
struct divecomputer *dc = &dive_table.dives[i]->dc;
if (dc->deviceid == deviceid && dc->diveid > maxdiveid)
maxdiveid = dc->diveid;
}
snprintf(divenr, 10, "%d", maxdiveid);
-
return strdup(divenr);
}
static char *do_uemis_download(struct argument_block *args)
{
const char *mountpath = args->mountpath;
- char **xml_buffer = args->xml_buffer;
- int xml_buffer_size;
char *newmax = NULL;
- int start, end, i;
+ int start, end, i, deviceidnr;
char objectid[10];
char *deviceid = NULL;
char *result = NULL;
char *endptr;
gboolean success;
- buffer_add(xml_buffer, &xml_buffer_size, "<dives type='uemis'><string></string>\n<list>\n");
uemis_info("Init Communication");
if (! uemis_init(mountpath))
return _("Uemis init failed");
if (! uemis_get_answer(mountpath, "getDeviceId", 0, 1, &result))
goto bail;
deviceid = strdup(param_buff[0]);
+ deviceidnr = atoi(deviceid);
/* the answer from the DeviceId call becomes the input parameter for getDeviceData */
if (! uemis_get_answer(mountpath, "getDeviceData", 1, 0, &result))
goto bail;
@@ -769,35 +736,25 @@ static char *do_uemis_download(struct argument_block *args)
if (import_thread_cancelled)
goto bail;
param_buff[1] = "notempty";
- /* if we have an empty divelist then the user will almost
- * certainly want to start downloading from the first dive on
- * the Uemis; otherwise check which was the last dive
- * downloaded */
+ /* if we have an empty divelist or force it, then we start downloading from the
+ * first dive on the Uemis; otherwise check which was the last dive downloaded */
if (!args->force_download && dive_table.nr > 0)
newmax = get_divenr(deviceid);
else
newmax = strdup("0");
-
- if (sscanf(newmax, "%d", &start) != 1)
- start = 0;
+ start = atoi(newmax);
for (;;) {
param_buff[2] = newmax;
param_buff[3] = 0;
success = uemis_get_answer(mountpath, "getDivelogs", 3, 0, &result);
/* process the buffer we have assembled */
- if (mbuf) {
- char *next_seg = process_raw_buffer(mbuf, &newmax);
- buffer_add(xml_buffer, &xml_buffer_size, next_seg);
- free(next_seg);
- }
- /* if we got an error, deal with it */
- if (!success)
- break;
- /* if the user clicked cancel, exit gracefully but ignore everything read */
+ if (mbuf)
+ process_raw_buffer(deviceidnr, mbuf, &newmax);
+ /* if the user clicked cancel, exit gracefully */
if (import_thread_cancelled)
goto bail;
- /* also, if we got nothing back, we should stop trying */
- if (!param_buff[3])
+ /* if we got an error or got nothing back, stop trying */
+ if (!success || !param_buff[3])
break;
/* finally, if the memory is getting too full, maybe we better stop, too */
if (progress_bar_fraction > 0.85) {
@@ -818,16 +775,21 @@ static char *do_uemis_download(struct argument_block *args)
for (i = start; i < end; i++) {
snprintf(objectid, sizeof(objectid), "%d", i);
param_buff[2] = objectid;
- param_buff[3] = 0;
success = uemis_get_answer(mountpath, "getDive", 3, 0, &result);
- if (mbuf) {
- char *next_detail = process_raw_buffer(mbuf, &newmax);
- buffer_insert(xml_buffer, &xml_buffer_size, next_detail);
- free(next_detail);
- }
+ if (mbuf)
+ process_raw_buffer(deviceidnr, mbuf, &newmax);
if (!success || import_thread_cancelled)
break;
}
+ success = TRUE;
+ for (i = 0; i <= nr_divespots; i++) {
+ char divespotnr[10];
+ snprintf(divespotnr, sizeof(divespotnr), "%d", i);
+ param_buff[2] = divespotnr;
+ success = uemis_get_answer(mountpath, "getDivespot", 3, 0, &result);
+ if (mbuf)
+ parse_divespot(mbuf);
+ }
bail:
(void) uemis_get_answer(mountpath, "terminateSync", 0, 3, &result);
if (! strcmp(param_buff[0], "error")) {
@@ -836,13 +798,6 @@ bail:
else
result = param_buff[2];
}
- if (import_thread_cancelled)
- xml_buffer[0] = 0;
- else
- buffer_add(xml_buffer, &xml_buffer_size, "</list></dives>");
-#if UEMIS_DEBUG > 5
- fprintf(debugfile, "XML buffer \"%s\"", *xml_buffer);
-#endif
free(deviceid);
return result;
}
@@ -866,12 +821,12 @@ static gboolean timeout_func(gpointer _data)
return FALSE;
}
-GError *uemis_download(const char *mountpath, char **xml_buffer, progressbar_t *progress,
+GError *uemis_download(const char *mountpath, progressbar_t *progress,
GtkDialog *dialog, gboolean force_download)
{
pthread_t pthread;
void *retval;
- struct argument_block args = {mountpath, xml_buffer, progress, force_download};
+ struct argument_block args = {mountpath, progress, force_download};
/* I'm sure there is some better interface for waiting on a thread in a UI main loop */
import_thread_done = 0;
@@ -891,18 +846,11 @@ GError *uemis_download(const char *mountpath, char **xml_buffer, progressbar_t *
update_progressbar(args.progress, progress_bar_fraction);
update_progressbar_text(args.progress, progress_bar_text);
result = gtk_dialog_run(dialog);
- switch (result) {
- case GTK_RESPONSE_CANCEL:
+ if (result == GTK_RESPONSE_CANCEL)
import_thread_cancelled = TRUE;
- progress_bar_text = "Cancelled...";
- break;
- default:
- /* nothing */
- break;
- }
} else {
update_progressbar(args.progress, progress_bar_fraction);
- update_progressbar_text(args.progress, progress_bar_text);
+ update_progressbar_text(args.progress, "Cancelled, exiting cleanly...");
usleep(100000);
}
}
diff --git a/uemis.c b/uemis.c
index 3c5bef082..dc2e29fa8 100644
--- a/uemis.c
+++ b/uemis.c
@@ -102,6 +102,79 @@ bail:
return datalen;
}
+struct uemis_helper {
+ int diveid;
+ int lbs;
+ int divespot;
+ char **location;
+ double *latitude;
+ double *longitude;
+ struct uemis_helper *next;
+};
+static struct uemis_helper *uemis_helper = NULL;
+
+static struct uemis_helper *uemis_get_helper(int diveid)
+{
+ struct uemis_helper **php = &uemis_helper;
+ struct uemis_helper *hp = *php;
+
+ while(hp) {
+ if (hp->diveid == diveid)
+ return hp;
+ if (hp->next) {
+ hp = hp->next;
+ continue;
+ }
+ php = &hp->next;
+ break;
+ }
+ hp = *php = malloc(sizeof(struct uemis_helper));
+ hp->diveid = diveid;
+ hp->next = NULL;
+ return hp;
+}
+
+static void uemis_weight_unit(int diveid, int lbs)
+{
+ struct uemis_helper *hp = uemis_get_helper(diveid);
+ if (hp)
+ hp->lbs = lbs;
+}
+
+int uemis_get_weight_unit(int diveid)
+{
+ struct uemis_helper *hp = uemis_helper;
+ while (hp) {
+ if (hp->diveid == diveid)
+ return hp->lbs;
+ hp = hp->next;
+ }
+ /* odd - we should have found this; default to kg */
+ return 0;
+}
+
+void uemis_mark_divelocation(int diveid, int divespot, char **location, double *longitude, double *latitude)
+{
+ struct uemis_helper *hp = uemis_get_helper(diveid);
+ hp->divespot = divespot;
+ hp->location = location;
+ hp->longitude = longitude;
+ hp->latitude = latitude;
+}
+
+void uemis_set_divelocation(int divespot, char *text, double longitude, double latitude)
+{
+ struct uemis_helper *hp = uemis_helper;
+ while (hp) {
+ if (hp->divespot == divespot && hp->location) {
+ *hp->location = text;
+ *hp->longitude = longitude;
+ *hp->latitude = latitude;
+ }
+ hp = hp->next;
+ }
+}
+
/* Create events from the flag bits and other data in the sample;
* These bits basically represent what is displayed on screen at sample time.
* Many of these 'warnings' are way hyper-active and seriously clutter the
@@ -203,7 +276,9 @@ void uemis_parse_divelog_binary(char *base64, void *datap) {
dc->model = strdup("Uemis Zurich");
dc->deviceid = *(uint32_t *)(data + 9);
dc->diveid = *(uint16_t *)(data + 7);
-
+ /* remember the weight units used in this dive - we may need this later when
+ * parsing the weight */
+ uemis_weight_unit(dc->diveid, *(uint8_t *)(data + 24));
/* dive template in use:
0 = air
1 = nitrox (B)
diff --git a/uemis.h b/uemis.h
index 4cb5c2b47..9e6e0950a 100644
--- a/uemis.h
+++ b/uemis.h
@@ -8,6 +8,10 @@
#include <stdint.h>
void uemis_parse_divelog_binary(char *base64, void *divep);
+int uemis_get_weight_unit(int diveid);
+void uemis_mark_divelocation(int diveid, int divespot, char **location, double *longitude, double *latitude);
+void uemis_set_divelocation(int divespot, char *text, double longitude, double latitude);
+
void decode(uint8_t *in, uint8_t *out, int len);
typedef struct {