diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 46c29b1..f1647c6 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -46,10 +46,15 @@ typedef struct oceanic_atom2_parser_t oceanic_atom2_parser_t; struct oceanic_atom2_parser_t { parser_t base; unsigned int model; + // Cached fields. + unsigned int cached; + unsigned int divetime; + double maxdepth; }; static parser_status_t oceanic_atom2_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size); static parser_status_t oceanic_atom2_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime); +static parser_status_t oceanic_atom2_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value); static parser_status_t oceanic_atom2_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata); static parser_status_t oceanic_atom2_parser_destroy (parser_t *abstract); @@ -57,7 +62,7 @@ static const parser_backend_t oceanic_atom2_parser_backend = { PARSER_TYPE_OCEANIC_ATOM2, oceanic_atom2_parser_set_data, /* set_data */ oceanic_atom2_parser_get_datetime, /* datetime */ - NULL, /* fields */ + oceanic_atom2_parser_get_field, /* fields */ oceanic_atom2_parser_samples_foreach, /* samples_foreach */ oceanic_atom2_parser_destroy /* destroy */ }; @@ -91,6 +96,9 @@ oceanic_atom2_parser_create (parser_t **out, unsigned int model) // Set the default values. parser->model = model; + parser->cached = 0; + parser->divetime = 0; + parser->maxdepth = 0.0; *out = (parser_t*) parser; @@ -114,9 +122,16 @@ oceanic_atom2_parser_destroy (parser_t *abstract) static parser_status_t oceanic_atom2_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size) { + oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) abstract; + if (! parser_is_oceanic_atom2 (abstract)) return PARSER_STATUS_TYPE_MISMATCH; + // Reset the cache. + parser->cached = 0; + parser->divetime = 0; + parser->maxdepth = 0.0; + return PARSER_STATUS_SUCCESS; } @@ -208,6 +223,76 @@ oceanic_atom2_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime) } +static parser_status_t +oceanic_atom2_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value) +{ + oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) abstract; + + const unsigned char *data = abstract->data; + unsigned int size = abstract->size; + + unsigned int length = 11 * PAGESIZE / 2; + unsigned int header = 4 * PAGESIZE; + unsigned int footer = size - PAGESIZE; + if (parser->model == GEO || parser->model == DATAMASK || + parser->model == GEO20 || parser->model == VEO20 || + parser->model == VEO30) + { + length -= PAGESIZE; + header -= PAGESIZE; + } + + if (size < length) + return PARSER_STATUS_ERROR; + + if (!parser->cached) { + sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER; + parser_status_t rc = oceanic_atom2_parser_samples_foreach ( + abstract, sample_statistics_cb, &statistics); + if (rc != PARSER_STATUS_SUCCESS) + return rc; + + parser->cached = 1; + parser->divetime = statistics.divetime; + parser->maxdepth = statistics.maxdepth; + } + + gasmix_t *gasmix = (gasmix_t *) value; + + unsigned int nitrox = 0; + + if (value) { + switch (type) { + case FIELD_TYPE_DIVETIME: + *((unsigned int *) value) = parser->divetime; + break; + case FIELD_TYPE_MAXDEPTH: + *((double *) value) = array_uint16_le (data + footer + 4) / 16.0 * FEET; + break; + case FIELD_TYPE_GASMIX_COUNT: + if (parser->model == DATAMASK) + *((unsigned int *) value) = 1; + else + *((unsigned int *) value) = 3; + break; + case FIELD_TYPE_GASMIX: + if (parser->model == DATAMASK) + nitrox = data[header + 3]; + else + nitrox = data[header + 4 + flags]; + gasmix->helium = 0.0; + gasmix->oxygen = (nitrox ? nitrox / 100.0 : 0.21); + gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; + break; + default: + return PARSER_STATUS_UNSUPPORTED; + } + } + + return PARSER_STATUS_SUCCESS; +} + + static parser_status_t oceanic_atom2_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata) { diff --git a/src/oceanic_veo250_parser.c b/src/oceanic_veo250_parser.c index 5217249..0986c6b 100644 --- a/src/oceanic_veo250_parser.c +++ b/src/oceanic_veo250_parser.c @@ -33,10 +33,15 @@ typedef struct oceanic_veo250_parser_t oceanic_veo250_parser_t; struct oceanic_veo250_parser_t { parser_t base; unsigned int model; + // Cached fields. + unsigned int cached; + unsigned int divetime; + double maxdepth; }; static parser_status_t oceanic_veo250_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size); static parser_status_t oceanic_veo250_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime); +static parser_status_t oceanic_veo250_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value); static parser_status_t oceanic_veo250_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata); static parser_status_t oceanic_veo250_parser_destroy (parser_t *abstract); @@ -44,7 +49,7 @@ static const parser_backend_t oceanic_veo250_parser_backend = { PARSER_TYPE_OCEANIC_VEO250, oceanic_veo250_parser_set_data, /* set_data */ oceanic_veo250_parser_get_datetime, /* datetime */ - NULL, /* fields */ + oceanic_veo250_parser_get_field, /* fields */ oceanic_veo250_parser_samples_foreach, /* samples_foreach */ oceanic_veo250_parser_destroy /* destroy */ }; @@ -78,6 +83,9 @@ oceanic_veo250_parser_create (parser_t **out, unsigned int model) // Set the default values. parser->model = model; + parser->cached = 0; + parser->divetime = 0; + parser->maxdepth = 0.0; *out = (parser_t*) parser; @@ -101,9 +109,16 @@ oceanic_veo250_parser_destroy (parser_t *abstract) static parser_status_t oceanic_veo250_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size) { + oceanic_veo250_parser_t *parser = (oceanic_veo250_parser_t *) abstract; + if (! parser_is_oceanic_veo250 (abstract)) return PARSER_STATUS_TYPE_MISMATCH; + // Reset the cache. + parser->cached = 0; + parser->divetime = 0; + parser->maxdepth = 0.0; + return PARSER_STATUS_SUCCESS; } @@ -133,6 +148,62 @@ oceanic_veo250_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime) return PARSER_STATUS_SUCCESS; } + +static parser_status_t +oceanic_veo250_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value) +{ + oceanic_veo250_parser_t *parser = (oceanic_veo250_parser_t *) abstract; + + const unsigned char *data = abstract->data; + unsigned int size = abstract->size; + + if (size < 7 * PAGESIZE / 2) + return PARSER_STATUS_ERROR; + + if (!parser->cached) { + sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER; + parser_status_t rc = oceanic_veo250_parser_samples_foreach ( + abstract, sample_statistics_cb, &statistics); + if (rc != PARSER_STATUS_SUCCESS) + return rc; + + parser->cached = 1; + parser->divetime = statistics.divetime; + parser->maxdepth = statistics.maxdepth; + } + + unsigned int footer = size - PAGESIZE; + + gasmix_t *gasmix = (gasmix_t *) value; + + if (value) { + switch (type) { + case FIELD_TYPE_DIVETIME: + *((unsigned int *) value) = data[footer + 3] * 60; + break; + case FIELD_TYPE_MAXDEPTH: + *((double *) value) = parser->maxdepth; + break; + case FIELD_TYPE_GASMIX_COUNT: + *((unsigned int *) value) = 1; + break; + case FIELD_TYPE_GASMIX: + gasmix->helium = 0.0; + if (data[footer + 6]) + gasmix->oxygen = data[footer + 6] / 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 oceanic_veo250_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata) { diff --git a/src/oceanic_vtpro_parser.c b/src/oceanic_vtpro_parser.c index 306fc2a..ab5c77d 100644 --- a/src/oceanic_vtpro_parser.c +++ b/src/oceanic_vtpro_parser.c @@ -32,10 +32,15 @@ typedef struct oceanic_vtpro_parser_t oceanic_vtpro_parser_t; struct oceanic_vtpro_parser_t { parser_t base; + // Cached fields. + unsigned int cached; + unsigned int divetime; + double maxdepth; }; static parser_status_t oceanic_vtpro_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size); static parser_status_t oceanic_vtpro_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime); +static parser_status_t oceanic_vtpro_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value); static parser_status_t oceanic_vtpro_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata); static parser_status_t oceanic_vtpro_parser_destroy (parser_t *abstract); @@ -43,7 +48,7 @@ static const parser_backend_t oceanic_vtpro_parser_backend = { PARSER_TYPE_OCEANIC_VTPRO, oceanic_vtpro_parser_set_data, /* set_data */ oceanic_vtpro_parser_get_datetime, /* datetime */ - NULL, /* fields */ + oceanic_vtpro_parser_get_field, /* fields */ oceanic_vtpro_parser_samples_foreach, /* samples_foreach */ oceanic_vtpro_parser_destroy /* destroy */ }; @@ -75,6 +80,11 @@ oceanic_vtpro_parser_create (parser_t **out) // Initialize the base class. parser_init (&parser->base, &oceanic_vtpro_parser_backend); + // Set the default values. + parser->cached = 0; + parser->divetime = 0; + parser->maxdepth = 0.0; + *out = (parser_t*) parser; return PARSER_STATUS_SUCCESS; @@ -97,9 +107,16 @@ oceanic_vtpro_parser_destroy (parser_t *abstract) static parser_status_t oceanic_vtpro_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size) { + oceanic_vtpro_parser_t *parser = (oceanic_vtpro_parser_t *) abstract; + if (! parser_is_oceanic_vtpro (abstract)) return PARSER_STATUS_TYPE_MISMATCH; + // Reset the cache. + parser->cached = 0; + parser->divetime = 0; + parser->maxdepth = 0.0; + return PARSER_STATUS_SUCCESS; } @@ -135,6 +152,61 @@ oceanic_vtpro_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime) } +static parser_status_t +oceanic_vtpro_parser_get_field (parser_t *abstract, parser_field_type_t type, unsigned int flags, void *value) +{ + oceanic_vtpro_parser_t *parser = (oceanic_vtpro_parser_t *) abstract; + + const unsigned char *data = abstract->data; + unsigned int size = abstract->size; + + if (size < 7 * PAGESIZE / 2) + return PARSER_STATUS_ERROR; + + if (!parser->cached) { + sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER; + parser_status_t rc = oceanic_vtpro_parser_samples_foreach ( + abstract, sample_statistics_cb, &statistics); + if (rc != PARSER_STATUS_SUCCESS) + return rc; + + parser->cached = 1; + parser->divetime = statistics.divetime; + parser->maxdepth = statistics.maxdepth; + } + + unsigned int footer = size - PAGESIZE; + + 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) = (data[footer + 0] + ((data[footer + 1] & 0x0F) << 8)) * 1; + break; + case FIELD_TYPE_GASMIX_COUNT: + *((unsigned int *) value) = 1; + break; + case FIELD_TYPE_GASMIX: + gasmix->helium = 0.0; + if (data[footer + 3]) + gasmix->oxygen = data[footer + 3] / 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 oceanic_vtpro_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata) { diff --git a/src/parser-private.h b/src/parser-private.h index 86c70d8..ab57a43 100644 --- a/src/parser-private.h +++ b/src/parser-private.h @@ -56,6 +56,16 @@ struct parser_backend_t { void parser_init (parser_t *parser, const parser_backend_t *backend); +typedef struct sample_statistics_t { + unsigned int divetime; + double maxdepth; +} sample_statistics_t; + +#define SAMPLE_STATISTICS_INITIALIZER {0, 0.0} + +void +sample_statistics_cb (parser_sample_type_t type, parser_sample_value_t value, void *userdata); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/parser.c b/src/parser.c index 96e80a4..0f0c7d7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -108,3 +108,22 @@ parser_destroy (parser_t *parser) return parser->backend->destroy (parser); } + + +void +sample_statistics_cb (parser_sample_type_t type, parser_sample_value_t value, void *userdata) +{ + sample_statistics_t *statistics = (sample_statistics_t *) userdata; + + switch (type) { + case SAMPLE_TYPE_TIME: + statistics->divetime = value.time; + break; + case SAMPLE_TYPE_DEPTH: + if (statistics->maxdepth < value.depth) + statistics->maxdepth = value.depth; + break; + default: + break; + } +}