summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--libdivecomputer.c8
-rw-r--r--uemis.c275
-rw-r--r--uemis.h15
4 files changed, 302 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 858f4a868..c78b806bb 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ LIBDIVECOMPUTERINCLUDES = $(LIBDIVECOMPUTERDIR)/include/libdivecomputer
LIBDIVECOMPUTERARCHIVE = $(LIBDIVECOMPUTERDIR)/lib/libdivecomputer.a
OBJS = main.o dive.o profile.o info.o equipment.o divelist.o \
- parse-xml.o save-xml.o libdivecomputer.o print.o
+ parse-xml.o save-xml.o libdivecomputer.o print.o uemis.o
divelog: $(OBJS)
$(CC) $(LDFLAGS) -o divelog $(OBJS) \
@@ -46,3 +46,6 @@ libdivecomputer.o: libdivecomputer.c dive.h display.h
$(CC) $(CFLAGS) `pkg-config --cflags gtk+-2.0 glib-2.0` \
-I$(LIBDIVECOMPUTERINCLUDES) \
-c libdivecomputer.c
+
+uemis.o: uemis.c uemis.h
+ $(CC) $(CFLAGS) `pkg-config --cflags gtk+-2.0 glib-2.0` -c uemis.c
diff --git a/libdivecomputer.c b/libdivecomputer.c
index 06ab06639..2b62fa365 100644
--- a/libdivecomputer.c
+++ b/libdivecomputer.c
@@ -18,6 +18,9 @@
#include <atomics.h>
#include <utils.h>
+/* handling uemis Zurich SDA files */
+#include "uemis.h"
+
/*
* I'd love to do a while-loop here for pending events, but
* that seems to screw up with the dive computer reading timing.
@@ -437,6 +440,10 @@ static void do_import(device_data_t *data)
device_t *device = NULL;
device_status_t rc;
+ if (data->type == DEVICE_TYPE_UEMIS) {
+ return uemis_import();
+ }
+
rc = device_open(data->devname, data->type, &device);
if (rc != DEVICE_STATUS_SUCCESS) {
error("Unable to open %s (%s)", data->name, data->devname);
@@ -502,6 +509,7 @@ struct device_list {
{ "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
{ "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
{ "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },
+ { "Uemis Zurich SDA", DEVICE_TYPE_UEMIS },
{ NULL }
};
diff --git a/uemis.c b/uemis.c
new file mode 100644
index 000000000..63541353b
--- /dev/null
+++ b/uemis.c
@@ -0,0 +1,275 @@
+/*
+ * uemis.c
+ *
+ * UEMIS SDA file importer
+ * AUTHOR: Dirk Hohndel - Copyright 2011
+ *
+ * Licensed under the MIT license.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#define __USE_XOPEN
+#include <time.h>
+#include <regex.h>
+
+#include <gtk/gtk.h>
+
+#include "dive.h"
+#include "display.h"
+#include "uemis.h"
+
+/*
+ * following code is based on code found in at base64.sourceforge.net/b64.c
+ * AUTHOR: Bob Trower 08/04/01
+ * COPYRIGHT: Copyright (c) Trantor Standard Systems Inc., 2001
+ * NOTE: This source code may be used as you wish, subject to
+ * the MIT license.
+ */
+/*
+ * Translation Table to decode (created by Bob Trower)
+ */
+static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
+
+/*
+ * decodeblock -- decode 4 '6-bit' characters into 3 8-bit binary bytes
+ */
+static void decodeblock( unsigned char in[4], unsigned char out[3] ) {
+ out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
+ out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
+ out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
+}
+
+/*
+ * decode a base64 encoded stream discarding padding, line breaks and noise
+ */
+static void decode( uint8_t *inbuf, uint8_t *outbuf, int inbuf_len ) {
+ uint8_t in[4], out[3], v;
+ int i,len,indx_in=0,indx_out=0;
+
+ while (indx_in < inbuf_len) {
+ for (len = 0, i = 0; i < 4 && (indx_in < inbuf_len); i++ ) {
+ v = 0;
+ while ((indx_in < inbuf_len) && v == 0) {
+ v = inbuf[indx_in++];
+ v = ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
+ if (v)
+ v = ((v == '$') ? 0 : v - 61);
+ }
+ if (indx_in < inbuf_len) {
+ len++;
+ if (v)
+ in[i] = (v - 1);
+ }
+ else
+ in[i] = 0;
+ }
+ if( len ) {
+ decodeblock( in, out );
+ for( i = 0; i < len - 1; i++ )
+ outbuf[indx_out++] = out[i];
+ }
+ }
+}
+/* end code from Bob Trower */
+
+/* small helper functions */
+/* simpleregex allocates (and reallocates) the found buffer
+ * don't forget to free it when you are done
+ */
+static int simpleregex(char *buffer, char *regex, char **found) {
+ int status;
+ regex_t re;
+ regmatch_t match[5];
+
+ if (regcomp(&re, regex, 0) !=0) {
+ fprintf(stderr,"internal error, regex failed!\n");
+ exit(1);
+ }
+ status = regexec(&re,buffer,5,match,0);
+ if(status == 0) {
+ *found = realloc(*found,match[1].rm_eo-match[1].rm_so + 1);
+ strncpy(*found,buffer+match[1].rm_so,match[1].rm_eo-match[1].rm_so);
+ (*found)[match[1].rm_eo-match[1].rm_so] = '\0';
+ }
+ return(status == 0);
+}
+
+/* read in line of arbitrary length (important for SDA files that can
+ * have lines that are tens of kB long
+ * don't forget to free it when you are done
+ */
+#define MYGETL_INCR 1024
+static char * mygetline(FILE * f) {
+ size_t size = 0;
+ size_t len = 0;
+ char * buf = NULL;
+
+ do {
+ size += MYGETL_INCR;
+ if ((buf = realloc(buf,size)) == NULL)
+ break;
+ fgets(buf+len,MYGETL_INCR,f);
+ len = strlen(buf);
+ } while (!feof(f) && buf[len-1]!='\n');
+ return buf;
+}
+
+/* text matching, used to build very poor man's XML parser */
+int matchit(FILE *infd, char *regex, char *typeregex, char **found) {
+ char *buffer;
+
+ while (!feof(infd)) {
+ buffer = mygetline(infd);
+ if (buffer && simpleregex(buffer,regex,found)) {
+ buffer = mygetline(infd);
+ if (buffer && simpleregex(buffer,typeregex,found)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * convert the base64 data blog
+ */
+int uemis_convert_base64(char *base64, uint8_t **data) {
+ int len,datalen;
+
+ len = strlen(base64);
+ datalen = (len/4 + 1)*3;
+ if (datalen < 0x123+0x25) {
+ /* less than header + 1 sample??? */
+ fprintf(stderr,"suspiciously short data block\n");
+ }
+ *data = malloc(datalen);
+ if (! *data) {
+ datalen = 0;
+ fprintf(stderr,"Out of memory\n");
+ goto bail;
+ }
+ decode(base64, *data, len);
+
+ if (memcmp(data,"Dive\01\00\00",7))
+ fprintf(stderr,"Missing Dive100 header\n");
+
+bail:
+ return datalen;
+}
+
+/*
+ * parse uemis base64 data blob into struct dive
+ */
+static void parse_divelog_binary(char *base64, struct dive **divep) {
+ int datalen;
+ int i;
+ uint8_t *data;
+ struct sample *sample;
+
+ datalen = uemis_convert_base64(base64, &data);
+
+ /* first byte of divelog data is at offset 0x123 */
+ i = 0x123;
+ while ((i < datalen) && (*(uint16_t *)(data+i))) {
+ /* it seems that a dive_time of 0 indicates the end of the valid readings */
+ sample = prepare_sample(divep);
+ sample->time.seconds = *(uint16_t *)(data+i);
+ sample->depth.mm = (*(uint16_t *)(data+i+2) - 100) / 0.101428571 + 0.5;
+ sample->temperature.mkelvin = (*(uint16_t *)(data+i+4) * 100) + 273150;
+ sample->cylinderpressure.mbar= *(uint16_t *)(data+i+23) * 10;
+ sample->cylinderindex = *(uint8_t *)(data+i+22);
+ finish_sample(*divep, sample);
+ i += 0x25;
+ }
+ return;
+}
+
+void
+parse_uemis_file(char *divelogfilename,GError **error) {
+ char *found=NULL;
+ struct tm tm;
+ struct dive *dive;
+
+ FILE *divelogfile = fopen(divelogfilename,"r");
+
+ dive = alloc_dive();
+
+ if (! matchit(divelogfile,"val key=\"date\"","<ts>\\([^<]*\\)</ts>",&found)) {
+ /* some error handling */
+ goto bail;
+ }
+ strptime(found, "%Y-%m-%dT%H:%M:%S", &tm);
+ dive->when = utc_mktime(&tm);
+ if (! matchit(divelogfile,"<val key=\"duration\">",
+ "<float>\\([0-9.]*\\)</float>", &found)) {
+ /* some error handling */
+ goto bail;
+ }
+ dive->duration.seconds = 60.0 * atof(found);
+
+ if (! matchit(divelogfile,"<val key=\"depth\">",
+ "<int>\\([0-9.]*\\)</int>", &found)) {
+ /* some error handling */
+ goto bail;
+ }
+ dive->maxdepth.mm = atof(found) / 0.10143 + 0.5;
+
+ if (! matchit(divelogfile,"<val key=\"file_content\">",
+ ">\\([a-zA-Z0-9+/]*\\)<", &found)) {
+ /* some error handling */
+ goto bail;
+ }
+ parse_divelog_binary(found,&dive);
+ record_dive(dive);
+bail:
+ if (found)
+ free(found);
+}
+
+/*
+ * parse the two files extracted from the SDA
+ */
+void
+uemis_import() {
+ GtkWidget *dialog;
+ GtkFileFilter *filter = gtk_file_filter_new ();
+ gtk_file_filter_add_pattern (filter, "*.SDA");
+ gtk_file_filter_set_name(filter, "uemis Zurich SDA files");
+ dialog = gtk_file_chooser_dialog_new("Open File",
+ GTK_WINDOW(main_window),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),filter);
+
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+ GSList *filenames;
+ char *filename;
+ filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
+
+ GError *error = NULL;
+ while(filenames != NULL) {
+ filename = (char *)filenames->data;
+ parse_uemis_file(filename, &error);
+ if (error != NULL)
+ {
+ report_error(error);
+ g_error_free(error);
+ error = NULL;
+ }
+
+ g_free(filename);
+ filenames = g_slist_next(filenames);
+ }
+ g_slist_free(filenames);
+ report_dives();
+ }
+ gtk_widget_destroy(dialog);
+}
diff --git a/uemis.h b/uemis.h
new file mode 100644
index 000000000..1b6c026d1
--- /dev/null
+++ b/uemis.h
@@ -0,0 +1,15 @@
+#ifndef UEMIS_H
+#define UEMIS_H
+
+/*
+ * defines and prototypes for the uemis Zurich SDA file parser
+ * we add this to the list of dive computers that is supported
+ * in libdivecomputer by using a negative value for the type enum
+ */
+#define DEVICE_TYPE_UEMIS (-1)
+
+void uemis_import();
+
+extern GtkWidget *main_window;
+
+#endif /* DIVE_H */