diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj
index 99abc2f..0ae0ed6 100644
--- a/msvc/libdivecomputer.vcproj
+++ b/msvc/libdivecomputer.vcproj
@@ -514,6 +514,10 @@
RelativePath="..\src\deepblu_parser.c"
>
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 566352e..af2bc6d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -69,6 +69,7 @@ libdivecomputer_la_SOURCES = \
rbstream.h rbstream.c \
checksum.h checksum.c \
array.h array.c \
+ field-cache.h field-cache.c \
buffer.c \
cochran_commander.h cochran_commander.c cochran_commander_parser.c \
tecdiving_divecomputereu.h tecdiving_divecomputereu.c tecdiving_divecomputereu_parser.c \
diff --git a/src/deepblu_parser.c b/src/deepblu_parser.c
index 6a4c778..073710e 100644
--- a/src/deepblu_parser.c
+++ b/src/deepblu_parser.c
@@ -28,6 +28,7 @@
#include "context-private.h"
#include "parser-private.h"
#include "array.h"
+#include "field-cache.h"
#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@@ -35,10 +36,6 @@
struct msg_desc;
-#define MAXTYPE 16
-#define MAXGASES 16
-#define MAXSTRINGS 32
-
typedef struct deepblu_parser_t {
dc_parser_t base;
@@ -48,37 +45,10 @@ typedef struct deepblu_parser_t {
// 20 sec for scuba, 1 sec for freedives
int sample_interval;
- // Field cache
- struct {
- unsigned int initialized;
-
- // dc_get_field() data
- unsigned int DIVETIME;
- double MAXDEPTH;
- double AVGDEPTH;
- double ATMOSPHERIC;
- dc_divemode_t DIVEMODE;
- unsigned int GASMIX_COUNT;
- dc_salinity_t SALINITY;
- dc_gasmix_t gasmix[MAXGASES];
-
- dc_field_string_t strings[MAXSTRINGS];
- } cache;
+ // Common fields
+ struct dc_field_cache 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);
@@ -114,41 +84,6 @@ deepblu_parser_create (dc_parser_t **out, dc_context_t *context)
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 double
pressure_to_depth(unsigned int mbar)
{
@@ -169,6 +104,7 @@ deepblu_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsig
const unsigned char *hdr = data;
const unsigned char *profile = data + 256;
unsigned int divetime, maxpressure;
+ dc_gasmix_t gasmix = {0, };
if (size < 256)
return DC_STATUS_IO;
@@ -189,19 +125,19 @@ deepblu_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsig
case 2:
// SCUBA - divetime in minutes
divetime *= 60;
- deepblu->cache.gasmix[0].oxygen = data[3] / 100.0;
- deepblu->cache.initialized |= 1u << DC_FIELD_GASMIX;
- ASSIGN_FIELD(GASMIX_COUNT, 1);
- ASSIGN_FIELD(DIVEMODE, DC_DIVEMODE_OC);
+ gasmix.oxygen = data[3] / 100.0;
+ DC_ASSIGN_IDX(deepblu->cache, GASMIX, 0, gasmix);
+ DC_ASSIGN_FIELD(deepblu->cache, GASMIX_COUNT, 1);
+ DC_ASSIGN_FIELD(deepblu->cache, DIVEMODE, DC_DIVEMODE_OC);
break;
case 3:
// GAUGE - divetime in minutes
divetime *= 60;
- ASSIGN_FIELD(DIVEMODE, DC_DIVEMODE_GAUGE);
+ DC_ASSIGN_FIELD(deepblu->cache, DIVEMODE, DC_DIVEMODE_GAUGE);
break;
case 4:
// FREEDIVE - divetime in seconds
- ASSIGN_FIELD(DIVEMODE, DC_DIVEMODE_FREEDIVE);
+ DC_ASSIGN_FIELD(deepblu->cache, DIVEMODE, DC_DIVEMODE_FREEDIVE);
deepblu->sample_interval = 1;
break;
default:
@@ -214,8 +150,8 @@ deepblu_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsig
maxpressure = hdr[22] + 256*hdr[23]; // Maxpressure in millibar
- ASSIGN_FIELD(DIVETIME, divetime);
- ASSIGN_FIELD(MAXDEPTH, pressure_to_depth(maxpressure));
+ DC_ASSIGN_FIELD(deepblu->cache, DIVETIME, divetime);
+ DC_ASSIGN_FIELD(deepblu->cache, MAXDEPTH, pressure_to_depth(maxpressure));
return DC_STATUS_SUCCESS;
}
@@ -263,25 +199,6 @@ deepblu_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
return DC_STATUS_SUCCESS;
}
-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)
{
@@ -296,28 +213,28 @@ deepblu_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
switch (type) {
case DC_FIELD_DIVETIME:
- return field_value(value, DIVETIME);
+ return DC_FIELD_VALUE(deepblu->cache, value, DIVETIME);
case DC_FIELD_MAXDEPTH:
- return field_value(value, MAXDEPTH);
+ return DC_FIELD_VALUE(deepblu->cache, value, MAXDEPTH);
case DC_FIELD_AVGDEPTH:
- return field_value(value, AVGDEPTH);
+ return DC_FIELD_VALUE(deepblu->cache, value, AVGDEPTH);
case DC_FIELD_GASMIX_COUNT:
case DC_FIELD_TANK_COUNT:
- return field_value(value, GASMIX_COUNT);
+ return DC_FIELD_VALUE(deepblu->cache, value, GASMIX_COUNT);
case DC_FIELD_GASMIX:
if (flags >= MAXGASES)
return DC_STATUS_UNSUPPORTED;
- return field_value(value, GASMIX);
+ return DC_FIELD_INDEX(deepblu->cache, value, GASMIX, flags);
case DC_FIELD_SALINITY:
- return field_value(value, SALINITY);
+ return DC_FIELD_VALUE(deepblu->cache, value, SALINITY);
case DC_FIELD_ATMOSPHERIC:
- return field_value(value, ATMOSPHERIC);
+ return DC_FIELD_VALUE(deepblu->cache, value, ATMOSPHERIC);
case DC_FIELD_DIVEMODE:
- return field_value(value, DIVEMODE);
+ return DC_FIELD_VALUE(deepblu->cache, value, DIVEMODE);
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);
+ return dc_field_get_string(&deepblu->cache, flags, (dc_field_string_t *)value);
default:
return DC_STATUS_UNSUPPORTED;
}
diff --git a/src/field-cache.c b/src/field-cache.c
new file mode 100644
index 0000000..ee25f39
--- /dev/null
+++ b/src/field-cache.c
@@ -0,0 +1,54 @@
+#include
+#include
+#include
+
+#include "parser-private.h"
+#include "field-cache.h"
+
+/*
+ * The field cache 'string' interface has some simple rules:
+ * the "descriptor" part is assumed to be a static allocation,
+ * while the "value" is something that this interface will
+ * alway sallocate with 'strdup()', so you can generate it
+ * dynamically on the stack or whatever without having to
+ * worry about it.
+ */
+void dc_field_add_string(dc_field_cache_t *cache, const char *desc, const char *value)
+{
+ int i;
+
+ cache->initialized |= 1 << DC_FIELD_STRING;
+ for (i = 0; i < MAXSTRINGS; i++) {
+ dc_field_string_t *str = cache->strings+i;
+ if (str->desc)
+ continue;
+ str->desc = desc;
+ str->value = strdup(value);
+ break;
+ }
+}
+
+void dc_field_add_string_fmt(dc_field_cache_t *cache, 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);
+
+ dc_field_add_string(cache, desc, buffer);
+}
+
+dc_status_t dc_field_get_string(dc_field_cache_t *cache, unsigned idx, dc_field_string_t *value)
+{
+ if (idx < MAXSTRINGS) {
+ dc_field_string_t *res = cache->strings+idx;
+ if (res->desc && res->value) {
+ *value = *res;
+ return DC_STATUS_SUCCESS;
+ }
+ }
+ return DC_STATUS_UNSUPPORTED;
+}
diff --git a/src/field-cache.h b/src/field-cache.h
new file mode 100644
index 0000000..87a4c6c
--- /dev/null
+++ b/src/field-cache.h
@@ -0,0 +1,47 @@
+#define MAXGASES 16
+#define MAXSTRINGS 32
+
+// dc_get_field() data
+typedef struct dc_field_cache {
+ unsigned int initialized;
+
+ unsigned int DIVETIME;
+ double MAXDEPTH;
+ double AVGDEPTH;
+ double ATMOSPHERIC;
+ dc_divemode_t DIVEMODE;
+ unsigned int GASMIX_COUNT;
+ dc_salinity_t SALINITY;
+ dc_gasmix_t GASMIX[MAXGASES];
+
+ dc_field_string_t strings[MAXSTRINGS];
+} dc_field_cache_t;
+
+void dc_field_add_string(dc_field_cache_t *, const char *desc, const char *data);
+void dc_field_add_string_fmt(dc_field_cache_t *, const char *desc, const char *fmt, ...);
+dc_status_t dc_field_get_string(dc_field_cache_t *, unsigned idx, dc_field_string_t *value);
+
+/*
+ * Macro to make it easy to set DC_FIELD_xyz values.
+ *
+ * This explains why dc_field_cache member names are
+ * those odd all-capitalized names: they match the
+ * names of the DC_FIELD_xyz enums.
+ */
+#define DC_ASSIGN_FIELD(cache, name, value) do { \
+ (cache).initialized |= 1u << DC_FIELD_##name; \
+ (cache).name = (value); \
+} while (0)
+
+#define DC_ASSIGN_IDX(cache, name, idx, value) do { \
+ (cache).initialized |= 1u << DC_FIELD_##name; \
+ (cache).name[idx] = (value); \
+} while (0)
+
+// Ugly define thing makes the code much easier to read
+// I'd love to use __typeof__, but that's a gcc'ism
+#define DC_FIELD_VALUE(cache, p, NAME) \
+ (memcpy((p), &(cache).NAME, sizeof((cache).NAME)), DC_STATUS_SUCCESS)
+
+#define DC_FIELD_INDEX(cache, p, NAME, idx) \
+ (memcpy((p), (cache).NAME+idx, sizeof((cache).NAME[0])), DC_STATUS_SUCCESS)