From 03ff5d32f23e3ddb7d4b50214e0524ee4bfc3333 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 23 Sep 2019 21:09:07 +0200 Subject: [PATCH 1/3] Use a struct for the gasmix data --- src/shearwater_predator_parser.c | 34 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 7d3a420..209ecd8 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -77,6 +77,11 @@ typedef struct shearwater_predator_parser_t shearwater_predator_parser_t; +typedef struct shearwater_predator_gasmix_t { + unsigned int oxygen; + unsigned int helium; +} shearwater_predator_gasmix_t; + struct shearwater_predator_parser_t { dc_parser_t base; unsigned int model; @@ -92,8 +97,7 @@ struct shearwater_predator_parser_t { unsigned int closing[NRECORDS]; unsigned int final; unsigned int ngasmixes; - unsigned int oxygen[NGASMIXES]; - unsigned int helium[NGASMIXES]; + shearwater_predator_gasmix_t gasmix[NGASMIXES]; unsigned int calibrated; double calibration[3]; dc_divemode_t mode; @@ -135,7 +139,7 @@ shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned { unsigned int i = 0; while (i < parser->ngasmixes) { - if (o2 == parser->oxygen[i] && he == parser->helium[i]) + if (o2 == parser->gasmix[i].oxygen && he == parser->gasmix[i].helium) break; i++; } @@ -185,8 +189,8 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig parser->final = UNDEFINED; parser->ngasmixes = 0; for (unsigned int i = 0; i < NGASMIXES; ++i) { - parser->oxygen[i] = 0; - parser->helium[i] = 0; + parser->gasmix[i].oxygen = 0; + parser->gasmix[i].helium = 0; } parser->calibrated = 0; for (unsigned int i = 0; i < 3; ++i) { @@ -235,8 +239,8 @@ shearwater_predator_parser_set_data (dc_parser_t *abstract, const unsigned char parser->final = UNDEFINED; parser->ngasmixes = 0; for (unsigned int i = 0; i < NGASMIXES; ++i) { - parser->oxygen[i] = 0; - parser->helium[i] = 0; + parser->gasmix[i].oxygen = 0; + parser->gasmix[i].helium = 0; } parser->calibrated = 0; for (unsigned int i = 0; i < 3; ++i) { @@ -333,8 +337,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) // Get the gas mixes. unsigned int ngasmixes = 0; - unsigned int oxygen[NGASMIXES] = {0}; - unsigned int helium[NGASMIXES] = {0}; + shearwater_predator_gasmix_t gasmix[NGASMIXES] = {0}; unsigned int o2_previous = 0, he_previous = 0; unsigned int offset = headersize; @@ -363,7 +366,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) // Find the gasmix in the list. unsigned int idx = 0; while (idx < ngasmixes) { - if (o2 == oxygen[idx] && he == helium[idx]) + if (o2 == gasmix[idx].oxygen && he == gasmix[idx].helium) break; idx++; } @@ -374,8 +377,8 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) ERROR (abstract->context, "Maximum number of gas mixes reached."); return DC_STATUS_NOMEMORY; } - oxygen[idx] = o2; - helium[idx] = he; + gasmix[idx].oxygen = o2; + gasmix[idx].helium = he; ngasmixes = idx + 1; } @@ -450,8 +453,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) parser->footersize = footersize; parser->ngasmixes = ngasmixes; for (unsigned int i = 0; i < ngasmixes; ++i) { - parser->oxygen[i] = oxygen[i]; - parser->helium[i] = helium[i]; + parser->gasmix[i] = gasmix[i]; } parser->mode = mode; parser->units = data[parser->opening[0] + 8]; @@ -497,8 +499,8 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ *((unsigned int *) value) = parser->ngasmixes; break; case DC_FIELD_GASMIX: - gasmix->oxygen = parser->oxygen[flags] / 100.0; - gasmix->helium = parser->helium[flags] / 100.0; + gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; + gasmix->helium = parser->gasmix[flags].helium / 100.0; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; case DC_FIELD_SALINITY: From e23c374cd8e94084e6898da0b83470537a601559 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 23 Sep 2019 21:13:53 +0200 Subject: [PATCH 2/3] Extract the log version immediately To be able to collect the tank begin/end pressure, the log version needs to be available earlier, because it's needed for parsing the tank pressure data in the samples. Therefore, extract the log version immediately after locating the opening record. --- src/shearwater_predator_parser.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 209ecd8..a4ef700 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -288,6 +288,10 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) return DC_STATUS_SUCCESS; } + // Log versions before 6 weren't reliably stored in the data, but + // 6 is also the oldest version that we assume in our code + unsigned int logversion = 0; + // Verify the minimum length. if (size < 2) { ERROR (abstract->context, "Invalid data length."); @@ -330,6 +334,9 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) parser->opening[i] = 0; parser->closing[i] = size - footersize; } + + // Log version + logversion = data[127]; } // Default dive mode. @@ -391,6 +398,11 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } else if (type >= LOG_RECORD_OPENING_0 && type <= LOG_RECORD_OPENING_7) { // Opening record parser->opening[type - LOG_RECORD_OPENING_0] = offset; + + // Log version + if (type == LOG_RECORD_OPENING_4) { + logversion = data[offset + 16]; + } } else if (type >= LOG_RECORD_CLOSING_0 && type <= LOG_RECORD_CLOSING_7) { // Closing record parser->closing[type - LOG_RECORD_CLOSING_0] = offset; @@ -410,10 +422,6 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } } - // Log versions before 6 weren't reliably stored in the data, but - // 6 is also the oldest version that we assume in our code - unsigned int logversion = data[parser->opening[4] + (pnf ? 16 : 127)]; - // Cache sensor calibration for later use unsigned int nsensors = 0, ndefaults = 0; unsigned int base = parser->opening[3] + (pnf ? 6 : 86); From 6c441bb402b842fbe7b42816809c8a8faef03388 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 23 Sep 2019 21:23:57 +0200 Subject: [PATCH 3/3] Improve the support for multiple tank transmitters Some of the newer Shearwater dive computers support up to 2 tank pressure sensors. The tank pressure samples were already reported, but the tank field with the corresponding begin/end pressure was still missing. --- src/shearwater_predator_parser.c | 112 +++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 22 deletions(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index a4ef700..02b34da 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -68,6 +68,7 @@ #define IMPERIAL 1 #define NGASMIXES 10 +#define NTANKS 2 #define NRECORDS 7 #define PREDATOR 2 @@ -82,6 +83,12 @@ typedef struct shearwater_predator_gasmix_t { unsigned int helium; } shearwater_predator_gasmix_t; +typedef struct shearwater_predator_tank_t { + unsigned int enabled; + unsigned int beginpressure; + unsigned int endpressure; +} shearwater_predator_tank_t; + struct shearwater_predator_parser_t { dc_parser_t base; unsigned int model; @@ -97,7 +104,10 @@ struct shearwater_predator_parser_t { unsigned int closing[NRECORDS]; unsigned int final; unsigned int ngasmixes; + unsigned int ntanks; shearwater_predator_gasmix_t gasmix[NGASMIXES]; + shearwater_predator_tank_t tank[NTANKS]; + unsigned int tankidx[NTANKS]; unsigned int calibrated; double calibration[3]; dc_divemode_t mode; @@ -192,6 +202,13 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig parser->gasmix[i].oxygen = 0; parser->gasmix[i].helium = 0; } + parser->ntanks = 0; + for (unsigned int i = 0; i < NTANKS; ++i) { + parser->tank[i].enabled = 0; + parser->tank[i].beginpressure = 0; + parser->tank[i].endpressure = 0; + parser->tankidx[i] = i; + } parser->calibrated = 0; for (unsigned int i = 0; i < 3; ++i) { parser->calibration[i] = 0.0; @@ -242,6 +259,13 @@ shearwater_predator_parser_set_data (dc_parser_t *abstract, const unsigned char parser->gasmix[i].oxygen = 0; parser->gasmix[i].helium = 0; } + parser->ntanks = 0; + for (unsigned int i = 0; i < NTANKS; ++i) { + parser->tank[i].enabled = 0; + parser->tank[i].beginpressure = 0; + parser->tank[i].endpressure = 0; + parser->tankidx[i] = i; + } parser->calibrated = 0; for (unsigned int i = 0; i < 3; ++i) { parser->calibration[i] = 0.0; @@ -345,6 +369,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) // Get the gas mixes. unsigned int ngasmixes = 0; shearwater_predator_gasmix_t gasmix[NGASMIXES] = {0}; + shearwater_predator_tank_t tank[NTANKS] = {0}; unsigned int o2_previous = 0, he_previous = 0; unsigned int offset = headersize; @@ -392,6 +417,31 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) o2_previous = o2; he_previous = he; } + + // Tank pressure + if (logversion >= 7) { + const unsigned int idx[NTANKS] = {27, 19}; + for (unsigned int i = 0; i < NTANKS; ++i) { + // Values above 0xFFF0 are special codes: + // 0xFFFF AI is off + // 0xFFFE No comms for 90 seconds+ + // 0xFFFD No comms for 30 seconds + // 0xFFFC Transmitter not paired + // For regular values, the top 4 bits contain the battery + // level (0=normal, 1=critical, 2=warning), and the lower 12 + // bits the tank pressure in units of 2 psi. + unsigned int pressure = array_uint16_be (data + offset + pnf + idx[i]); + if (pressure < 0xFFF0) { + pressure &= 0x0FFF; + if (!tank[i].enabled) { + tank[i].enabled = 1; + tank[i].beginpressure = pressure; + tank[i].endpressure = pressure; + } + tank[i].endpressure = pressure; + } + } + } } else if (type == LOG_RECORD_FREEDIVE_SAMPLE) { // Freedive record mode = DC_DIVEMODE_FREEDIVE; @@ -463,6 +513,16 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) for (unsigned int i = 0; i < ngasmixes; ++i) { parser->gasmix[i] = gasmix[i]; } + parser->ntanks = 0; + for (unsigned int i = 0; i < NTANKS; ++i) { + if (tank[i].enabled) { + parser->tankidx[i] = parser->ntanks; + parser->tank[parser->ntanks] = tank[i]; + parser->ntanks++; + } else { + parser->tankidx[i] = UNDEFINED; + } + } parser->mode = mode; parser->units = data[parser->opening[0] + 8]; parser->atmospheric = array_uint16_be (data + parser->opening[1] + (parser->pnf ? 16 : 47)); @@ -485,6 +545,7 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ return rc; dc_gasmix_t *gasmix = (dc_gasmix_t *) value; + dc_tank_t *tank = (dc_tank_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; if (value) { @@ -511,6 +572,17 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ gasmix->helium = parser->gasmix[flags].helium / 100.0; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; + case DC_FIELD_TANK_COUNT: + *((unsigned int *) value) = parser->ntanks; + break; + case DC_FIELD_TANK: + tank->type = DC_TANKVOLUME_NONE; + tank->volume = 0.0; + tank->workpressure = 0.0; + tank->beginpressure = parser->tank[flags].beginpressure * 2 * PSI / BAR; + tank->endpressure = parser->tank[flags].endpressure * 2 * PSI / BAR; + tank->gasmix = DC_GASMIX_UNKNOWN; + break; case DC_FIELD_SALINITY: if (parser->density == 1000) water->type = DC_WATER_FRESH; @@ -680,28 +752,24 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal // for logversion 7 and newer (introduced for Perdix AI) // detect tank pressure if (parser->logversion >= 7) { - // Tank pressure - // Values above 0xFFF0 are special codes: - // 0xFFFF AI is off - // 0xFFFE No comms for 90 seconds+ - // 0xFFFD No comms for 30 seconds - // 0xFFFC Transmitter not paired - // For regular values, the top 4 bits contain the battery - // level (0=normal, 1=critical, 2=warning), and the lower 12 - // bits the tank pressure in units of 2 psi. - unsigned int pressure = array_uint16_be (data + offset + pnf + 27); - if (pressure < 0xFFF0) { - pressure &= 0x0FFF; - sample.pressure.tank = 0; - sample.pressure.value = pressure * 2 * PSI / BAR; - if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); - } - pressure = array_uint16_be (data + offset + pnf + 19); - if (pressure < 0xFFF0) { - pressure &= 0x0FFF; - sample.pressure.tank = 1; - sample.pressure.value = pressure * 2 * PSI / BAR; - if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); + const unsigned int idx[NTANKS] = {27, 19}; + for (unsigned int i = 0; i < NTANKS; ++i) { + // Tank pressure + // Values above 0xFFF0 are special codes: + // 0xFFFF AI is off + // 0xFFFE No comms for 90 seconds+ + // 0xFFFD No comms for 30 seconds + // 0xFFFC Transmitter not paired + // For regular values, the top 4 bits contain the battery + // level (0=normal, 1=critical, 2=warning), and the lower 12 + // bits the tank pressure in units of 2 psi. + unsigned int pressure = array_uint16_be (data + offset + pnf + idx[i]); + if (pressure < 0xFFF0) { + pressure &= 0x0FFF; + sample.pressure.tank = parser->tankidx[i]; + sample.pressure.value = pressure * 2 * PSI / BAR; + if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); + } } // Gas time remaining in minutes