From d8ccfd928bd41908cd902b2aa9cf4f2437d87446 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 22 Mar 2014 07:20:05 +0100 Subject: [PATCH] Cache the gas mix data internally. The gas mix data is used from multiple functions, and the code to parse that data is duplicated in each function. Because this is error prone, the code is moved to a single place, and the data cached in the parser. --- src/suunto_d9_parser.c | 204 +++++++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 89 deletions(-) diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index 4e34f08..f982902 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -31,6 +31,7 @@ #define ISINSTANCE(parser) dc_parser_isinstance((parser), &suunto_d9_parser_vtable) #define MAXPARAMS 3 +#define NGASMIXES 11 #define D9 0x0E #define D6 0x0F @@ -60,6 +61,13 @@ typedef struct suunto_d9_parser_t suunto_d9_parser_t; struct suunto_d9_parser_t { dc_parser_t base; unsigned int model; + // Cached fields. + unsigned int cached; + unsigned int mode; + unsigned int ngasmixes; + unsigned int oxygen[NGASMIXES]; + unsigned int helium[NGASMIXES]; + unsigned int config; }; typedef struct sample_info_t { @@ -85,6 +93,77 @@ static const dc_parser_vtable_t suunto_d9_parser_vtable = { }; +static dc_status_t +suunto_d9_parser_cache (suunto_d9_parser_t *parser) +{ + const unsigned char *data = parser->base.data; + unsigned int size = parser->base.size; + + if (parser->cached) { + return DC_STATUS_SUCCESS; + } + + // Gasmix information. + unsigned int gasmode_offset = 0x19; + unsigned int gasmix_offset = 0x21; + unsigned int gasmix_count = 3; + if (parser->model == HELO2) { + gasmode_offset = 0x1F; + gasmix_offset = 0x54; + gasmix_count = 8; + } else if (parser->model == D4i) { + gasmode_offset = 0x1D; + gasmix_offset = 0x5F; + gasmix_count = 1; + } else if (parser->model == D6i) { + gasmode_offset = 0x1D; + gasmix_offset = 0x5F; + if (data[1] == 0x63) + gasmix_count = 3; + else + gasmix_count = 2; + } else if (parser->model == D9tx) { + gasmode_offset = 0x1D; + gasmix_offset = 0x87; + gasmix_count = 8; + } else if (parser->model == DX) { + gasmode_offset = 0x21; + gasmix_offset = 0xC1; + gasmix_count = 11; + } + + // Offset to the configuration data. + unsigned int config = 0x3A; + if (parser->model == D4) { + config += 1; + } else if (parser->model == HELO2 || parser->model == D4i || + parser->model == D6i || parser->model == D9tx || + parser->model == DX) { + config = gasmix_offset + gasmix_count * 6; + } + if (config + 1 > size) + return DC_STATUS_DATAFORMAT; + + // Cache the data for later use. + parser->mode = data[gasmode_offset]; + parser->ngasmixes = gasmix_count; + for (unsigned int i = 0; i < gasmix_count; ++i) { + if (parser->model == HELO2 || parser->model == D4i || + parser->model == D6i || parser->model == D9tx || + parser->model == DX) { + parser->oxygen[i] = data[gasmix_offset + 6 * i + 1]; + parser->helium[i] = data[gasmix_offset + 6 * i + 2]; + } else { + parser->oxygen[i] = data[gasmix_offset + i]; + parser->helium[i] = 0.0; + } + } + parser->config = config; + parser->cached = 1; + + return DC_STATUS_SUCCESS; +} + dc_status_t suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) { @@ -103,6 +182,14 @@ suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int // Set the default values. parser->model = model; + parser->cached = 0; + parser->mode = AIR; + parser->ngasmixes = 0; + for (unsigned int i = 0; i < NGASMIXES; ++i) { + parser->oxygen[i] = 0; + parser->helium[i] = 0; + } + parser->config = 0; *out = (dc_parser_t*) parser; @@ -123,6 +210,18 @@ suunto_d9_parser_destroy (dc_parser_t *abstract) static dc_status_t suunto_d9_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { + suunto_d9_parser_t *parser = (suunto_d9_parser_t *) abstract; + + // Reset the cache. + parser->cached = 0; + parser->mode = AIR; + parser->ngasmixes = 0; + for (unsigned int i = 0; i < NGASMIXES; ++i) { + parser->oxygen[i] = 0; + parser->helium[i] = 0; + } + parser->config = 0; + return DC_STATUS_SUCCESS; } @@ -174,49 +273,10 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne const unsigned char *data = abstract->data; unsigned int size = abstract->size; - // Gasmix information. - unsigned int gasmix_offset = 0x21, gasmix_count = 3; - if (parser->model == HELO2) { - gasmix_offset = 0x54; - gasmix_count = 8; - } else if (parser->model == D4i) { - gasmix_offset = 0x5F; - gasmix_count = 1; - } else if (parser->model == D6i) { - gasmix_offset = 0x5F; - if (data[1] == 0x63) - gasmix_count = 3; - else - gasmix_count = 2; - } else if (parser->model == D9tx) { - gasmix_offset = 0x87; - gasmix_count = 8; - } else if (parser->model == DX) { - gasmix_offset = 0xC1; - gasmix_count = 11; - } - - // Offset to the configuration data. - unsigned int config = 0x3A; - if (parser->model == D4) { - config += 1; - } else if (parser->model == HELO2 || parser->model == D4i || - parser->model == D6i || parser->model == D9tx || - parser->model == DX) { - config = gasmix_offset + gasmix_count * 6; - } - if (config + 1 > size) - return DC_STATUS_DATAFORMAT; - - // Gas model - unsigned int gasmodel_offset = 0x19; - if (parser->model == HELO2) - gasmodel_offset = 0x1F; - else if (parser->model == D4i || parser->model == D6i || parser->model == D9tx) - gasmodel_offset = 0x1D; - else if (parser->model == DX) - gasmodel_offset = 0x21; - unsigned int gasmodel = data[gasmodel_offset]; + // Cache the gas mix data. + dc_status_t rc = suunto_d9_parser_cache (parser); + if (rc != DC_STATUS_SUCCESS) + return rc; dc_gasmix_t *gasmix = (dc_gasmix_t *) value; @@ -237,24 +297,19 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne *((double *) value) = array_uint16_le (data + 0x09) / 100.0; break; case DC_FIELD_GASMIX_COUNT: - if (gasmodel == AIR) { + if (parser->mode == AIR) { *((unsigned int *) value) = 1; } else { - *((unsigned int *) value) = gasmix_count; + *((unsigned int *) value) = parser->ngasmixes; } break; case DC_FIELD_GASMIX: - if (gasmodel == AIR) { + if (parser->mode == AIR) { gasmix->helium = 0.0; gasmix->oxygen = 0.21; - } else if (parser->model == HELO2 || parser->model == D4i || - parser->model == D6i || parser->model == D9tx || - parser->model == DX) { - gasmix->helium = data[gasmix_offset + 6 * flags + 2] / 100.0; - gasmix->oxygen = data[gasmix_offset + 6 * flags + 1] / 100.0; } else { - gasmix->helium = 0.0; - gasmix->oxygen = data[gasmix_offset + flags] / 100.0; + gasmix->helium = parser->helium[flags] / 100.0; + gasmix->oxygen = parser->oxygen[flags] / 100.0; } gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; @@ -275,42 +330,13 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca const unsigned char *data = abstract->data; unsigned int size = abstract->size; - // Gasmix information. - unsigned int gasmix_offset = 0x21, gasmix_count = 3; - if (parser->model == HELO2) { - gasmix_offset = 0x54; - gasmix_count = 8; - } else if (parser->model == D4i) { - gasmix_offset = 0x5F; - gasmix_count = 1; - } else if (parser->model == D6i) { - gasmix_offset = 0x5F; - if (data[1] == 0x63) - gasmix_count = 3; - else - gasmix_count = 2; - } else if (parser->model == D9tx) { - gasmix_offset = 0x87; - gasmix_count = 8; - } else if (parser->model == DX) { - gasmix_offset = 0xC1; - gasmix_count = 11; - } - - // Offset to the configuration data. - unsigned int config = 0x3A; - if (parser->model == D4) { - config += 1; - } else if (parser->model == HELO2 || parser->model == D4i || - parser->model == D6i || parser->model == D9tx || - parser->model == DX) { - config = gasmix_offset + gasmix_count * 6; - } - if (config + 1 > size) - return DC_STATUS_DATAFORMAT; + // Cache the gas mix data. + dc_status_t rc = suunto_d9_parser_cache (parser); + if (rc != DC_STATUS_SUCCESS) + return rc; // Number of parameters in the configuration data. - unsigned int nparams = data[config]; + unsigned int nparams = data[parser->config]; if (nparams == 0 || nparams > MAXPARAMS) return DC_STATUS_DATAFORMAT; @@ -320,7 +346,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca // Get the sample configuration. sample_info_t info[MAXPARAMS] = {{0}}; for (unsigned int i = 0; i < nparams; ++i) { - unsigned int idx = config + 2 + i * 3; + unsigned int idx = parser->config + 2 + i * 3; info[i].type = data[idx + 0]; info[i].interval = data[idx + 1]; info[i].divisor = divisors[(data[idx + 2] & 0x1C) >> 2]; @@ -338,7 +364,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca } // Offset to the profile data. - unsigned int profile = config + 2 + nparams * 3; + unsigned int profile = parser->config + 2 + nparams * 3; if (profile + 5 > size) return DC_STATUS_DATAFORMAT;