Implement the new field api for the Suunto devices.

This commit is contained in:
Jef Driesen 2010-11-15 21:28:08 +01:00
parent 7c00b1d74e
commit 014f7aa420
4 changed files with 309 additions and 4 deletions

View File

@ -38,6 +38,7 @@ struct suunto_d9_parser_t {
static parser_status_t suunto_d9_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size);
static parser_status_t suunto_d9_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime);
static parser_status_t suunto_d9_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value);
static parser_status_t suunto_d9_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata);
static parser_status_t suunto_d9_parser_destroy (parser_t *abstract);
@ -45,7 +46,7 @@ static const parser_backend_t suunto_d9_parser_backend = {
PARSER_TYPE_SUUNTO_D9,
suunto_d9_parser_set_data, /* set_data */
suunto_d9_parser_get_datetime, /* datetime */
NULL, /* fields */
suunto_d9_parser_get_field, /* fields */
suunto_d9_parser_samples_foreach, /* samples_foreach */
suunto_d9_parser_destroy /* destroy */
};
@ -136,6 +137,64 @@ suunto_d9_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime)
}
static parser_status_t
suunto_d9_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value)
{
suunto_d9_parser_t *parser = (suunto_d9_parser_t*) abstract;
const unsigned char *data = abstract->data;
unsigned int size = abstract->size;
// Offset to the configuration data.
unsigned int config = 0x3E - SKIP;
if (parser->model == 0x12)
config += 1; // D4
if (parser->model == 0x15)
config += 74; // HelO2
if (size < config)
return PARSER_STATUS_ERROR;
gasmix_t *gasmix = (gasmix_t *) value;
if (value) {
switch (type) {
case FIELD_TYPE_DIVETIME:
if (parser->model == 0x12)
*((unsigned int *) value) = array_uint16_le (data + 0x0F - SKIP);
else if (parser->model == 0x15)
*((unsigned int *) value) = array_uint16_le (data + 0x0F - SKIP + 2) * 60;
else
*((unsigned int *) value) = array_uint16_le (data + 0x0F - SKIP) * 60;
break;
case FIELD_TYPE_MAXDEPTH:
*((double *) value) = array_uint16_le (data + 0x0D - SKIP) / 100.0;
break;
case FIELD_TYPE_GASMIX_COUNT:
if (parser->model == 0x15) {
*((unsigned int *) value) = 8;
} else {
*((unsigned int *) value) = 3;
}
break;
case FIELD_TYPE_GASMIX:
if (parser->model == 0x15) {
gasmix->helium = data[0x58 - SKIP + 6 * flags + 2] / 100.0;
gasmix->oxygen = data[0x58 - SKIP + 6 * flags + 1] / 100.0;
} else {
gasmix->helium = 0.0;
gasmix->oxygen = data[0x25 - SKIP + flags] / 100.0;
}
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
break;
default:
return PARSER_STATUS_UNSUPPORTED;
}
}
return PARSER_STATUS_SUCCESS;
}
static parser_status_t
suunto_d9_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata)
{

View File

@ -32,10 +32,15 @@ typedef struct suunto_eon_parser_t suunto_eon_parser_t;
struct suunto_eon_parser_t {
parser_t base;
int spyder;
// Cached fields.
unsigned int cached;
unsigned int divetime;
unsigned int maxdepth;
};
static parser_status_t suunto_eon_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size);
static parser_status_t suunto_eon_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime);
static parser_status_t suunto_eon_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value);
static parser_status_t suunto_eon_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata);
static parser_status_t suunto_eon_parser_destroy (parser_t *abstract);
@ -43,7 +48,7 @@ static const parser_backend_t suunto_eon_parser_backend = {
PARSER_TYPE_SUUNTO_EON,
suunto_eon_parser_set_data, /* set_data */
suunto_eon_parser_get_datetime, /* datetime */
NULL, /* fields */
suunto_eon_parser_get_field, /* fields */
suunto_eon_parser_samples_foreach, /* samples_foreach */
suunto_eon_parser_destroy /* destroy */
};
@ -77,6 +82,9 @@ suunto_eon_parser_create (parser_t **out, int spyder)
// Set the default values.
parser->spyder = spyder;
parser->cached = 0;
parser->divetime = 0;
parser->maxdepth = 0;
*out = (parser_t*) parser;
@ -100,9 +108,16 @@ suunto_eon_parser_destroy (parser_t *abstract)
static parser_status_t
suunto_eon_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size)
{
suunto_eon_parser_t *parser = (suunto_eon_parser_t *) abstract;
if (! parser_is_suunto_eon (abstract))
return PARSER_STATUS_TYPE_MISMATCH;
// Reset the cache.
parser->cached = 0;
parser->divetime = 0;
parser->maxdepth = 0;
return PARSER_STATUS_SUCCESS;
}
@ -138,6 +153,72 @@ suunto_eon_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime)
}
static parser_status_t
suunto_eon_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value)
{
suunto_eon_parser_t *parser = (suunto_eon_parser_t *) abstract;
const unsigned char *data = abstract->data;
unsigned int size = abstract->size;
if (size < 13)
return PARSER_STATUS_ERROR;
if (!parser->cached) {
unsigned int interval = data[3];
unsigned int nsamples = 0;
unsigned int depth = 0, maxdepth = 0;
unsigned int offset = 11;
while (offset < size && data[offset] != 0x80) {
unsigned char value = data[offset++];
if (value < 0x7d || value > 0x82) {
depth += (signed char) value;
if (depth > maxdepth)
maxdepth = depth;
nsamples++;
}
}
// Store the offset to the end marker.
unsigned int marker = offset;
if (marker + 2 >= size || data[marker] != 0x80)
return PARSER_STATUS_ERROR;
parser->cached = 1;
parser->divetime = nsamples * interval;
parser->maxdepth = maxdepth;
}
gasmix_t *gasmix = (gasmix_t *) value;
if (value) {
switch (type) {
case FIELD_TYPE_DIVETIME:
*((unsigned int *) value) = parser->divetime;
break;
case FIELD_TYPE_MAXDEPTH:
*((double *) value) = parser->maxdepth * FEET;
break;
case FIELD_TYPE_GASMIX_COUNT:
*((unsigned int *) value) = 1;
break;
case FIELD_TYPE_GASMIX:
gasmix->helium = 0.0;
if ((data[4] & 0x80) && !parser->spyder)
gasmix->oxygen = data[0x05] / 100.0;
else
gasmix->oxygen = 0.21;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
break;
default:
return PARSER_STATUS_UNSUPPORTED;
}
}
return PARSER_STATUS_SUCCESS;
}
static parser_status_t
suunto_eon_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata)
{

View File

@ -30,9 +30,14 @@ typedef struct suunto_solution_parser_t suunto_solution_parser_t;
struct suunto_solution_parser_t {
parser_t base;
// Cached fields.
unsigned int cached;
unsigned int divetime;
unsigned int maxdepth;
};
static parser_status_t suunto_solution_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size);
static parser_status_t suunto_solution_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value);
static parser_status_t suunto_solution_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata);
static parser_status_t suunto_solution_parser_destroy (parser_t *abstract);
@ -40,7 +45,7 @@ static const parser_backend_t suunto_solution_parser_backend = {
PARSER_TYPE_SUUNTO_SOLUTION,
suunto_solution_parser_set_data, /* set_data */
NULL, /* datetime */
NULL, /* fields */
suunto_solution_parser_get_field, /* fields */
suunto_solution_parser_samples_foreach, /* samples_foreach */
suunto_solution_parser_destroy /* destroy */
};
@ -72,6 +77,11 @@ suunto_solution_parser_create (parser_t **out)
// Initialize the base class.
parser_init (&parser->base, &suunto_solution_parser_backend);
// Set the default values.
parser->cached = 0;
parser->divetime = 0;
parser->maxdepth = 0;
*out = (parser_t*) parser;
return PARSER_STATUS_SUCCESS;
@ -94,13 +104,86 @@ suunto_solution_parser_destroy (parser_t *abstract)
static parser_status_t
suunto_solution_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size)
{
suunto_solution_parser_t *parser = (suunto_solution_parser_t *) abstract;
if (! parser_is_suunto_solution (abstract))
return PARSER_STATUS_TYPE_MISMATCH;
// Reset the cache.
parser->cached = 0;
parser->divetime = 0;
parser->maxdepth = 0;
return PARSER_STATUS_SUCCESS;
}
static parser_status_t
suunto_solution_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value)
{
suunto_solution_parser_t *parser = (suunto_solution_parser_t *) abstract;
const unsigned char *data = abstract->data;
unsigned int size = abstract->size;
if (size < 4)
return PARSER_STATUS_ERROR;
if (!parser->cached) {
unsigned int nsamples = 0;
unsigned int depth = 0, maxdepth = 0;
unsigned int offset = 3;
while (offset < size && data[offset] != 0x80) {
unsigned char value = data[offset++];
if (value < 0x7e || value > 0x82) {
depth += (signed char) value;
if (value == 0x7D || value == 0x83) {
if (offset + 1 > size)
return PARSER_STATUS_ERROR;
depth += (signed char) data[offset++];
}
if (depth > maxdepth)
maxdepth = depth;
nsamples++;
}
}
// Store the offset to the end marker.
unsigned int marker = offset;
if (marker + 1 >= size || data[marker] != 0x80)
return PARSER_STATUS_ERROR;
parser->cached = 1;
parser->divetime = (nsamples * 3 + data[marker + 1]) * 60;
parser->maxdepth = maxdepth;
}
gasmix_t *gasmix = (gasmix_t *) value;
if (value) {
switch (type) {
case FIELD_TYPE_DIVETIME:
*((unsigned int *) value) = parser->divetime;
break;
case FIELD_TYPE_MAXDEPTH:
*((double *) value) = parser->maxdepth * FEET;
break;
case FIELD_TYPE_GASMIX_COUNT:
*((unsigned int *) value) = 1;
break;
case FIELD_TYPE_GASMIX:
gasmix->helium = 0.0;
gasmix->oxygen = 0.21;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
break;
default:
return PARSER_STATUS_UNSUPPORTED;
}
}
return PARSER_STATUS_SUCCESS;
}
static parser_status_t
suunto_solution_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata)
{

View File

@ -30,10 +30,15 @@ typedef struct suunto_vyper_parser_t suunto_vyper_parser_t;
struct suunto_vyper_parser_t {
parser_t base;
// Cached fields.
unsigned int cached;
unsigned int divetime;
unsigned int maxdepth;
};
static parser_status_t suunto_vyper_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size);
static parser_status_t suunto_vyper_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime);
static parser_status_t suunto_vyper_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value);
static parser_status_t suunto_vyper_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata);
static parser_status_t suunto_vyper_parser_destroy (parser_t *abstract);
@ -41,7 +46,7 @@ static const parser_backend_t suunto_vyper_parser_backend = {
PARSER_TYPE_SUUNTO_VYPER,
suunto_vyper_parser_set_data, /* set_data */
suunto_vyper_parser_get_datetime, /* datetime */
NULL, /* fields */
suunto_vyper_parser_get_field, /* fields */
suunto_vyper_parser_samples_foreach, /* samples_foreach */
suunto_vyper_parser_destroy /* destroy */
};
@ -73,6 +78,11 @@ suunto_vyper_parser_create (parser_t **out)
// Initialize the base class.
parser_init (&parser->base, &suunto_vyper_parser_backend);
// Set the default values.
parser->cached = 0;
parser->divetime = 0;
parser->maxdepth = 0;
*out = (parser_t*) parser;
return PARSER_STATUS_SUCCESS;
@ -95,9 +105,16 @@ suunto_vyper_parser_destroy (parser_t *abstract)
static parser_status_t
suunto_vyper_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size)
{
suunto_vyper_parser_t *parser = (suunto_vyper_parser_t *) abstract;
if (! parser_is_suunto_vyper (abstract))
return PARSER_STATUS_TYPE_MISMATCH;
// Reset the cache.
parser->cached = 0;
parser->divetime = 0;
parser->maxdepth = 0;
return PARSER_STATUS_SUCCESS;
}
@ -123,6 +140,71 @@ suunto_vyper_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime)
}
static parser_status_t
suunto_vyper_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value)
{
suunto_vyper_parser_t *parser = (suunto_vyper_parser_t *) abstract;
const unsigned char *data = abstract->data;
unsigned int size = abstract->size;
if (size < 18)
return PARSER_STATUS_ERROR;
if (!parser->cached) {
unsigned int interval = data[3];
unsigned int nsamples = 0;
unsigned int depth = 0, maxdepth = 0;
unsigned int offset = 14;
while (offset < size && data[offset] != 0x80) {
unsigned char value = data[offset++];
if (value < 0x79 || value > 0x87) {
depth += (signed char) value;
if (depth > maxdepth)
maxdepth = depth;
nsamples++;
}
}
// Store the offset to the end marker.
unsigned int marker = offset;
if (marker + 4 >= size || data[marker] != 0x80)
return PARSER_STATUS_ERROR;
parser->cached = 1;
parser->divetime = nsamples * interval;
parser->maxdepth = maxdepth;
}
gasmix_t *gas = (gasmix_t *) value;
if (value) {
switch (type) {
case FIELD_TYPE_DIVETIME:
*((unsigned int *) value) = parser->divetime;
break;
case FIELD_TYPE_MAXDEPTH:
*((double *) value) = parser->maxdepth * FEET;
break;
case FIELD_TYPE_GASMIX_COUNT:
*((unsigned int *) value) = 1;
break;
case FIELD_TYPE_GASMIX:
gas->helium = 0.0;
if (data[6])
gas->oxygen = data[6] / 100.0;
else
gas->oxygen = 0.21;
gas->nitrogen = 1.0 - gas->oxygen;
break;
default:
return PARSER_STATUS_UNSUPPORTED;
}
}
return PARSER_STATUS_SUCCESS;
}
static parser_status_t
suunto_vyper_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata)
{