From b17f432635f883dcd35ae04c46c2d6eaa008c31f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 4 Jun 2015 14:31:45 +0200 Subject: [PATCH 1/4] Fix the logic to skip disabled gas mixes. Originally I assumed it's not possible to enable a gas mix if the previous gas mix has already been disabled. However, this assumption turns out to be wrong. For devices with support for 3 gas mixes, it's possible to enable only the first and the third gas mix, and leave the second gas mix disabled. This is fixed by checking all gas mixes, instead of aborting once the first disabled gas mix has been found. Due to this change the uwatec gas mix id's are no longer sequential and need to remapped to the corresponding internal array index. --- src/uwatec_smart_parser.c | 110 ++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 664f635..d72ff1a 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -90,9 +90,16 @@ typedef struct uwatec_smart_sample_info_t { unsigned int extrabytes; } uwatec_smart_sample_info_t; +typedef struct uwatec_smart_gasmix_t { + unsigned int id; + unsigned int oxygen; +} uwatec_smart_gasmix_t; + typedef struct uwatec_smart_tank_t { + unsigned int id; unsigned int beginpressure; unsigned int endpressure; + unsigned int gasmix; } uwatec_smart_tank_t; typedef struct uwatec_smart_parser_t uwatec_smart_parser_t; @@ -110,7 +117,7 @@ struct uwatec_smart_parser_t { unsigned int cached; unsigned int trimix; unsigned int ngasmixes; - unsigned int oxygen[NGASMIXES]; + uwatec_smart_gasmix_t gasmix[NGASMIXES]; unsigned int ntanks; uwatec_smart_tank_t tank[NGASMIXES]; dc_water_t watertype; @@ -293,6 +300,20 @@ uwatec_smart_sample_info_t uwatec_smart_tec_samples[] = { }; +static unsigned int +uwatec_smart_find_gasmix (uwatec_smart_parser_t *parser, unsigned int id) +{ + unsigned int i = 0; + while (i < parser->ngasmixes) { + if (id == parser->gasmix[i].id) + break; + i++; + } + + return i; +} + + static dc_status_t uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) { @@ -314,42 +335,45 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) } } - // Get the gas mixes. - unsigned int ngasmixes = 0; - unsigned int oxygen[NGASMIXES] = {0}; - if (!trimix) { - for (unsigned int i = 0; i < parser->header->ngases; ++i) { - unsigned int o2 = data[parser->header->gasmix + i * 2]; - if (o2 == 0) - break; // Skip disabled gas mixes. - oxygen[ngasmixes] = o2; - ngasmixes++; - } - } - - // Get the tanks. + // Get the gas mixes and tanks. unsigned int ntanks = 0; + unsigned int ngasmixes = 0; uwatec_smart_tank_t tank[NGASMIXES] = {{0}}; - if (!trimix && header->tankpressure != UNSUPPORTED) { + uwatec_smart_gasmix_t gasmix[NGASMIXES] = {{0}}; + if (!trimix) { for (unsigned int i = 0; i < header->ngases; ++i) { + unsigned int idx = DC_GASMIX_UNKNOWN; + + unsigned int o2 = data[header->gasmix + i * 2]; + if (o2 != 0) { + idx = ngasmixes; + gasmix[ngasmixes].id = i; + gasmix[ngasmixes].oxygen = o2; + ngasmixes++; + } + unsigned int beginpressure = 0; unsigned int endpressure = 0; - if (parser->model == GALILEO || parser->model == GALILEOTRIMIX || - parser->model == ALADIN2G || parser->model == MERIDIAN || - parser->model == CHROMIS) { - unsigned int idx = header->tankpressure + 2 * i; - endpressure = array_uint16_le(data + idx); - beginpressure = array_uint16_le(data + idx + 2 * header->ngases); - } else { - unsigned int idx = header->tankpressure + 4 * i; - beginpressure = array_uint16_le(data + idx); - endpressure = array_uint16_le(data + idx + 2); + if (header->tankpressure != UNSUPPORTED) { + if (parser->model == GALILEO || parser->model == GALILEOTRIMIX || + parser->model == ALADIN2G || parser->model == MERIDIAN || + parser->model == CHROMIS) { + unsigned int offset = header->tankpressure + 2 * i; + endpressure = array_uint16_le(data + offset); + beginpressure = array_uint16_le(data + offset + 2 * header->ngases); + } else { + unsigned int offset = header->tankpressure + 4 * i; + beginpressure = array_uint16_le(data + offset); + endpressure = array_uint16_le(data + offset + 2); + } + } + if (beginpressure != 0 || endpressure != 0) { + tank[ntanks].id = i; + tank[ntanks].beginpressure = beginpressure; + tank[ntanks].endpressure = endpressure; + tank[ntanks].gasmix = idx; + ntanks++; } - if (beginpressure == 0 && endpressure == 0) - break; // Skip unused tanks. - tank[ntanks].beginpressure = beginpressure; - tank[ntanks].endpressure = endpressure; - ntanks++; } } @@ -365,7 +389,7 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) parser->trimix = trimix; parser->ngasmixes = ngasmixes; for (unsigned int i = 0; i < ngasmixes; ++i) { - parser->oxygen[i] = oxygen[i]; + parser->gasmix[i] = gasmix[i]; } parser->ntanks = ntanks; for (unsigned int i = 0; i < ntanks; ++i) { @@ -450,9 +474,12 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i parser->ngasmixes = 0; parser->ntanks = 0; for (unsigned int i = 0; i < NGASMIXES; ++i) { - parser->oxygen[i] = 0; + parser->gasmix[i].id = 0; + parser->gasmix[i].oxygen = 0; + parser->tank[i].id = 0; parser->tank[i].beginpressure = 0; parser->tank[i].endpressure = 0; + parser->tank[i].gasmix = 0; } parser->watertype = DC_WATER_FRESH; @@ -483,9 +510,12 @@ uwatec_smart_parser_set_data (dc_parser_t *abstract, const unsigned char *data, parser->ngasmixes = 0; parser->ntanks = 0; for (unsigned int i = 0; i < NGASMIXES; ++i) { - parser->oxygen[i] = 0; + parser->gasmix[i].id = 0; + parser->gasmix[i].oxygen = 0; + parser->tank[i].id = 0; parser->tank[i].beginpressure = 0; parser->tank[i].endpressure = 0; + parser->tank[i].gasmix = 0; } parser->watertype = DC_WATER_FRESH; @@ -564,7 +594,7 @@ uwatec_smart_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi if (parser->trimix) return DC_STATUS_UNSUPPORTED; gasmix->helium = 0.0; - gasmix->oxygen = parser->oxygen[flags] / 100.0; + gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; case DC_FIELD_TANK_COUNT: @@ -578,12 +608,9 @@ uwatec_smart_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi tank->type = DC_TANKVOLUME_NONE; tank->volume = 0.0; tank->workpressure = 0.0; - if (flags < parser->ngasmixes) - tank->gasmix = flags; - else - tank->gasmix = DC_GASMIX_UNKNOWN; tank->beginpressure = parser->tank[flags].beginpressure / 128.0; tank->endpressure = parser->tank[flags].endpressure / 128.0; + tank->gasmix = parser->tank[flags].gasmix; break; case DC_FIELD_TEMPERATURE_MINIMUM: *((double *) value) = (signed short) array_uint16_le (data + table->temp_minimum) / 10.0; @@ -885,14 +912,15 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t if (callback) callback (DC_SAMPLE_TIME, sample, userdata); if (parser->ngasmixes && gasmix != gasmix_previous) { - if (gasmix >= parser->ngasmixes) { + unsigned int idx = uwatec_smart_find_gasmix (parser, gasmix); + if (idx >= parser->ngasmixes) { ERROR (abstract->context, "Invalid gas mix index."); return DC_STATUS_DATAFORMAT; } sample.event.type = SAMPLE_EVENT_GASCHANGE; sample.event.time = 0; sample.event.flags = 0; - sample.event.value = parser->oxygen[gasmix]; + sample.event.value = parser->gasmix[idx].oxygen; if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); gasmix_previous = gasmix; } From 82c1a55a13780aadf7d08e1f5a0d5d6994eaef35 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 4 Jun 2015 21:07:13 +0200 Subject: [PATCH 2/4] Fix the gas switches for galileo devices. The bitmask for the gas mix bits was wrong. With the new mask we also no longer have to disable the alarm based gas switches for the Meridian and Chromis. --- src/uwatec_smart_parser.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index d72ff1a..163476d 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -880,8 +880,10 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t alarms[table[id].index] = value; have_alarms = 1; if (table[id].index == 1) { - if (parser->model != MERIDIAN && parser->model != CHROMIS) { + if (parser->model == ALADINTEC || parser->model == ALADINTEC2G) { gasmix = (value & 0x30) >> 4; + } else { + gasmix = (value & 0x60) >> 5; } } break; From 7f3cea691dc64ec3d95fce8440114598d3afcce6 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 4 Jun 2015 22:24:29 +0200 Subject: [PATCH 3/4] Use a fixed id for the uwatec deco mix. The id of the uwatec deco mix is always 2, even for devices which support maximum two gas mixes. Strictly speaking, this change is more correct than commit 4fd825cdac341a2d4a1366c6deb7d4a71bbdf94d, allthough in practice they are equivalent. --- src/uwatec_smart_parser.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 163476d..ee6be1e 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -342,12 +342,17 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) uwatec_smart_gasmix_t gasmix[NGASMIXES] = {{0}}; if (!trimix) { for (unsigned int i = 0; i < header->ngases; ++i) { + unsigned int id = i; + if (id > 0 && header->ngases == 2) { + id++; // Remap the id of the deco mix. + } + unsigned int idx = DC_GASMIX_UNKNOWN; unsigned int o2 = data[header->gasmix + i * 2]; if (o2 != 0) { idx = ngasmixes; - gasmix[ngasmixes].id = i; + gasmix[ngasmixes].id = id; gasmix[ngasmixes].oxygen = o2; ngasmixes++; } @@ -368,7 +373,7 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) } } if (beginpressure != 0 || endpressure != 0) { - tank[ntanks].id = i; + tank[ntanks].id = id; tank[ntanks].beginpressure = beginpressure; tank[ntanks].endpressure = endpressure; tank[ntanks].gasmix = idx; @@ -881,7 +886,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t have_alarms = 1; if (table[id].index == 1) { if (parser->model == ALADINTEC || parser->model == ALADINTEC2G) { - gasmix = (value & 0x30) >> 4; + gasmix = (value & 0x18) >> 3; } else { gasmix = (value & 0x60) >> 5; } From 701b93d86568c2fb1e9a389cb8a906241f5534bb Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 7 Jun 2015 10:28:04 +0200 Subject: [PATCH 4/4] Add support for the Galileo Trimix. For the trimix version, the gasmix and tank information is no longer stored in the header. It's now stored in a special sample at the end of the dive. --- src/uwatec_smart_parser.c | 94 ++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index ee6be1e..622a4f7 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -49,7 +49,10 @@ #define UNSUPPORTED 0xFFFFFFFF -#define NGASMIXES 3 +#define NGASMIXES 10 + +#define HEADER 1 +#define PROFILE 2 #define FRESH 1.000 #define SALT 1.025 @@ -93,6 +96,7 @@ typedef struct uwatec_smart_sample_info_t { typedef struct uwatec_smart_gasmix_t { unsigned int id; unsigned int oxygen; + unsigned int helium; } uwatec_smart_gasmix_t; typedef struct uwatec_smart_tank_t { @@ -313,6 +317,18 @@ uwatec_smart_find_gasmix (uwatec_smart_parser_t *parser, unsigned int id) return i; } +static unsigned int +uwatec_smart_find_tank (uwatec_smart_parser_t *parser, unsigned int id) +{ + unsigned int i = 0; + while (i < parser->ntanks) { + if (id == parser->tank[i].id) + break; + i++; + } + + return i; +} static dc_status_t uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) @@ -354,6 +370,7 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) idx = ngasmixes; gasmix[ngasmixes].id = id; gasmix[ngasmixes].oxygen = o2; + gasmix[ngasmixes].helium = 0; ngasmixes++; } @@ -401,7 +418,7 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) parser->tank[i] = tank[i]; } parser->watertype = watertype; - parser->cached = 1; + parser->cached = HEADER; return DC_STATUS_SUCCESS; } @@ -481,6 +498,7 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i for (unsigned int i = 0; i < NGASMIXES; ++i) { parser->gasmix[i].id = 0; parser->gasmix[i].oxygen = 0; + parser->gasmix[i].helium = 0; parser->tank[i].id = 0; parser->tank[i].beginpressure = 0; parser->tank[i].endpressure = 0; @@ -517,6 +535,7 @@ uwatec_smart_parser_set_data (dc_parser_t *abstract, const unsigned char *data, for (unsigned int i = 0; i < NGASMIXES; ++i) { parser->gasmix[i].id = 0; parser->gasmix[i].oxygen = 0; + parser->gasmix[i].helium = 0; parser->tank[i].id = 0; parser->tank[i].beginpressure = 0; parser->tank[i].endpressure = 0; @@ -576,6 +595,13 @@ uwatec_smart_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi if (rc != DC_STATUS_SUCCESS) return rc; + // Cache the profile data. + if (parser->cached < PROFILE) { + rc = uwatec_smart_parser_samples_foreach (abstract, NULL, NULL); + if (rc != DC_STATUS_SUCCESS) + return rc; + } + double salinity = (parser->watertype == DC_WATER_SALT ? SALT : FRESH); dc_gasmix_t *gasmix = (dc_gasmix_t *) value; @@ -591,24 +617,20 @@ uwatec_smart_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = array_uint16_le (data + table->maxdepth) / 100.0 * salinity; break; case DC_FIELD_GASMIX_COUNT: - if (parser->trimix) - return DC_STATUS_UNSUPPORTED; *((unsigned int *) value) = parser->ngasmixes; break; case DC_FIELD_GASMIX: - if (parser->trimix) - return DC_STATUS_UNSUPPORTED; - gasmix->helium = 0.0; + gasmix->helium = parser->gasmix[flags].helium / 100.0; gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; case DC_FIELD_TANK_COUNT: - if (parser->trimix || table->tankpressure == UNSUPPORTED) + if (table->tankpressure == UNSUPPORTED) return DC_STATUS_UNSUPPORTED; *((unsigned int *) value) = parser->ntanks; break; case DC_FIELD_TANK: - if (parser->trimix || table->tankpressure == UNSUPPORTED) + if (table->tankpressure == UNSUPPORTED) return DC_STATUS_UNSUPPORTED; tank->type = DC_TANKVOLUME_NONE; tank->volume = 0.0; @@ -819,6 +841,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t signed int svalue = uwatec_smart_fixsignbit (value, nbits); // Parse the value. + unsigned int subtype = 0; switch (table[id].type) { case PRESSURE_DEPTH: pressure += ((signed char) ((svalue >> NBITS) & 0xFF)) / 4.0; @@ -907,6 +930,51 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ERROR (abstract->context, "Incomplete sample data."); return DC_STATUS_DATAFORMAT; } + + subtype = data[offset]; + if (subtype >= 32 && subtype <= 41) { + if (value < 16) { + ERROR (abstract->context, "Incomplete sample data."); + return DC_STATUS_DATAFORMAT; + } + unsigned int mixid = subtype - 32; + unsigned int mixidx = DC_GASMIX_UNKNOWN; + unsigned int o2 = array_uint16_le (data + offset + 1); + unsigned int he = array_uint16_le (data + offset + 3); + unsigned int beginpressure = array_uint16_le (data + offset + 5); + unsigned int endpressure = array_uint16_le (data + offset + 7); + + if (o2 != 0 || he != 0) { + unsigned int idx = uwatec_smart_find_gasmix (parser, mixid); + if (idx >= parser->ngasmixes) { + if (idx >= NGASMIXES) { + ERROR (abstract->context, "Maximum number of gas mixes reached."); + return DC_STATUS_NOMEMORY; + } + parser->gasmix[idx].id = mixid; + parser->gasmix[idx].oxygen = o2; + parser->gasmix[idx].helium = he; + parser->ngasmixes++; + } + mixidx = idx; + } + + if (beginpressure != 0 || endpressure != 0) { + unsigned int idx = uwatec_smart_find_tank (parser, mixid); + if (idx >= parser->ntanks) { + if (idx >= NGASMIXES) { + ERROR (abstract->context, "Maximum number of tanks reached."); + return DC_STATUS_NOMEMORY; + } + parser->tank[idx].id = mixid; + parser->tank[idx].beginpressure = beginpressure; + parser->tank[idx].endpressure = endpressure; + parser->tank[idx].gasmix = mixidx; + parser->ntanks++; + } + } + } + offset += value - 1; break; default: @@ -924,10 +992,12 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ERROR (abstract->context, "Invalid gas mix index."); return DC_STATUS_DATAFORMAT; } - sample.event.type = SAMPLE_EVENT_GASCHANGE; + unsigned int o2 = parser->gasmix[idx].oxygen; + unsigned int he = parser->gasmix[idx].helium; + sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.flags = 0; - sample.event.value = parser->gasmix[idx].oxygen; + sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); gasmix_previous = gasmix; } @@ -978,5 +1048,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t } } + parser->cached = PROFILE; + return DC_STATUS_SUCCESS; }