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 <glance@acc.umu.se>
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Dirk Hohndel 2014-11-08 18:08:58 -08:00 committed by Linus Torvalds
parent a6637442b7
commit 9a38a1ac6d
4 changed files with 126 additions and 10 deletions

View File

@ -36,7 +36,7 @@ dc_status_t
hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -36,7 +36,7 @@ dc_status_t
hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -20,6 +20,12 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
#include "libdivecomputer/units.h" #include "libdivecomputer/units.h"
@ -61,8 +67,14 @@
#define OSTC3_APNEA 3 #define OSTC3_APNEA 3
#define OSTC3_PSCR 4 #define OSTC3_PSCR 4
#define OSTC3_ZHL16 0
#define OSTC3_ZHL16_GF 1
#define OSTC4_VPM 2
#define OSTC4 0x3B #define OSTC4 0x3B
#define UNSUPPORTED 0xFFFFFFFF
typedef struct hw_ostc_sample_info_t { typedef struct hw_ostc_sample_info_t {
unsigned int type; unsigned int type;
unsigned int divisor; unsigned int divisor;
@ -78,7 +90,13 @@ typedef struct hw_ostc_layout_t {
unsigned int salinity; unsigned int salinity;
unsigned int duration; unsigned int duration;
unsigned int temperature; unsigned int temperature;
unsigned int battery;
unsigned int desat;
unsigned int firmware; unsigned int firmware;
unsigned int deco_info1;
unsigned int deco_info2;
unsigned int decomode;
unsigned int battery_percentage;
} hw_ostc_layout_t; } hw_ostc_layout_t;
typedef struct hw_ostc_gasmix_t { typedef struct hw_ostc_gasmix_t {
@ -90,6 +108,7 @@ typedef struct hw_ostc_parser_t {
dc_parser_t base; dc_parser_t base;
unsigned int hwos; unsigned int hwos;
unsigned int model; unsigned int model;
unsigned int serial;
// Cached fields. // Cached fields.
unsigned int cached; unsigned int cached;
unsigned int version; unsigned int version;
@ -127,7 +146,13 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc = {
43, /* salinity */ 43, /* salinity */
47, /* duration */ 47, /* duration */
13, /* temperature */ 13, /* temperature */
34, /* battery volt after dive */
17, /* desat */
32, /* firmware */ 32, /* firmware */
49, /* deco_info1 */
50, /* deco_info1 */
51, /* decomode */
0, /* battery percentage TBD */
}; };
static const hw_ostc_layout_t hw_ostc_layout_frog = { 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 */ 43, /* salinity */
47, /* duration */ 47, /* duration */
19, /* temperature */ 19, /* temperature */
34, /* battery volt after dive */
23, /* desat */
32, /* firmware */ 32, /* firmware */
49, /* deco_info1 */
50, /* deco_info2 */
51, /* decomode */
0, /* battery percentage TBD */
}; };
static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { 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 */ 70, /* salinity */
75, /* duration */ 75, /* duration */
22, /* temperature */ 22, /* temperature */
50, /* battery volt after dive */
26, /* desat */
48, /* firmware */ 48, /* firmware */
77, /* deco_info1 */
78, /* deco_info2 */
79, /* decomode */
59, /* battery percentage */
}; };
static unsigned int 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. // 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_setpoint = data[60];
} }
// Initial CNS // Initial CNS
@ -294,7 +331,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
} }
static dc_status_t 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; 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].oxygen = 0;
parser->gasmix[i].helium = 0; parser->gasmix[i].helium = 0;
} }
parser->serial = serial;
*out = (dc_parser_t *) parser; *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 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 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 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; return DC_STATUS_SUCCESS;
} }
#define BUFLEN 32
static dc_status_t static dc_status_t
hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) 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_gasmix_t *gasmix = (dc_gasmix_t *) value;
dc_salinity_t *water = (dc_salinity_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]; unsigned int salinity = data[layout->salinity];
if (version == 0x23 || version == 0x24) if (version == 0x23 || version == 0x24)
salinity += 100; salinity += 100;
char buf[BUFLEN];
if (value) { if (value) {
switch (type) { 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; return DC_STATUS_UNSUPPORTED;
} }
break; 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: default:
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
} }

View File

@ -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); rc = mares_iconhd_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_HW_OSTC: case DC_FAMILY_HW_OSTC:
rc = hw_ostc_parser_create (&parser, context, 0); rc = hw_ostc_parser_create (&parser, context, serial, 0);
break; break;
case DC_FAMILY_HW_FROG: case DC_FAMILY_HW_FROG:
case DC_FAMILY_HW_OSTC3: case DC_FAMILY_HW_OSTC3:
rc = hw_ostc3_parser_create (&parser, context, model); rc = hw_ostc3_parser_create (&parser, context, serial, model);
break; break;
case DC_FAMILY_CRESSI_EDY: case DC_FAMILY_CRESSI_EDY:
case DC_FAMILY_ZEAGLE_N2ITION3: case DC_FAMILY_ZEAGLE_N2ITION3: