From a21f60e0bcdd7dccd198d2b16c7e7fe17774873e Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 13 Oct 2015 20:35:35 +0200 Subject: [PATCH 01/11] Handle a libusb timeout as a non fatal error. Dives are downloaded using bulk transfers with an 8K buffer. Normally the 2 second timeout is more than sufficient, and the timeout should never expire, unless there is some serious communcation problem. But nevertheless, users are reporting timeouts for dives having a length that is an exact multiple of the USB packet size (64 bytes). In that case, libusb reports a timeout with an non-zero amount of bytes received. Despite the timeout, the received data contains a complete dive. I suspect libusb is somehow unable to determine whether the transfer is complete and therefore waits until the timeout expires. For transfers that are not a multiple of the USB packet size, the end of the transfer is indicated by the last incomplete packet. This is not the case if the length is an exact multiple of the USB packet size. This problem is usually solved by sending a zero-length packet. Maybe the USB stack of the Cobalt is not sending such a zero-length packet? Atomics will address the problem with a Coblat 2 firmware upgrade, that will simply append two zero bytes if the length is a multiple of 64 bytes. As a workaround for older firmware versions, we ignore the timeout and process all received data. This shouldn't have any disadvantages. An incomplete dive, for example due to a real timeout, will now be detected by means of the minimum length and/or the checksum. --- src/atomics_cobalt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atomics_cobalt.c b/src/atomics_cobalt.c index 88febec..aec412d 100644 --- a/src/atomics_cobalt.c +++ b/src/atomics_cobalt.c @@ -284,7 +284,7 @@ atomics_cobalt_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, unsigned char packet[8 * 1024] = {0}; rc = libusb_bulk_transfer (device->handle, 0x82, packet, sizeof (packet), &length, TIMEOUT); - if (rc != LIBUSB_SUCCESS) { + if (rc != LIBUSB_SUCCESS && rc != LIBUSB_ERROR_TIMEOUT) { ERROR (abstract->context, "Failed to receive the answer."); return EXITCODE(rc); } From 6f89e445e31f8a090c0d323b30c5309145687c19 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 20 Oct 2015 20:30:37 +0100 Subject: [PATCH 02/11] Convert the internal tank id to an index. The internal Uwatec tank id should be converted to the libdivecomputer tank index. If there is no corresponding tank, the tank pressure samples are dropped for the following reasons: Some models appear to record an absolute tank pressure sample, even if there is no pressure sensor attached to the corresponding tank. In this case only the tank index changes. The sample value simply retains the last pressure of the previous tank. Since we don't have any real pressure data, dropping those samples is fine. --- src/uwatec_smart_parser.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 138b196..7a6a35f 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -1146,9 +1146,12 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t } if (have_pressure) { - sample.pressure.tank = tank; - sample.pressure.value = pressure; - if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); + idx = uwatec_smart_find_tank(parser, tank); + if (idx < parser->ntanks) { + sample.pressure.tank = idx; + sample.pressure.value = pressure; + if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); + } } if (have_heartrate) { From 95aa477129988fcec3d39cb2c7418b02cb044ba1 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 20 Oct 2015 18:12:58 +0200 Subject: [PATCH 03/11] Cache the parser data internally. --- src/oceanic_atom2_parser.c | 217 +++++++++++++++++++++++-------------- 1 file changed, 133 insertions(+), 84 deletions(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 0a6508f..6c2fdcd 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -79,6 +79,11 @@ #define GAUGE 1 #define FREEDIVE 2 +#define NGASMIXES 6 + +#define HEADER 1 +#define PROFILE 2 + typedef struct oceanic_atom2_parser_t oceanic_atom2_parser_t; struct oceanic_atom2_parser_t { @@ -88,6 +93,12 @@ struct oceanic_atom2_parser_t { unsigned int footersize; // Cached fields. unsigned int cached; + unsigned int header; + unsigned int footer; + unsigned int mode; + unsigned int ngasmixes; + unsigned int oxygen[NGASMIXES]; + unsigned int helium[NGASMIXES]; unsigned int divetime; double maxdepth; }; @@ -152,6 +163,14 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned } parser->cached = 0; + parser->header = 0; + parser->footer = 0; + parser->mode = NORMAL; + parser->ngasmixes = 0; + for (unsigned int i = 0; i < NGASMIXES; ++i) { + parser->oxygen[i] = 0; + parser->helium[i] = 0; + } parser->divetime = 0; parser->maxdepth = 0.0; @@ -178,6 +197,14 @@ oceanic_atom2_parser_set_data (dc_parser_t *abstract, const unsigned char *data, // Reset the cache. parser->cached = 0; + parser->header = 0; + parser->footer = 0; + parser->mode = NORMAL; + parser->ngasmixes = 0; + for (unsigned int i = 0; i < NGASMIXES; ++i) { + parser->oxygen[i] = 0; + parser->helium[i] = 0; + } parser->divetime = 0; parser->maxdepth = 0.0; @@ -320,12 +347,14 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim static dc_status_t -oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) +oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser) { - oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) abstract; + const unsigned char *data = parser->base.data; + unsigned int size = parser->base.size; - const unsigned char *data = abstract->data; - unsigned int size = abstract->size; + if (parser->cached) { + return DC_STATUS_SUCCESS; + } // Get the total amount of bytes before and after the profile data. unsigned int headersize = parser->headersize; @@ -352,14 +381,88 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns mode = (data[1] & 0x60) >> 5; } - if (!parser->cached) { - sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER; - dc_status_t rc = oceanic_atom2_parser_samples_foreach ( - abstract, sample_statistics_cb, &statistics); - if (rc != DC_STATUS_SUCCESS) - return rc; + // Get the gas mixes. + unsigned int ngasmixes = 0; + unsigned int o2_offset = 0; + unsigned int he_offset = 0; + if (mode == FREEDIVE) { + ngasmixes = 0; + } else if (parser->model == DATAMASK || parser->model == COMPUMASK) { + ngasmixes = 1; + o2_offset = header + 3; + } else if (parser->model == VT4 || parser->model == VT41 || + parser->model == A300AI) { + o2_offset = header + 4; + ngasmixes = 4; + } else if (parser->model == OCI) { + o2_offset = 0x28; + ngasmixes = 4; + } else if (parser->model == TX1) { + o2_offset = 0x3E; + he_offset = 0x48; + ngasmixes = 6; + } else if (parser->model == A300CS || parser->model == VTX) { + o2_offset = 0x2A; + if (data[0x39] & 0x04) { + ngasmixes = 1; + } else if (data[0x39] & 0x08) { + ngasmixes = 2; + } else if (data[0x39] & 0x10) { + ngasmixes = 3; + } else { + ngasmixes = 4; + } + } else { + o2_offset = header + 4; + ngasmixes = 3; + } - parser->cached = 1; + // Cache the data for later use. + parser->header = header; + parser->footer = footer; + parser->mode = mode; + parser->ngasmixes = ngasmixes; + for (unsigned int i = 0; i < ngasmixes; ++i) { + if (data[o2_offset + i]) { + parser->oxygen[i] = data[o2_offset + i]; + } else { + parser->oxygen[i] = 21; + } + if (he_offset) { + parser->helium[i] = data[he_offset + i]; + } else { + parser->helium[i] = 0; + } + } + parser->cached = HEADER; + + return DC_STATUS_SUCCESS; +} + + +static dc_status_t +oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) +{ + dc_status_t status = DC_STATUS_SUCCESS; + oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) abstract; + + const unsigned char *data = abstract->data; + unsigned int size = abstract->size; + + // Cache the header data. + status = oceanic_atom2_parser_cache (parser); + if (status != DC_STATUS_SUCCESS) + return status; + + // Cache the profile data. + if (parser->cached < PROFILE) { + sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER; + status = oceanic_atom2_parser_samples_foreach ( + abstract, sample_statistics_cb, &statistics); + if (status != DC_STATUS_SUCCESS) + return status; + + parser->cached = PROFILE; parser->divetime = statistics.divetime; parser->maxdepth = statistics.maxdepth; } @@ -367,9 +470,6 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; - unsigned int oxygen = 0; - unsigned int helium = 0; - if (value) { switch (type) { case DC_FIELD_DIVETIME: @@ -382,47 +482,14 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns if (parser->model == F10 || parser->model == F11) *((double *) value) = array_uint16_le (data + 4) / 16.0 * FEET; else - *((double *) value) = array_uint16_le (data + footer + 4) / 16.0 * FEET; + *((double *) value) = array_uint16_le (data + parser->footer + 4) / 16.0 * FEET; break; case DC_FIELD_GASMIX_COUNT: - if (mode == FREEDIVE) { - *((unsigned int *) value) = 0; - } else if (parser->model == DATAMASK || parser->model == COMPUMASK) { - *((unsigned int *) value) = 1; - } else if (parser->model == VT4 || parser->model == VT41 || - parser->model == OCI || parser->model == A300AI) { - *((unsigned int *) value) = 4; - } else if (parser->model == TX1) { - *((unsigned int *) value) = 6; - } else if (parser->model == A300CS || parser->model == VTX) { - if (data[0x39] & 0x04) { - *((unsigned int *) value) = 1; - } else if (data[0x39] & 0x08) { - *((unsigned int *) value) = 2; - } else if (data[0x39] & 0x10) { - *((unsigned int *) value) = 3; - } else { - *((unsigned int *) value) = 4; - } - } else { - *((unsigned int *) value) = 3; - } + *((unsigned int *) value) = parser->ngasmixes; break; case DC_FIELD_GASMIX: - if (parser->model == DATAMASK || parser->model == COMPUMASK) { - oxygen = data[header + 3]; - } else if (parser->model == OCI) { - oxygen = data[0x28 + flags]; - } else if (parser->model == A300CS || parser->model == VTX) { - oxygen = data[0x2A + flags]; - } else if (parser->model == TX1) { - oxygen = data[0x3E + flags]; - helium = data[0x48 + flags]; - } else { - oxygen = data[header + 4 + flags]; - } - gasmix->helium = helium / 100.0; - gasmix->oxygen = (oxygen ? oxygen / 100.0 : 0.21); + gasmix->oxygen = parser->oxygen[flags] / 100.0; + gasmix->helium = parser->helium[flags] / 100.0; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; case DC_FIELD_SALINITY: @@ -438,7 +505,7 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns } break; case DC_FIELD_DIVEMODE: - switch (mode) { + switch (parser->mode) { case NORMAL: *((unsigned int *) value) = DC_DIVEMODE_OC; break; @@ -464,38 +531,20 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns static dc_status_t oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) { + dc_status_t status = DC_STATUS_SUCCESS; oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) abstract; const unsigned char *data = abstract->data; unsigned int size = abstract->size; - // Get the total amount of bytes before and after the profile data. - unsigned int headersize = parser->headersize; - unsigned int footersize = parser->footersize; - if (size < headersize + footersize) - return DC_STATUS_DATAFORMAT; - - // Get the offset to the header sample. - unsigned int header = headersize - PAGESIZE / 2; - if (parser->model == VT4 || parser->model == VT41 || - parser->model == A300AI) { - header = 3 * PAGESIZE; - } - - // Get the dive mode. - unsigned int mode = NORMAL; - if (parser->model == F10 || parser->model == F11) { - mode = FREEDIVE; - } else if (parser->model == T3B || parser->model == VT3 || - parser->model == DG03) { - mode = (data[2] & 0xC0) >> 6; - } else if (parser->model == VEO20 || parser->model == VEO30) { - mode = (data[1] & 0x60) >> 5; - } + // Cache the header data. + status = oceanic_atom2_parser_cache (parser); + if (status != DC_STATUS_SUCCESS) + return status; unsigned int time = 0; unsigned int interval = 1; - if (mode != FREEDIVE) { + if (parser->mode != FREEDIVE) { unsigned int idx = 0x17; if (parser->model == A300CS || parser->model == VTX) idx = 0x1f; @@ -516,7 +565,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } unsigned int samplesize = PAGESIZE / 2; - if (mode == FREEDIVE) { + if (parser->mode == FREEDIVE) { if (parser->model == F10 || parser->model == F11) { samplesize = 2; } else { @@ -530,7 +579,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } unsigned int have_temperature = 1, have_pressure = 1; - if (mode == FREEDIVE) { + if (parser->mode == FREEDIVE) { have_temperature = 0; have_pressure = 0; } else if (parser->model == VEO30 || parser->model == OCS || @@ -544,7 +593,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // Initial temperature. unsigned int temperature = 0; if (have_temperature) { - temperature = data[header + 7]; + temperature = data[parser->header + 7]; } // Initial tank pressure. @@ -554,14 +603,14 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int idx = 2; if (parser->model == A300CS || parser->model == VTX) idx = 16; - pressure = data[header + idx] + (data[header + idx + 1] << 8); + pressure = array_uint16_le(data + parser->header + idx); if (pressure == 10000) have_pressure = 0; } unsigned int complete = 1; - unsigned int offset = headersize; - while (offset + samplesize <= size - footersize) { + unsigned int offset = parser->headersize; + while (offset + samplesize <= size - parser->footersize) { dc_sample_value_t sample = {0}; // Ignore empty samples. @@ -582,7 +631,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // Get the sample type. unsigned int sampletype = data[offset + 0]; - if (mode == FREEDIVE) + if (parser->mode == FREEDIVE) sampletype = 0; // The sample size is usually fixed, but some sample types have a @@ -698,7 +747,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // Depth (1/16 ft) unsigned int depth; - if (mode == FREEDIVE) + if (parser->mode == FREEDIVE) depth = array_uint16_le (data + offset); else if (parser->model == GEO20 || parser->model == VEO20 || parser->model == VEO30 || parser->model == OC1A || From 7341403f73e967f97227f8ec7cff877c4fc73b0f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 21 Oct 2015 20:39:34 +0200 Subject: [PATCH 04/11] Fix the temperature for the Tusa Zen. --- src/oceanic_atom2_parser.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 6c2fdcd..7aaba64 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -689,7 +689,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // Temperature (°F) if (have_temperature) { if (parser->model == GEO || parser->model == ATOM1 || - parser->model == ELEMENT2 || parser->model == MANTA) { + parser->model == ELEMENT2 || parser->model == MANTA || + parser->model == ZEN) { temperature = data[offset + 6]; } else if (parser->model == GEO20 || parser->model == VEO20 || parser->model == VEO30 || parser->model == OC1A || From 3b0e36ccbfb83a10ea12b39935501037c0391b5e Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 21 Oct 2015 20:49:51 +0200 Subject: [PATCH 05/11] Implement ndl/deco support for the Tusa Zen. --- src/oceanic_atom2_parser.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 7aaba64..dec47cd 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -763,14 +763,21 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); // NDL / Deco - // bits 6..4 of byte 15 encode deco state & depth - // bytes 6 & 7 encode minutes of NDL / deco + unsigned int have_deco = 0; + unsigned int decostop = 0, decotime = 0; if (parser->model == A300CS || parser->model == VTX) { - unsigned int deco = (data[offset + 15] & 0x70) >> 4; - unsigned int decotime = array_uint16_le(data + offset + 6) & 0x03FF; - if (deco) { + decostop = (data[offset + 15] & 0x70) >> 4; + decotime = array_uint16_le(data + offset + 6) & 0x03FF; + have_deco = 1; + } else if (parser->model == ZEN) { + decostop = (data[offset + 5] & 0xF0) >> 4; + decotime = array_uint16_le(data + offset + 4) & 0x0FFF; + have_deco = 1; + } + if (have_deco) { + if (decostop) { sample.deco.type = DC_DECO_DECOSTOP; - sample.deco.depth = deco * 10 * FEET; + sample.deco.depth = decostop * 10 * FEET; } else { sample.deco.type = DC_DECO_NDL; sample.deco.depth = 0.0; From 99300d4e37bc035b52cebebfc40d6743e4dfe787 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 26 Oct 2015 19:08:02 +0100 Subject: [PATCH 06/11] Implement ndl/deco support for the Hollis TX1. --- src/oceanic_atom2_parser.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index dec47cd..2503f52 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -773,6 +773,10 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ decostop = (data[offset + 5] & 0xF0) >> 4; decotime = array_uint16_le(data + offset + 4) & 0x0FFF; have_deco = 1; + } else if (parser->model == TX1) { + decostop = data[offset + 10]; + decotime = array_uint16_le(data + offset + 6); + have_deco = 1; } if (have_deco) { if (decostop) { From aa2499ef0f74c3973e71c371191a3e0dcd91fb89 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 26 Oct 2015 19:16:19 +0100 Subject: [PATCH 07/11] Implement gas switches for the Hollis TX1. --- src/oceanic_atom2_parser.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 2503f52..6651519 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -608,6 +608,9 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ have_pressure = 0; } + // Initial gas mix. + unsigned int gasmix_previous = 0xFFFFFFFF; + unsigned int complete = 1; unsigned int offset = parser->headersize; while (offset + samplesize <= size - parser->footersize) { @@ -762,6 +765,28 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ sample.depth = depth / 16.0 * FEET; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); + // Gas mix + unsigned int have_gasmix = 0; + unsigned int gasmix = 0; + if (parser->model == TX1) { + gasmix = data[offset] & 0x07; + have_gasmix = 1; + } + if (have_gasmix && gasmix != gasmix_previous) { + if (gasmix < 1 || gasmix > parser->ngasmixes) { + ERROR (abstract->context, "Invalid gas mix index (%u).", gasmix); + return DC_STATUS_DATAFORMAT; + } + unsigned int o2 = parser->oxygen[gasmix - 1]; + unsigned int he = parser->helium[gasmix - 1]; + sample.event.type = SAMPLE_EVENT_GASCHANGE2; + sample.event.time = 0; + sample.event.flags = 0; + sample.event.value = o2 | (he << 16); + if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); + gasmix_previous = gasmix; + } + // NDL / Deco unsigned int have_deco = 0; unsigned int decostop = 0, decotime = 0; From ae70d1efba1da8ac1fd75ec688ac98432978b2c6 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 28 Oct 2015 19:10:12 +0100 Subject: [PATCH 08/11] Fix the dive mode for the Galileo Trimix. Parsing the gas mixes has been implemented a while ago, so this check is no longer neccessary. --- src/uwatec_smart_parser.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 7a6a35f..66542b3 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -760,8 +760,6 @@ uwatec_smart_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = (signed short) array_uint16_le (data + table->temp_surface) / 10.0; break; case DC_FIELD_DIVEMODE: - if (parser->trimix) - return DC_STATUS_UNSUPPORTED; if (parser->ngasmixes) *((dc_divemode_t *) value) = DC_DIVEMODE_OC; else From 84d67c554446ca9af0096da3b3d9f432fbfd448c Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 28 Oct 2015 19:21:45 +0100 Subject: [PATCH 09/11] Add support for the new OSTC logbook format. With the new logbook format version 0x24, the OSTC no longer stores the date/time at the end of the dive, but at the start of the dive. --- src/hw_ostc_parser.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 394291f..8c0702a 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -196,6 +196,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) header = 256; break; case 0x23: + case 0x24: layout = &hw_ostc_layout_ostc3; header = 256; break; @@ -220,7 +221,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) gasmix[i].oxygen = data[25 + 2 * i]; gasmix[i].helium = 0; } - } else if (version == 0x23) { + } else if (version == 0x23 || version == 0x24) { ngasmixes = 5; for (unsigned int i = 0; i < ngasmixes; ++i) { gasmix[i].oxygen = data[28 + 4 * i + 0]; @@ -355,7 +356,7 @@ hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) const unsigned char *p = data + layout->datetime; dc_datetime_t dt; - if (version == 0x23) { + if (version == 0x23 || version == 0x24) { dt.year = p[0] + 2000; dt.month = p[1]; dt.day = p[2]; @@ -368,14 +369,19 @@ hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) dt.minute = p[4]; dt.second = 0; - dc_ticks_t ticks = dc_datetime_mktime (&dt); - if (ticks == (dc_ticks_t) -1) - return DC_STATUS_DATAFORMAT; + if (version == 0x24) { + if (datetime) + *datetime = dt; + } else { + dc_ticks_t ticks = dc_datetime_mktime (&dt); + if (ticks == (dc_ticks_t) -1) + return DC_STATUS_DATAFORMAT; - ticks -= divetime; + ticks -= divetime; - if (!dc_datetime_localtime (datetime, ticks)) - return DC_STATUS_DATAFORMAT; + if (!dc_datetime_localtime (datetime, ticks)) + return DC_STATUS_DATAFORMAT; + } return DC_STATUS_SUCCESS; } @@ -405,7 +411,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; unsigned int salinity = data[layout->salinity]; - if (version == 0x23) + if (version == 0x23 || version == 0x24) salinity += 100; if (value) { @@ -476,7 +482,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned default: return DC_STATUS_DATAFORMAT; } - } else if (version == 0x23) { + } else if (version == 0x23 || version == 0x24) { switch (data[82]) { case OSTC3_OC: *((dc_divemode_t *) value) = DC_DIVEMODE_OC; @@ -524,14 +530,14 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call // Get the sample rate. unsigned int samplerate = 0; - if (version == 0x23) + if (version == 0x23 || version == 0x24) samplerate = data[header + 3]; else samplerate = data[36]; // Get the salinity factor. unsigned int salinity = data[layout->salinity]; - if (version == 0x23) + if (version == 0x23 || version == 0x24) salinity += 100; if (salinity < 100 || salinity > 104) salinity = 100; @@ -539,7 +545,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call // Get the number of sample descriptors. unsigned int nconfig = 0; - if (version == 0x23) + if (version == 0x23 || version == 0x24) nconfig = data[header + 4]; else nconfig = 6; @@ -551,7 +557,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call // Get the extended sample configuration. hw_ostc_sample_info_t info[MAXCONFIG] = {{0}}; for (unsigned int i = 0; i < nconfig; ++i) { - if (version == 0x23) { + if (version == 0x23 || version == 0x24) { info[i].type = data[header + 5 + 3 * i + 0]; info[i].size = data[header + 5 + 3 * i + 1]; info[i].divisor = data[header + 5 + 3 * i + 2]; @@ -592,7 +598,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call unsigned int nsamples = 0; unsigned int offset = header; - if (version == 0x23) + if (version == 0x23 || version == 0x24) offset += 5 + 3 * nconfig; while (offset + 3 <= size) { dc_sample_value_t sample = {0}; @@ -636,7 +642,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call unsigned int nbits = 0; unsigned int events = 0; while (data[offset - 1] & 0x80) { - if (nbits && version != 0x23) + if (nbits && version != 0x23 && version != 0x24) break; if (length < 1) { ERROR (abstract->context, "Buffer overflow detected!"); @@ -730,7 +736,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call length--; } - if (version == 0x23) { + if (version == 0x23 || version == 0x24) { // SetPoint Change if (events & 0x40) { if (length < 1) { @@ -820,7 +826,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call } } - if (version != 0x23) { + if (version != 0x23 && version != 0x24) { // SetPoint Change if (events & 0x40) { if (length < 1) { From 0a20eae342ec9890a7a7f017847d9487e2f0dd66 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 4 Nov 2015 19:36:03 +0100 Subject: [PATCH 10/11] Prefer the C99 identifier for the function name. The GCC 5 compiler with -Wpedantic enabled generates warnings for the non-standard predefined identifier __FUNCTION___. These warnings can be avoided by using the C99 identifier __func__ instead. --- src/context-private.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/context-private.h b/src/context-private.h index 39323ed..e7509bf 100644 --- a/src/context-private.h +++ b/src/context-private.h @@ -34,13 +34,19 @@ extern "C" { #define UNUSED(x) (void)sizeof(x) +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define FUNCTION __func__ +#else +#define FUNCTION __FUNCTION__ +#endif + #ifdef ENABLE_LOGGING -#define HEXDUMP(context, loglevel, prefix, data, size) dc_context_hexdump (context, loglevel, __FILE__, __LINE__, __FUNCTION__, prefix, data, size) -#define SYSERROR(context, errcode) dc_context_syserror (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, __FUNCTION__, errcode) -#define ERROR(context, ...) dc_context_log (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) -#define WARNING(context, ...) dc_context_log (context, DC_LOGLEVEL_WARNING, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) -#define INFO(context, ...) dc_context_log (context, DC_LOGLEVEL_INFO, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) -#define DEBUG(context, ...) dc_context_log (context, DC_LOGLEVEL_DEBUG, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#define HEXDUMP(context, loglevel, prefix, data, size) dc_context_hexdump (context, loglevel, __FILE__, __LINE__, FUNCTION, prefix, data, size) +#define SYSERROR(context, errcode) dc_context_syserror (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, FUNCTION, errcode) +#define ERROR(context, ...) dc_context_log (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, FUNCTION, __VA_ARGS__) +#define WARNING(context, ...) dc_context_log (context, DC_LOGLEVEL_WARNING, __FILE__, __LINE__, FUNCTION, __VA_ARGS__) +#define INFO(context, ...) dc_context_log (context, DC_LOGLEVEL_INFO, __FILE__, __LINE__, FUNCTION, __VA_ARGS__) +#define DEBUG(context, ...) dc_context_log (context, DC_LOGLEVEL_DEBUG, __FILE__, __LINE__, FUNCTION, __VA_ARGS__) #else #define HEXDUMP(context, loglevel, prefix, data, size) UNUSED(context) #define SYSERROR(context, errcode) UNUSED(context) From fb5f7ad971ea9b7cc92cc43c03973c318b716f6d Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 4 Nov 2015 19:42:17 +0100 Subject: [PATCH 11/11] Use the GCC printf format attribute. This enables the compiler to check the arguments against a printf style format string in all calls to the logging functions. --- examples/utils.h | 8 +++++++- src/context-private.h | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/examples/utils.h b/examples/utils.h index e43c06c..7562beb 100644 --- a/examples/utils.h +++ b/examples/utils.h @@ -26,9 +26,15 @@ extern "C" { #endif /* __cplusplus */ +#if defined(__GNUC__) +#define ATTR_FORMAT_PRINTF(a,b) __attribute__((format(printf, a, b))) +#else +#define ATTR_FORMAT_PRINTF(a,b) +#endif + #define WARNING(expr) message ("%s:%d: %s\n", __FILE__, __LINE__, expr) -int message (const char* fmt, ...); +int message (const char* fmt, ...) ATTR_FORMAT_PRINTF(1, 2); void message_set_logfile (const char* filename); diff --git a/src/context-private.h b/src/context-private.h index e7509bf..7f50a68 100644 --- a/src/context-private.h +++ b/src/context-private.h @@ -40,6 +40,12 @@ extern "C" { #define FUNCTION __FUNCTION__ #endif +#if defined(__GNUC__) +#define ATTR_FORMAT_PRINTF(a,b) __attribute__((format(printf, a, b))) +#else +#define ATTR_FORMAT_PRINTF(a,b) +#endif + #ifdef ENABLE_LOGGING #define HEXDUMP(context, loglevel, prefix, data, size) dc_context_hexdump (context, loglevel, __FILE__, __LINE__, FUNCTION, prefix, data, size) #define SYSERROR(context, errcode) dc_context_syserror (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, FUNCTION, errcode) @@ -57,7 +63,7 @@ extern "C" { #endif dc_status_t -dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *format, ...); +dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *format, ...) ATTR_FORMAT_PRINTF(6, 7); dc_status_t dc_context_syserror (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, int errcode);