From 9a38a1ac6d6eded4717e62e45c0becc4de8c26b2 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 8 Nov 2014 18:08:58 -0800 Subject: [PATCH] Heinrichs Weikamp OSTC: add extended information parsing This adds the string field interface to the HW OSTC family, including the proper serial number handling. The deco model information was done by Anton Lundin in the original subsurface branch, and the salinity, serial number, battery voltage and desat information was added by Dirk Hohndel. Jan Mulder added the battery percentage. [ The sign-offs have been taken from the original commits in that old subsurface branch, and I'm marking Dirk as the main author because on the whole most of the lines come from him - Linus ] Signed-off-by: Anton Lundin Signed-off-by: Jan Mulder Signed-off-by: Dirk Hohndel Signed-off-by: Linus Torvalds --- src/hw_ostc.h | 2 +- src/hw_ostc3.h | 2 +- src/hw_ostc_parser.c | 128 +++++++++++++++++++++++++++++++++++++++++-- src/parser.c | 4 +- 4 files changed, 126 insertions(+), 10 deletions(-) diff --git a/src/hw_ostc.h b/src/hw_ostc.h index a0ce743..8232e5d 100644 --- a/src/hw_ostc.h +++ b/src/hw_ostc.h @@ -36,7 +36,7 @@ dc_status_t hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); dc_status_t -hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int hwos); +hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial, unsigned int hwos); #ifdef __cplusplus } diff --git a/src/hw_ostc3.h b/src/hw_ostc3.h index 92cf277..1e7720a 100644 --- a/src/hw_ostc3.h +++ b/src/hw_ostc3.h @@ -36,7 +36,7 @@ dc_status_t hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); dc_status_t -hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model); +hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int model); #ifdef __cplusplus } diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index bf28be9..f053a21 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -20,6 +20,12 @@ */ #include +#include +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif #include "libdivecomputer/units.h" @@ -61,8 +67,14 @@ #define OSTC3_APNEA 3 #define OSTC3_PSCR 4 +#define OSTC3_ZHL16 0 +#define OSTC3_ZHL16_GF 1 +#define OSTC4_VPM 2 + #define OSTC4 0x3B +#define UNSUPPORTED 0xFFFFFFFF + typedef struct hw_ostc_sample_info_t { unsigned int type; unsigned int divisor; @@ -78,7 +90,13 @@ typedef struct hw_ostc_layout_t { unsigned int salinity; unsigned int duration; unsigned int temperature; + unsigned int battery; + unsigned int desat; unsigned int firmware; + unsigned int deco_info1; + unsigned int deco_info2; + unsigned int decomode; + unsigned int battery_percentage; } hw_ostc_layout_t; typedef struct hw_ostc_gasmix_t { @@ -90,6 +108,7 @@ typedef struct hw_ostc_parser_t { dc_parser_t base; unsigned int hwos; unsigned int model; + unsigned int serial; // Cached fields. unsigned int cached; unsigned int version; @@ -127,7 +146,13 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc = { 43, /* salinity */ 47, /* duration */ 13, /* temperature */ + 34, /* battery volt after dive */ + 17, /* desat */ 32, /* firmware */ + 49, /* deco_info1 */ + 50, /* deco_info1 */ + 51, /* decomode */ + 0, /* battery percentage TBD */ }; static const hw_ostc_layout_t hw_ostc_layout_frog = { @@ -139,7 +164,13 @@ static const hw_ostc_layout_t hw_ostc_layout_frog = { 43, /* salinity */ 47, /* duration */ 19, /* temperature */ + 34, /* battery volt after dive */ + 23, /* desat */ 32, /* firmware */ + 49, /* deco_info1 */ + 50, /* deco_info2 */ + 51, /* decomode */ + 0, /* battery percentage TBD */ }; static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { @@ -151,7 +182,13 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { 70, /* salinity */ 75, /* duration */ 22, /* temperature */ + 50, /* battery volt after dive */ + 26, /* desat */ 48, /* firmware */ + 77, /* deco_info1 */ + 78, /* deco_info2 */ + 79, /* decomode */ + 59, /* battery percentage */ }; static unsigned int @@ -251,7 +288,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) } } // The first fixed setpoint is the initial setpoint in CCR mode. - if (data[82] == OSTC3_CC) { + if (data[82] == OSTC3_CC) { initial_setpoint = data[60]; } // Initial CNS @@ -294,7 +331,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) } static dc_status_t -hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int hwos, unsigned int model) +hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos, unsigned int model) { hw_ostc_parser_t *parser = NULL; @@ -324,6 +361,7 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign parser->gasmix[i].oxygen = 0; parser->gasmix[i].helium = 0; } + parser->serial = serial; *out = (dc_parser_t *) parser; @@ -332,15 +370,15 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign dc_status_t -hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int hwos) +hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos) { - return hw_ostc_parser_create_internal (out, context, hwos, 0); + return hw_ostc_parser_create_internal (out, context, serial, hwos, 0); } dc_status_t -hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) +hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int model) { - return hw_ostc_parser_create_internal (out, context, 1, model); + return hw_ostc_parser_create_internal (out, context, serial, 1, model); } static dc_status_t @@ -428,6 +466,8 @@ hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) return DC_STATUS_SUCCESS; } +#define BUFLEN 32 + static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) { @@ -452,9 +492,12 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; + dc_field_string_t *string = (dc_field_string_t *) value; + unsigned int salinity = data[layout->salinity]; if (version == 0x23 || version == 0x24) salinity += 100; + char buf[BUFLEN]; if (value) { switch (type) { @@ -550,6 +593,79 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned return DC_STATUS_UNSUPPORTED; } break; + case DC_FIELD_STRING: + switch(flags) { + case 0: /* serial */ + string->desc = "Serial"; + snprintf(buf, BUFLEN, "%u", parser->serial); + break; + case 1: /* battery */ + string->desc = "Battery at end"; + unsigned int percentage = (unsigned int) data[layout->battery_percentage]; + if (percentage != 0xFF && (version == 0x23 || version == 0x24)) { + percentage = percentage>100? 100: percentage; + snprintf(buf, BUFLEN, "%.2fV, %u%% remaining", + array_uint16_le (data + layout->battery) / 1000.0, + percentage); + } else { + snprintf(buf, BUFLEN, "%.2fV", array_uint16_le (data + layout->battery) / 1000.0); + } + break; + case 2: /* desat */ + string->desc = "Desat time"; + snprintf(buf, BUFLEN, "%0u:%02u", array_uint16_le (data + layout->desat) / 60, + array_uint16_le (data + layout->desat) % 60); + break; + case 3: /* firmware */ + string->desc = "FW Version"; + /* OSTC4 stores firmware as XXXX XYYY YYZZ ZZZB, -> X.Y.Z beta? */ + if (parser->model == OSTC4) { + int firmwareOnDevice = array_uint16_le (data + layout->firmware); + unsigned char X = 0, Y = 0, Z = 0, beta = 0; + X = (firmwareOnDevice & 0xF800) >> 11; + Y = (firmwareOnDevice & 0x07C0) >> 6; + Z = (firmwareOnDevice & 0x003E) >> 1; + beta = firmwareOnDevice & 0x0001; + + snprintf(buf, BUFLEN, "%u.%u.%u%s\n", X, Y, Z, beta? "beta": ""); + } else { + snprintf(buf, BUFLEN, "%0u.%02u", data[layout->firmware], data[layout->firmware + 1]); + } + break; + + case 4: /* Deco model */ + string->desc = "Deco model"; + if (((version == 0x23 || version == 0x24) && data[layout->decomode] == OSTC3_ZHL16) || + (version == 0x22 && data[layout->decomode] == FROG_ZHL16) || + (version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC || data[layout->decomode] == OSTC_ZHL16_CC))) + strncpy(buf, "ZH-L16", BUFLEN); + else if (((version == 0x23 || version == 0x24) && data[layout->decomode] == OSTC3_ZHL16_GF) || + (version == 0x22 && data[layout->decomode] == FROG_ZHL16_GF) || + (version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC_GF || data[layout->decomode] == OSTC_ZHL16_CC_GF))) + strncpy(buf, "ZH-L16-GF", BUFLEN); + else if (((version == 0x24) && data[layout->decomode] == OSTC4_VPM)) + strncpy(buf, "VPM", BUFLEN); + else + return DC_STATUS_DATAFORMAT; + break; + case 5: /* Deco model info */ + string->desc = "Deco model info"; + if (((version == 0x23 || version == 0x24) && data[layout->decomode] == OSTC3_ZHL16) || + (version == 0x22 && data[layout->decomode] == FROG_ZHL16) || + (version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC || data[layout->decomode] == OSTC_ZHL16_CC))) + snprintf(buf, BUFLEN, "Saturation %u, Desaturation %u", layout->deco_info1, layout->deco_info2); + else if (((version == 0x23 || version == 0x24) && data[layout->decomode] == OSTC3_ZHL16_GF) || + (version == 0x22 && data[layout->decomode] == FROG_ZHL16_GF) || + (version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC_GF || data[layout->decomode] == OSTC_ZHL16_CC_GF))) + snprintf(buf, BUFLEN, "GF %u/%u", data[layout->deco_info1], data[layout->deco_info2]); + else + return DC_STATUS_DATAFORMAT; + break; + default: + return DC_STATUS_UNSUPPORTED; + } + string->value = strdup(buf); + break; default: return DC_STATUS_UNSUPPORTED; } diff --git a/src/parser.c b/src/parser.c index 2c982f5..a04eb38 100644 --- a/src/parser.c +++ b/src/parser.c @@ -133,11 +133,11 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa rc = mares_iconhd_parser_create (&parser, context, model); break; case DC_FAMILY_HW_OSTC: - rc = hw_ostc_parser_create (&parser, context, 0); + rc = hw_ostc_parser_create (&parser, context, serial, 0); break; case DC_FAMILY_HW_FROG: case DC_FAMILY_HW_OSTC3: - rc = hw_ostc3_parser_create (&parser, context, model); + rc = hw_ostc3_parser_create (&parser, context, serial, model); break; case DC_FAMILY_CRESSI_EDY: case DC_FAMILY_ZEAGLE_N2ITION3: