From f801b512c346467c01d0590c207551b760934e9c Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 6 Sep 2019 08:57:37 +0200 Subject: [PATCH 1/6] Check condition before entering the loop The condition doesn't change inside the loop, so there is no need to check it every iteration. --- src/hw_ostc3.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index 1bdac9c..187a9e4 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -325,12 +325,9 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, } } - if (delay) { + if (delay && device->available == 0) { unsigned int count = delay / 100; for (unsigned int i = 0; i < count; ++i) { - if (device->available) - break; - size_t available = 0; status = dc_iostream_get_available (device->iostream, &available); if (status == DC_STATUS_SUCCESS && available > 0) From ffeb6b244752916cbe6ff18761b9a5b9783313cc Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 6 Sep 2019 10:31:29 +0200 Subject: [PATCH 2/6] Update the Shearwater Nerd bluetooth names Add the Shearwater Nerd 2 bluetooth device name. The change to uppercase is purely cosmetic. The string comparisions are not case-sensitive. But for documentation purposes it's good practice to list the exact name as reported by the device. --- src/descriptor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/descriptor.c b/src/descriptor.c index 3495acd..2a05036 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -530,7 +530,8 @@ static int dc_filter_shearwater (dc_transport_t transport, const void *userdata) static const char * const bluetooth[] = { "Predator", "Petrel", - "Nerd", + "NERD", + "NERD 2", "Perdix", "Teric", }; From 41b24adfcbfec961c198bf31a2456196a4560e01 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 6 Sep 2019 11:54:50 +0200 Subject: [PATCH 3/6] Use a prefix match for the Suunto bluetooth name The Suunto D5 bluetooth device name contains the serial number. Thus we need to match only the prefix, instead of the full name. --- src/descriptor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/descriptor.c b/src/descriptor.c index 2a05036..65105f3 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -503,7 +503,7 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata) if (transport == DC_TRANSPORT_USBHID) { return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb); } else if (transport == DC_TRANSPORT_BLE) { - return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name); + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix); } return 1; From 03ff5d32f23e3ddb7d4b50214e0524ee4bfc3333 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 23 Sep 2019 21:09:07 +0200 Subject: [PATCH 4/6] 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 5/6] 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 6/6] 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