diff --git a/examples/common.c b/examples/common.c
index d5740d8..ebc1542 100644
--- a/examples/common.c
+++ b/examples/common.c
@@ -91,6 +91,7 @@ static const backend_table_t g_backends[] = {
{"cochran", DC_FAMILY_COCHRAN_COMMANDER, 0},
{"divecomputereu", DC_FAMILY_TECDIVING_DIVECOMPUTEREU, 0},
{"descentmk1", DC_FAMILY_GARMIN, 0},
+ {"cosmiq", DC_FAMILY_DEEPBLU, 0},
};
static const transport_table_t g_transports[] = {
diff --git a/include/libdivecomputer/common.h b/include/libdivecomputer/common.h
index 4ba705b..0819843 100644
--- a/include/libdivecomputer/common.h
+++ b/include/libdivecomputer/common.h
@@ -110,6 +110,8 @@ typedef enum dc_family_t {
DC_FAMILY_TECDIVING_DIVECOMPUTEREU = (15 << 16),
/* Garmin */
DC_FAMILY_GARMIN = (16 << 16),
+ /* Deepblu */
+ DC_FAMILY_DEEPBLU = (17 << 16),
} dc_family_t;
#ifdef __cplusplus
diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj
index 8c5cbf2..99abc2f 100644
--- a/msvc/libdivecomputer.vcproj
+++ b/msvc/libdivecomputer.vcproj
@@ -506,6 +506,14 @@
RelativePath="..\src\garmin_parser.c"
>
+
+
+
+
@@ -852,6 +860,10 @@
RelativePath="..\src\garmin.h"
>
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 2afd9cf..566352e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -73,6 +73,7 @@ libdivecomputer_la_SOURCES = \
cochran_commander.h cochran_commander.c cochran_commander_parser.c \
tecdiving_divecomputereu.h tecdiving_divecomputereu.c tecdiving_divecomputereu_parser.c \
garmin.h garmin.c garmin_parser.c \
+ deepblu.h deepblu.c deepblu_parser.c \
socket.h socket.c \
irda.c \
usbhid.c \
diff --git a/src/deepblu.c b/src/deepblu.c
new file mode 100644
index 0000000..454486d
--- /dev/null
+++ b/src/deepblu.c
@@ -0,0 +1,110 @@
+/*
+ * Deepblu Cosmiq+ downloading
+ *
+ * Copyright (C) 2019 Linus Torvalds
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include
+
+#include "deepblu.h"
+#include "context-private.h"
+#include "device-private.h"
+#include "array.h"
+
+typedef struct deepblu_device_t {
+ dc_device_t base;
+ dc_iostream_t *iostream;
+ unsigned char fingerprint[8];
+} deepblu_device_t;
+
+static dc_status_t deepblu_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
+static dc_status_t deepblu_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
+static dc_status_t deepblu_device_close (dc_device_t *abstract);
+
+static const dc_device_vtable_t deepblu_device_vtable = {
+ sizeof(deepblu_device_t),
+ DC_FAMILY_DEEPBLU,
+ deepblu_device_set_fingerprint, /* set_fingerprint */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* dump */
+ deepblu_device_foreach, /* foreach */
+ NULL, /* timesync */
+ deepblu_device_close, /* close */
+};
+
+dc_status_t
+deepblu_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
+{
+ deepblu_device_t *device;
+
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ // Allocate memory.
+ device = (deepblu_device_t *) dc_device_allocate (context, &deepblu_device_vtable);
+ if (device == NULL) {
+ ERROR (context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ // Set the default values.
+ device->iostream = iostream;
+ memset(device->fingerprint, 0, sizeof(device->fingerprint));
+
+ *out = (dc_device_t *) device;
+
+ ERROR (context, "Deepblu Cosmiq+ open called");
+ return DC_STATUS_SUCCESS;
+}
+
+static dc_status_t
+deepblu_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
+{
+ deepblu_device_t *device = (deepblu_device_t *)abstract;
+
+ if (size && size != sizeof (device->fingerprint))
+ return DC_STATUS_INVALIDARGS;
+
+ if (size)
+ memcpy (device->fingerprint, data, sizeof (device->fingerprint));
+ else
+ memset (device->fingerprint, 0, sizeof (device->fingerprint));
+
+ ERROR (device->base.context, "Deepblu Cosmiq+ set_fingerprint called");
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+deepblu_device_close (dc_device_t *abstract)
+{
+ deepblu_device_t *device = (deepblu_device_t *) abstract;
+
+ ERROR (device->base.context, "Deepblu Cosmiq+ device close called");
+ return DC_STATUS_SUCCESS;
+}
+
+static dc_status_t
+deepblu_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
+{
+ deepblu_device_t *device = (deepblu_device_t *) abstract;
+
+ ERROR (device->base.context, "Deepblu Cosmiq+ device_foreach called");
+ return DC_STATUS_SUCCESS;
+}
diff --git a/src/deepblu.h b/src/deepblu.h
new file mode 100644
index 0000000..92b821f
--- /dev/null
+++ b/src/deepblu.h
@@ -0,0 +1,43 @@
+/*
+ * Deepblu Cosmiq+ downloading/parsing
+ *
+ * Copyright (C) 2018 Linus Torvalds
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef DEEPBLU_H
+#define DEEPBLU_H
+
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+dc_status_t
+deepblu_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
+
+dc_status_t
+deepblu_parser_create (dc_parser_t **parser, dc_context_t *context);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* DEEPBLU_H */
diff --git a/src/deepblu_parser.c b/src/deepblu_parser.c
new file mode 100644
index 0000000..71161e1
--- /dev/null
+++ b/src/deepblu_parser.c
@@ -0,0 +1,240 @@
+/*
+ * Deeplu Cosmiq+ parsing
+ *
+ * Copyright (C) 2019 Linus Torvalds
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include
+#include
+#include
+#include
+
+#include "deepblu.h"
+#include "context-private.h"
+#include "parser-private.h"
+#include "array.h"
+
+#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+#define MAXFIELDS 128
+
+struct msg_desc;
+
+#define MAXTYPE 16
+#define MAXGASES 16
+#define MAXSTRINGS 32
+
+typedef struct deepblu_parser_t {
+ dc_parser_t base;
+
+ dc_sample_callback_t callback;
+ void *userdata;
+
+ // Field cache
+ struct {
+ unsigned int initialized;
+
+ // dc_get_field() data
+ unsigned int DIVETIME;
+ double MAXDEPTH;
+ double AVGDEPTH;
+ unsigned int GASMIX_COUNT;
+ dc_salinity_t SALINITY;
+ dc_gasmix_t gasmix[MAXGASES];
+
+ dc_field_string_t strings[MAXSTRINGS];
+ } cache;
+} deepblu_parser_t;
+
+// I *really* need to make this generic
+static void add_string(deepblu_parser_t *deepblu, const char *desc, const char *data);
+static void add_string_fmt(deepblu_parser_t *deepblu, const char *desc, const char *fmt, ...);
+
+/*
+ * Macro to make it easy to set DC_FIELD_xyz values
+ */
+#define ASSIGN_FIELD(name, value) do { \
+ deepblu->cache.initialized |= 1u << DC_FIELD_##name; \
+ deepblu->cache.name = (value); \
+} while (0)
+
+
+static dc_status_t deepblu_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
+static dc_status_t deepblu_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
+static dc_status_t deepblu_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
+static dc_status_t deepblu_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
+
+static const dc_parser_vtable_t deepblu_parser_vtable = {
+ sizeof(deepblu_parser_t),
+ DC_FAMILY_DEEPBLU,
+ deepblu_parser_set_data, /* set_data */
+ deepblu_parser_get_datetime, /* datetime */
+ deepblu_parser_get_field, /* fields */
+ deepblu_parser_samples_foreach, /* samples_foreach */
+ NULL /* destroy */
+};
+
+dc_status_t
+deepblu_parser_create (dc_parser_t **out, dc_context_t *context)
+{
+ deepblu_parser_t *parser = NULL;
+
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ // Allocate memory.
+ parser = (deepblu_parser_t *) dc_parser_allocate (context, &deepblu_parser_vtable);
+ if (parser == NULL) {
+ ERROR (context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ *out = (dc_parser_t *) parser;
+
+ ERROR (context, "Deepblu Cosmiq+ parser_create() called");
+ return DC_STATUS_SUCCESS;
+}
+
+/*
+ * FIXME! This should all be generic.
+ *
+ * Now it's just copied between all the different
+ * dive computers that support the strings..
+ */
+static void add_string(deepblu_parser_t *deepblu, const char *desc, const char *value)
+{
+ int i;
+
+ deepblu->cache.initialized |= 1 << DC_FIELD_STRING;
+ for (i = 0; i < MAXSTRINGS; i++) {
+ dc_field_string_t *str = deepblu->cache.strings+i;
+ if (str->desc)
+ continue;
+ str->desc = desc;
+ str->value = strdup(value);
+ break;
+ }
+}
+
+static void add_string_fmt(deepblu_parser_t *deepblu, const char *desc, const char *fmt, ...)
+{
+ char buffer[256];
+ va_list ap;
+
+ va_start(ap, fmt);
+ buffer[sizeof(buffer)-1] = 0;
+ (void) vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
+ va_end(ap);
+
+ add_string(deepblu, desc, buffer);
+}
+
+static dc_status_t
+deepblu_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
+{
+ deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
+
+ deepblu->callback = NULL;
+ deepblu->userdata = NULL;
+ memset(&deepblu->cache, 0, sizeof(deepblu->cache));
+
+ ERROR (abstract->context, "Deepblu Cosmiq+ parser_set_data() called");
+ return DC_STATUS_SUCCESS;
+}
+
+static dc_status_t
+deepblu_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
+{
+ deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
+
+ ERROR (abstract->context, "Deepblu Cosmiq+ parser_get_datetime() called");
+ return DC_STATUS_UNSUPPORTED;
+}
+
+static dc_status_t get_string_field(dc_field_string_t *strings, unsigned idx, dc_field_string_t *value)
+{
+ if (idx < MAXSTRINGS) {
+ dc_field_string_t *res = strings+idx;
+ if (res->desc && res->value) {
+ *value = *res;
+ return DC_STATUS_SUCCESS;
+ }
+ }
+ return DC_STATUS_UNSUPPORTED;
+}
+
+// Ugly define thing makes the code much easier to read
+// I'd love to use __typeof__, but that's a gcc'ism
+#define field_value(p, NAME) \
+ (memcpy((p), &deepblu->cache.NAME, sizeof(deepblu->cache.NAME)), DC_STATUS_SUCCESS)
+// Hacky hack hack
+#define GASMIX gasmix[flags]
+
+static dc_status_t
+deepblu_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
+{
+ deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
+
+ if (!value)
+ return DC_STATUS_INVALIDARGS;
+
+ /* This whole sequence should be standardized */
+ if (!(deepblu->cache.initialized & (1 << type)))
+ return DC_STATUS_UNSUPPORTED;
+
+ switch (type) {
+ case DC_FIELD_DIVETIME:
+ return field_value(value, DIVETIME);
+ case DC_FIELD_MAXDEPTH:
+ return field_value(value, MAXDEPTH);
+ case DC_FIELD_AVGDEPTH:
+ return field_value(value, AVGDEPTH);
+ case DC_FIELD_GASMIX_COUNT:
+ case DC_FIELD_TANK_COUNT:
+ return field_value(value, GASMIX_COUNT);
+ case DC_FIELD_GASMIX:
+ if (flags >= MAXGASES)
+ return DC_STATUS_UNSUPPORTED;
+ return field_value(value, GASMIX);
+ case DC_FIELD_SALINITY:
+ return field_value(value, SALINITY);
+ case DC_FIELD_ATMOSPHERIC:
+ return DC_STATUS_UNSUPPORTED;
+ case DC_FIELD_DIVEMODE:
+ return DC_STATUS_UNSUPPORTED;
+ case DC_FIELD_TANK:
+ return DC_STATUS_UNSUPPORTED;
+ case DC_FIELD_STRING:
+ return get_string_field(deepblu->cache.strings, flags, (dc_field_string_t *)value);
+ default:
+ return DC_STATUS_UNSUPPORTED;
+ }
+ return DC_STATUS_SUCCESS;
+}
+
+static dc_status_t
+deepblu_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
+{
+ deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
+
+ deepblu->callback = callback;
+ deepblu->userdata = userdata;
+
+ ERROR (abstract->context, "Deepblu Cosmiq+ samples_foreach() called");
+ return DC_STATUS_SUCCESS;
+}
diff --git a/src/descriptor.c b/src/descriptor.c
index da0a990..81d34f0 100644
--- a/src/descriptor.c
+++ b/src/descriptor.c
@@ -48,6 +48,7 @@ static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata);
static int dc_filter_garmin (dc_transport_t transport, const void *userdata);
static int dc_filter_mares (dc_transport_t transport, const void *userdata);
static int dc_filter_divesystem (dc_transport_t transport, const void *userdata);
+static int dc_filter_deepblu (dc_transport_t transport, const void *userdata);
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
@@ -373,6 +374,8 @@ static const dc_descriptor_t g_descriptors[] = {
{"Tecdiving", "DiveComputer.eu", DC_FAMILY_TECDIVING_DIVECOMPUTEREU, 0, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_tecdiving},
/* Garmin */
{"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
+ /* Deepblu */
+ {"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU, 0, DC_TRANSPORT_BLE, dc_filter_deepblu},
};
static int
@@ -601,6 +604,19 @@ static int dc_filter_divesystem (dc_transport_t transport, const void *userdata)
return 1;
}
+static int dc_filter_deepblu (dc_transport_t transport, const void *userdata)
+{
+ static const char * const bluetooth[] = {
+ "COSMIQ",
+ };
+
+ if (transport == DC_TRANSPORT_BLE) {
+ return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
+ }
+
+ return 1;
+}
+
dc_status_t
dc_descriptor_iterator (dc_iterator_t **out)
{
diff --git a/src/device.c b/src/device.c
index ce9a29f..15bfcf3 100644
--- a/src/device.c
+++ b/src/device.c
@@ -58,6 +58,7 @@
#include "cochran_commander.h"
#include "tecdiving_divecomputereu.h"
#include "garmin.h"
+#include "deepblu.h"
#include "device-private.h"
#include "context-private.h"
@@ -215,6 +216,9 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
case DC_FAMILY_GARMIN:
rc = garmin_device_open (&device, context, iostream);
break;
+ case DC_FAMILY_DEEPBLU:
+ rc = deepblu_device_open (&device, context, iostream);
+ break;
default:
return DC_STATUS_INVALIDARGS;
}
diff --git a/src/parser.c b/src/parser.c
index 563bd78..11e3975 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -176,6 +176,9 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
case DC_FAMILY_GARMIN:
rc = garmin_parser_create (&parser, context);
break;
+ case DC_FAMILY_DEEPBLU:
+ rc = deepblu_parser_create (&parser, context);
+ break;
default:
return DC_STATUS_INVALIDARGS;
}