From 90a08ad84539bcf6b1c96abe9794fe446f53f222 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 25 Nov 2020 14:11:23 +0100 Subject: [PATCH 01/23] Add support for the Sherwood Sage The Sherwood Sage appears to be very similar to the Aeris A300CS. For the BLE communication the handshake fails and is disabled. Reported-By: Nick Shore --- src/descriptor.c | 2 ++ src/oceanic_atom2.c | 4 +++- src/oceanic_atom2_parser.c | 21 +++++++++++++-------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index 8b2593a..cc80a59 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -253,6 +253,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641, DC_TRANSPORT_SERIAL, NULL}, {"Aqualung", "i550", DC_FAMILY_OCEANIC_ATOM2, 0x4642, DC_TRANSPORT_SERIAL, NULL}, {"Aqualung", "i200", DC_FAMILY_OCEANIC_ATOM2, 0x4646, DC_TRANSPORT_SERIAL, NULL}, + {"Sherwood", "Sage", DC_FAMILY_OCEANIC_ATOM2, 0x4647, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic}, {"Aqualung", "i300C", DC_FAMILY_OCEANIC_ATOM2, 0x4648, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic}, {"Aqualung", "i200C", DC_FAMILY_OCEANIC_ATOM2, 0x4649, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic}, {"Aqualung", "i100", DC_FAMILY_OCEANIC_ATOM2, 0x464E, DC_TRANSPORT_SERIAL, NULL}, @@ -641,6 +642,7 @@ static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, vo { static const unsigned int model[] = { 0x4552, // Oceanic Pro Plus X + 0x4647, // Sherwood Sage 0x4648, // Aqualung i300C 0x4649, // Aqualung i200C 0x4651, // Aqualung i770R diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index ccad96c..c4de23d 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -38,6 +38,7 @@ #define PROPLUSX 0x4552 #define VTX 0x4557 #define I750TC 0x455A +#define SAGE 0x4647 #define I770R 0x4651 #define GEO40 0x4653 @@ -491,6 +492,7 @@ static const oceanic_common_version_t versions[] = { {"AER300CS \0\0 2048", 0, &aeris_a300cs_layout}, {"OCEANVTX \0\0 2048", 0, &aeris_a300cs_layout}, {"AQUAI750 \0\0 2048", 0, &aeris_a300cs_layout}, + {"SWDRAGON \0\0 2048", 0, &aeris_a300cs_layout}, {"AQUAI450 \0\0 2048", 0, &aqualung_i450t_layout}, @@ -902,7 +904,7 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream } if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE && - model != PROPLUSX) { + model != PROPLUSX && model != SAGE ) { status = oceanic_atom2_ble_handshake(device); if (status != DC_STATUS_SUCCESS) { goto error_free; diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 94c6ba3..e2a54ff 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -87,6 +87,7 @@ #define I450T 0x4641 #define I550 0x4642 #define I200 0x4646 +#define SAGE 0x4647 #define I300C 0x4648 #define I200C 0x4649 #define I100 0x464E @@ -188,7 +189,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned parser->footersize = 0; } else if (model == A300CS || model == VTX || model == I450T || model == I750TC || - model == I770R) { + model == I770R || model == SAGE) { parser->headersize = 5 * PAGESIZE; } else if (model == PROPLUSX) { parser->headersize = 3 * PAGESIZE; @@ -341,6 +342,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim case I750TC: case PROPLUSX: case I770R: + case SAGE: datetime->year = (p[10]) + 2000; datetime->month = (p[8]); datetime->day = (p[9]); @@ -461,7 +463,7 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser) he_offset = 0x48; ngasmixes = 6; } else if (parser->model == A300CS || parser->model == VTX || - parser->model == I750TC) { + parser->model == I750TC || parser->model == SAGE) { o2_offset = 0x2A; if (data[0x39] & 0x04) { ngasmixes = 1; @@ -670,7 +672,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int idx = 0x17; if (parser->model == A300CS || parser->model == VTX || parser->model == I450T || parser->model == I750TC || - parser->model == PROPLUSX || parser->model == I770R) + parser->model == PROPLUSX || parser->model == I770R || + parser->model == SAGE) idx = 0x1f; switch (data[idx] & 0x03) { case 0: @@ -726,7 +729,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == TX1 || parser->model == A300CS || parser->model == VTX || parser->model == I450T || parser->model == I750TC || parser->model == PROPLUSX || - parser->model == I770R || parser->model == I470TC) { + parser->model == I770R || parser->model == I470TC || + parser->model == SAGE) { samplesize = PAGESIZE; } @@ -811,7 +815,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ tank = 0; pressure = (((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF); } else if (parser->model == A300CS || parser->model == VTX || - parser->model == I750TC) { + parser->model == I750TC || parser->model == SAGE) { // Tank pressure (1 psi) and number (one based index) tank = (data[offset + 1] & 0x03) - 1; pressure = ((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF; @@ -913,7 +917,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ temperature = ((data[offset + 7] & 0xF0) >> 4) | ((data[offset + 7] & 0x0C) << 2) | ((data[offset + 5] & 0x0C) << 4); } else if (parser->model == A300CS || parser->model == VTX || parser->model == I750TC || parser->model == PROPLUSX || - parser->model == I770R) { + parser->model == I770R|| parser->model == SAGE) { temperature = data[offset + 11]; } else { unsigned int sign; @@ -957,7 +961,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ pressure = (((data[offset + 0] & 0x03) << 8) + data[offset + 1]) * 5; else if (parser->model == TX1 || parser->model == A300CS || parser->model == VTX || parser->model == I750TC || - parser->model == PROPLUSX || parser->model == I770R) + parser->model == PROPLUSX || parser->model == I770R || + parser->model == SAGE) pressure = array_uint16_le (data + offset + 4); else pressure -= data[offset + 1]; @@ -1008,7 +1013,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int have_deco = 0; unsigned int decostop = 0, decotime = 0; if (parser->model == A300CS || parser->model == VTX || - parser->model == I750TC || + parser->model == I750TC || parser->model == SAGE || parser->model == PROPLUSX || parser->model == I770R) { decostop = (data[offset + 15] & 0x70) >> 4; decotime = array_uint16_le(data + offset + 6) & 0x03FF; From e53e7cf96153f8475a771c1245e334fb48021cb4 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 30 Nov 2020 19:57:21 +0100 Subject: [PATCH 02/23] Re-use the common error handling code There is no need to duplicate the error cleanup code everywhere. Break out of the while loop and cleanup at the end of the function. --- src/oceanic_common.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/oceanic_common.c b/src/oceanic_common.c index 9a7c2e2..d4802fc 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -504,9 +504,8 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr { ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", rb_entry_first, rb_entry_last); - dc_rbstream_free (rbstream); - free (profiles); - return DC_STATUS_DATAFORMAT; + status = DC_STATUS_DATAFORMAT; + break; } // Calculate the end pointer and the number of bytes. @@ -533,9 +532,8 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr rc = dc_rbstream_read (rbstream, progress, profiles + offset, rb_entry_size + gap); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to read the dive."); - dc_rbstream_free (rbstream); - free (profiles); - return rc; + status = rc; + break; } remaining -= rb_entry_size + gap; @@ -570,7 +568,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr dc_rbstream_free (rbstream); free (profiles); - return DC_STATUS_SUCCESS; + return status; } From 9eddbe88be88bf9a6dfbbef5e7a74c9b6d0c23e9 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 30 Nov 2020 20:25:27 +0100 Subject: [PATCH 03/23] Skip logbook entries with invalid pointers Since logbook entries with invalid ringbuffer pointers are considered a fatal error, the download is aborted. The result is that any remaining entries, located after the invalid entry, can't be downloaded at all. This can be avoided by skipping the problematic entry instead of aborting the download. --- src/oceanic_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/oceanic_common.c b/src/oceanic_common.c index d4802fc..51c234f 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -415,7 +415,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", rb_entry_first, rb_entry_last); status = DC_STATUS_DATAFORMAT; - break; + continue; } // Calculate the end pointer and the number of bytes. @@ -505,7 +505,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", rb_entry_first, rb_entry_last); status = DC_STATUS_DATAFORMAT; - break; + continue; } // Calculate the end pointer and the number of bytes. From 9438064afc3e562e25b403d4fe48813ba6b2994b Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 14 Dec 2020 13:58:23 +0100 Subject: [PATCH 04/23] Fix the Mares Genius memory layout The Mares Genius appears to have 16M of flash memory, and it also supports 4K packets. --- src/mares_iconhd.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index 6388bb5..e2085eb 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -128,6 +128,12 @@ static const mares_iconhd_layout_t mares_iconhdnet_layout = { 0x100000, /* rb_profile_end */ }; +static const mares_iconhd_layout_t mares_genius_layout = { + 0x1000000, /* memsize */ + 0x0100000, /* rb_profile_begin */ + 0x1000000, /* rb_profile_end */ +}; + static const mares_iconhd_layout_t mares_matrix_layout = { 0x40000, /* memsize */ 0x0A000, /* rb_profile_begin */ @@ -560,8 +566,8 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_ device->packetsize = 256; break; case GENIUS: - device->layout = &mares_iconhdnet_layout; - device->packetsize = 256; + device->layout = &mares_genius_layout; + device->packetsize = 4096; device->fingerprint_size = 4; break; case ICONHDNET: From 484e9dcdc3a9b76945b693026eecef4a40a29e21 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 15 Dec 2020 14:34:24 +0100 Subject: [PATCH 05/23] Swap the object major and minor version --- src/mares_iconhd_parser.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index 5d35bea..afae746 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -365,8 +365,8 @@ mares_genius_cache (mares_iconhd_parser_t *parser) // Check the header type and version. unsigned int type = array_uint16_le (data); - unsigned int major = data[2]; - unsigned int minor = data[3]; + unsigned int minor = data[2]; + unsigned int major = data[3]; if (type != 1 || major != 0 || minor != 0) { ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).", type, major, minor); @@ -833,9 +833,9 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t // Check the profile type and version. unsigned int type = array_uint16_le (data); - unsigned int major = data[2]; - unsigned int minor = data[3]; - if (type != 0 || major != 2 || minor != 0) { + unsigned int minor = data[2]; + unsigned int major = data[3]; + if (type != 0 || major != 0 || minor != 2) { ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).", type, major, minor); return DC_STATUS_DATAFORMAT; From 8b06f2c31d437d6e067c21e7263b5ccc33539537 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 10 Dec 2020 13:40:06 +0100 Subject: [PATCH 06/23] Add support for the Mares Horizon The Mares Horizon is a variant of the Mares Genius, with a few changes to support SCR dives: The dive header is slightly modified. There is an extra 8 byte field at offset 0x18, which causes all later fields to have moved up with the same amount. This difference is indicated in both the object minor version (with a change from v0.0 to v0.1), and the logformat. For the profile data, there is a new SDPT sample type which contains a bit more information compared to the existing DPRS sample type. This difference is indicated with a change in the object type (from 0 to 1). The current implementation assumes a fixed order for the record types (a DSTR record, a TISS record, zero or more DPRS/SDPT records with an AIRS record every 4 sample, and finally a DEND record), and either only DPRS or SDPT records but never a mixture of the two. If these assumptions turns out to be incorrect, the implementation will need to be changed significantly. Note that the assumption of the fixed order was already present for the Genius. Bluetooth support is currently disabled in the Horizon firmware, but might be re-enabled in the future. --- src/descriptor.c | 1 + src/mares_iconhd.c | 5 +- src/mares_iconhd_parser.c | 157 ++++++++++++++++++++++++++------------ 3 files changed, 114 insertions(+), 49 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index cc80a59..f47c65a 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -294,6 +294,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Mares", "Quad Air", DC_FAMILY_MARES_ICONHD , 0x23, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Smart Air", DC_FAMILY_MARES_ICONHD , 0x24, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares}, + {"Mares", "Horizon", DC_FAMILY_MARES_ICONHD , 0x2C, DC_TRANSPORT_SERIAL, NULL}, /* Heinrichs Weikamp */ {"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL}, {"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL}, diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index e2085eb..2a70be3 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -49,6 +49,7 @@ #define QUADAIR 0x23 #define SMARTAIR 0x24 #define QUAD 0x29 +#define HORIZON 0x2C #define MAXRETRIES 4 @@ -162,6 +163,7 @@ mares_iconhd_get_model (mares_iconhd_device_t *device) {"Quad Air", QUADAIR}, {"Smart Air", SMARTAIR}, {"Quad", QUAD}, + {"Horizon", HORIZON}, }; // Check the product name in the version packet against the list @@ -566,6 +568,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_ device->packetsize = 256; break; case GENIUS: + case HORIZON: device->layout = &mares_genius_layout; device->packetsize = 4096; device->fingerprint_size = 4; @@ -958,7 +961,7 @@ mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, devinfo.serial = array_uint32_le (serial); device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); - if (device->model == GENIUS) { + if (device->model == GENIUS || device->model == HORIZON) { return mares_iconhd_device_foreach_object (abstract, callback, userdata); } else { return mares_iconhd_device_foreach_raw (abstract, callback, userdata); diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index afae746..5d26d13 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -38,6 +38,7 @@ #define GENIUS 0x1C #define QUADAIR 0x23 #define SMARTAIR 0x24 +#define HORIZON 0x2C #define NGASMIXES_ICONHD 3 #define NGASMIXES_GENIUS 5 @@ -58,6 +59,8 @@ #define GENIUS_TRIMIX 3 #define GENIUS_GAUGE 4 #define GENIUS_FREEDIVE 5 +#define GENIUS_SCR 6 +#define GENIUS_OC 7 // Record types and sizes #define DSTR_TYPE 0x44535452 // Dive start record @@ -66,6 +69,8 @@ #define TISS_SIZE 138 #define DPRS_TYPE 0x44505253 // Sample record #define DPRS_SIZE 34 +#define SDPT_TYPE 0x53445054 // SCR sample record +#define SDPT_SIZE 78 #define AIRS_TYPE 0x41495253 // Air integration record #define AIRS_SIZE 16 #define DEND_TYPE 0x44454E44 // Dive end record @@ -128,6 +133,7 @@ struct mares_iconhd_parser_t { unsigned int model; // Cached fields. unsigned int cached; + unsigned int logformat; unsigned int mode; unsigned int nsamples; unsigned int samplesize; @@ -331,6 +337,7 @@ mares_iconhd_cache (mares_iconhd_parser_t *parser) parser->base.size = length; // Cache the data for later use. + parser->logformat = 0; parser->mode = mode; parser->nsamples = nsamples; parser->samplesize = samplesize; @@ -358,7 +365,7 @@ mares_genius_cache (mares_iconhd_parser_t *parser) const unsigned char *data = parser->base.data; unsigned int size = parser->base.size; - if (size < 4) { + if (size < 20) { ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; } @@ -367,21 +374,30 @@ mares_genius_cache (mares_iconhd_parser_t *parser) unsigned int type = array_uint16_le (data); unsigned int minor = data[2]; unsigned int major = data[3]; - if (type != 1 || major != 0 || minor != 0) { + if (type != 1 || major != 0 || minor > 1) { ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).", type, major, minor); return DC_STATUS_DATAFORMAT; } + // Get the data format. + unsigned int logformat = data[0x10]; + + // The Horizon header has 8 bytes extra at offset 0x18. + unsigned int extra = 0; + if (logformat == 1) { + extra = 8; + } + // Get the header size. - unsigned int headersize = 0xB8; + unsigned int headersize = 0xB8 + extra; if (headersize > size) { ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; } // Get the number of samples in the profile data. - unsigned int nsamples = array_uint16_le (data + 0x20); + unsigned int nsamples = array_uint16_le (data + 0x20 + extra); // Get the dive settings. unsigned int settings = array_uint32_le (data + 0x0C); @@ -389,8 +405,11 @@ mares_genius_cache (mares_iconhd_parser_t *parser) // Get the dive mode. unsigned int mode = settings & 0xF; + // Get the sample size. + unsigned int samplesize = logformat == 1 ? SDPT_SIZE: DPRS_SIZE; + // Calculate the total number of bytes for this dive. - unsigned int nbytes = headersize + 4 + DSTR_SIZE + TISS_SIZE + nsamples * DPRS_SIZE + (nsamples / 4) * AIRS_SIZE + DEND_SIZE; + unsigned int nbytes = headersize + 4 + DSTR_SIZE + TISS_SIZE + nsamples * samplesize + (nsamples / 4) * AIRS_SIZE + DEND_SIZE; if (nbytes > size) { ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; @@ -402,7 +421,7 @@ mares_genius_cache (mares_iconhd_parser_t *parser) mares_iconhd_gasmix_t gasmix[NGASMIXES_GENIUS] = {0}; mares_iconhd_tank_t tank[NTANKS_GENIUS] = {0}; for (unsigned int i = 0; i < NGASMIXES_GENIUS; i++) { - unsigned int offset = 0x54 + i * 20; + unsigned int offset = 0x54 + extra + i * 20; unsigned int gasmixparams = array_uint32_le(data + offset + 0); unsigned int beginpressure = array_uint16_le(data + offset + 4); unsigned int endpressure = array_uint16_le(data + offset + 6); @@ -441,9 +460,10 @@ mares_genius_cache (mares_iconhd_parser_t *parser) } // Cache the data for later use. + parser->logformat = logformat; parser->mode = mode; parser->nsamples = nsamples; - parser->samplesize = DPRS_SIZE; + parser->samplesize = samplesize; parser->headersize = headersize; parser->settings = settings; parser->interval = 5; @@ -468,7 +488,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) return DC_STATUS_SUCCESS; } - if (parser->model == GENIUS) { + if (parser->model == GENIUS || parser->model == HORIZON) { return mares_genius_cache (parser); } else { return mares_iconhd_cache (parser); @@ -493,7 +513,8 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i // Set the default values. parser->model = model; parser->cached = 0; - parser->mode = (model == GENIUS) ? GENIUS_AIR : ICONHD_AIR; + parser->logformat = 0; + parser->mode = (model == GENIUS || model == HORIZON) ? GENIUS_AIR : ICONHD_AIR; parser->nsamples = 0; parser->samplesize = 0; parser->headersize = 0; @@ -526,7 +547,8 @@ mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data, // Reset the cache. parser->cached = 0; - parser->mode = (parser->model == GENIUS) ? GENIUS_AIR : ICONHD_AIR; + parser->logformat = 0; + parser->mode = (parser->model == GENIUS || parser->model == HORIZON) ? GENIUS_AIR : ICONHD_AIR; parser->nsamples = 0; parser->samplesize = 0; parser->headersize = 0; @@ -562,7 +584,7 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime // Pointer to the header data. const unsigned char *p = abstract->data; - if (parser->model != GENIUS) { + if (parser->model != GENIUS && parser->model != HORIZON) { p += abstract->size - parser->headersize; if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) { p += 4; @@ -570,7 +592,7 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime } // Offset to the date/time field. - if (parser->model == GENIUS) { + if (parser->model == GENIUS || parser->model == HORIZON) { p += 0x08; } else if (parser->model == SMARTAPNEA) { p += 0x40; @@ -581,7 +603,7 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime } if (datetime) { - if (parser->model == GENIUS) { + if (parser->model == GENIUS || parser->model == HORIZON) { unsigned int timestamp = array_uint32_le (p); datetime->hour = (timestamp ) & 0x1F; datetime->minute = (timestamp >> 5) & 0x3F; @@ -616,14 +638,21 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi // Pointer to the header data. const unsigned char *p = abstract->data; - if (parser->model != GENIUS) { + if (parser->model != GENIUS && parser->model != HORIZON) { p += abstract->size - parser->headersize; if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) { p += 4; } } - unsigned int metric = parser->model == GENIUS ? p[0x34] : parser->settings & 0x0100; + // The Horizon header has 8 bytes extra at offset 0x18. + unsigned int extra = 0; + if (parser->logformat == 1) { + extra = 8; + } + + unsigned int metric = (parser->model == GENIUS || parser->model == HORIZON) ? + p[0x34 + extra] : parser->settings & 0x0100; dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_tank_t *tank = (dc_tank_t *) value; @@ -632,7 +661,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi if (value) { switch (type) { case DC_FIELD_DIVETIME: - if (parser->model == GENIUS) { + if (parser->model == GENIUS || parser->model == HORIZON) { *((unsigned int *) value) = parser->nsamples * parser->interval; } else if (parser->model == SMARTAPNEA) { *((unsigned int *) value) = array_uint16_le (p + 0x24); @@ -649,8 +678,8 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi } break; case DC_FIELD_MAXDEPTH: - if (parser->model == GENIUS) - *((double *) value) = array_uint16_le (p + 0x22) / 10.0; + if (parser->model == GENIUS || parser->model == HORIZON) + *((double *) value) = array_uint16_le (p + 0x22 + extra) / 10.0; else if (parser->model == SMARTAPNEA) *((double *) value) = array_uint16_le (p + 0x3A) / 10.0; else if (parser->mode == ICONHD_FREEDIVE) @@ -691,8 +720,8 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi } break; case DC_FIELD_ATMOSPHERIC: - if (parser->model == GENIUS) - *((double *) value) = array_uint16_le (p + 0x3E) / 1000.0; + if (parser->model == GENIUS || parser->model == HORIZON) + *((double *) value) = array_uint16_le (p + 0x3E + extra) / 1000.0; else if (parser->model == SMARTAPNEA) *((double *) value) = array_uint16_le (p + 0x38) / 1000.0; else if (parser->mode == ICONHD_FREEDIVE) @@ -701,7 +730,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = array_uint16_le (p + 0x22) / 8000.0; break; case DC_FIELD_SALINITY: - if (parser->model == GENIUS) { + if (parser->model == GENIUS || parser->model == HORIZON) { unsigned int salinity = (parser->settings >> 5) & 0x03; switch (salinity) { case WATER_FRESH: @@ -737,8 +766,8 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi } break; case DC_FIELD_TEMPERATURE_MINIMUM: - if (parser->model == GENIUS) - *((double *) value) = (signed short) array_uint16_le (p + 0x28) / 10.0; + if (parser->model == GENIUS || parser->model == HORIZON) + *((double *) value) = (signed short) array_uint16_le (p + 0x28 + extra) / 10.0; else if (parser->model == SMARTAPNEA) *((double *) value) = (signed short) array_uint16_le (p + 0x3E) / 10.0; else if (parser->mode == ICONHD_FREEDIVE) @@ -747,8 +776,8 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = (signed short) array_uint16_le (p + 0x42) / 10.0; break; case DC_FIELD_TEMPERATURE_MAXIMUM: - if (parser->model == GENIUS) - *((double *) value) = (signed short) array_uint16_le (p + 0x26) / 10.0; + if (parser->model == GENIUS || parser->model == HORIZON) + *((double *) value) = (signed short) array_uint16_le (p + 0x26 + extra) / 10.0; else if (parser->model == SMARTAPNEA) *((double *) value) = (signed short) array_uint16_le (p + 0x3C) / 10.0; else if (parser->mode == ICONHD_FREEDIVE) @@ -757,12 +786,13 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = (signed short) array_uint16_le (p + 0x44) / 10.0; break; case DC_FIELD_DIVEMODE: - if (parser->model == GENIUS) { + if (parser->model == GENIUS || parser->model == HORIZON) { switch (parser->mode) { case GENIUS_AIR: case GENIUS_NITROX_SINGLE: case GENIUS_NITROX_MULTI: case GENIUS_TRIMIX: + case GENIUS_OC: *((dc_divemode_t *) value) = DC_DIVEMODE_OC; break; case GENIUS_GAUGE: @@ -771,6 +801,9 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi case GENIUS_FREEDIVE: *((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE; break; + case GENIUS_SCR: + *((dc_divemode_t *) value) = DC_DIVEMODE_SCR; + break; default: return DC_STATUS_DATAFORMAT; } @@ -823,11 +856,12 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t // Previous gas mix - initialize with impossible value unsigned int gasmix_previous = 0xFFFFFFFF; - unsigned int isairintegrated = (parser->model == ICONHDNET || parser->model == QUADAIR || parser->model == SMARTAIR || parser->model == GENIUS); + unsigned int isairintegrated = (parser->model == ICONHDNET || parser->model == QUADAIR || + parser->model == SMARTAIR || parser->model == GENIUS || parser->model == HORIZON); unsigned int offset = 4; unsigned int marker = 0; - if (parser->model == GENIUS) { + if (parser->model == GENIUS || parser->model == HORIZON) { // Skip the dive header. data += parser->headersize; @@ -835,7 +869,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t unsigned int type = array_uint16_le (data); unsigned int minor = data[2]; unsigned int major = data[3]; - if (type != 0 || major != 0 || minor != 2) { + if (type > 1 || major != 0 || minor != 2) { ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).", type, major, minor); return DC_STATUS_DATAFORMAT; @@ -894,7 +928,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t offset += 2 * parser->samplerate; } - } else if (parser->model != GENIUS && parser->mode == ICONHD_FREEDIVE) { + } else if (parser->model != GENIUS && parser->model != HORIZON && parser->mode == ICONHD_FREEDIVE) { unsigned int maxdepth = array_uint16_le (data + offset + 0); unsigned int divetime = array_uint16_le (data + offset + 2); unsigned int surftime = array_uint16_le (data + offset + 4); @@ -921,18 +955,46 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t nsamples++; } else { unsigned int depth = 0, temperature = 0; - unsigned int gasmix = 0, misc = 0, alarms = 0; - if (parser->model == GENIUS) { - if (!mares_genius_isvalid (data + offset, DPRS_SIZE, DPRS_TYPE)) { - ERROR (abstract->context, "Invalid DPRS record."); - return DC_STATUS_DATAFORMAT; - } + unsigned int gasmix = 0, alarms = 0; + unsigned int decostop = 0, decodepth = 0, decotime = 0, tts = 0; + if (parser->model == GENIUS || parser->model == HORIZON) { + if (parser->logformat == 1) { + if (!mares_genius_isvalid (data + offset, SDPT_SIZE, SDPT_TYPE)) { + ERROR (abstract->context, "Invalid SDPT record."); + return DC_STATUS_DATAFORMAT; + } - depth = array_uint16_le (data + offset + marker + 0); - temperature = array_uint16_le (data + offset + marker + 4); - alarms = array_uint32_le (data + offset + marker + 0x0C); - misc = array_uint32_le (data + offset + marker + 0x14); - gasmix = (misc >> 6) & 0xF; + unsigned int misc = 0, deco = 0; + depth = array_uint16_le (data + offset + marker + 2); + temperature = array_uint16_le (data + offset + marker + 6); + alarms = array_uint32_le (data + offset + marker + 0x14); + misc = array_uint32_le (data + offset + marker + 0x18); + deco = array_uint32_le (data + offset + marker + 0x1C); + gasmix = (misc >> 6) & 0x0F; + decostop = (misc >> 10) & 0x01; + if (decostop) { + decodepth = (deco >> 3) & 0x7F; + decotime = (deco >> 10) & 0xFF; + tts = (deco >> 18) & 0x3FFF; + } else { + decotime = deco & 0xFF; + } + } else { + if (!mares_genius_isvalid (data + offset, DPRS_SIZE, DPRS_TYPE)) { + ERROR (abstract->context, "Invalid DPRS record."); + return DC_STATUS_DATAFORMAT; + } + + unsigned int misc = 0; + depth = array_uint16_le (data + offset + marker + 0); + temperature = array_uint16_le (data + offset + marker + 4); + decotime = array_uint16_le (data + offset + marker + 0x0A); + alarms = array_uint32_le (data + offset + marker + 0x0C); + misc = array_uint32_le (data + offset + marker + 0x14); + gasmix = (misc >> 6) & 0x0F; + decostop = (misc >> 18) & 0x01; + decodepth = (misc >> 19) & 0x7F; + } } else { depth = array_uint16_le (data + offset + 0); temperature = array_uint16_le (data + offset + 2) & 0x0FFF; @@ -965,10 +1027,8 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t } } - if (parser->model == GENIUS) { + if (parser->model == GENIUS || parser->model == HORIZON) { // Deco stop / NDL. - unsigned int decostop = (misc >> 18) & 0x01; - unsigned int decodepth = (misc >> 19) & 0x7F; if (decostop) { sample.deco.type = DC_DECO_DECOSTOP; sample.deco.depth = decodepth; @@ -976,7 +1036,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t sample.deco.type = DC_DECO_NDL; sample.deco.depth = 0.0; } - sample.deco.time = array_uint16_le (data + offset + marker + 0x0A) * 60; + sample.deco.time = decotime * 60; if (callback) callback (DC_SAMPLE_DECO, sample, userdata); // Alarms @@ -1013,7 +1073,8 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t // Some extra data. if (isairintegrated && (nsamples % 4) == 0) { - if (parser->model == GENIUS && !mares_genius_isvalid (data + offset, AIRS_SIZE, AIRS_TYPE)) { + if ((parser->model == GENIUS || parser->model == HORIZON) && + !mares_genius_isvalid (data + offset, AIRS_SIZE, AIRS_TYPE)) { ERROR (abstract->context, "Invalid AIRS record."); return DC_STATUS_DATAFORMAT; } @@ -1028,12 +1089,12 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t WARNING (abstract->context, "Invalid tank with non-zero pressure."); } - offset += (parser->model == GENIUS) ? AIRS_SIZE : 8; + offset += (parser->model == GENIUS || parser->model == HORIZON) ? AIRS_SIZE : 8; } } } - if (parser->model == GENIUS) { + if (parser->model == GENIUS || parser->model == HORIZON) { // Skip the DEND record. if (!mares_genius_isvalid (data + offset, DEND_SIZE, DEND_TYPE)) { ERROR (abstract->context, "Invalid DEND record."); From cebf4089cc6788a257fdceef33ce5f9ac064655b Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 25 Aug 2020 15:12:12 +0200 Subject: [PATCH 07/23] Verify the oxygen and helium percentage The oxygen and helium percentage in the gas change event should correspond to the percentages indicated in the dive header. --- src/suunto_d9_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index 11b99e9..f735a7e 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -757,7 +757,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca if ((type & 0x80) == 0) { idx += parser->nccr; } - if (idx >= parser->ngasmixes) { + if (idx >= parser->ngasmixes || o2 != parser->oxygen[idx] || he != parser->helium[idx]) { ERROR (abstract->context, "Invalid gas mix."); return DC_STATUS_DATAFORMAT; } From e592c7e7b7317c5eec1e0038031f4b70a499a31f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 10 Dec 2020 08:00:07 +0100 Subject: [PATCH 08/23] Use some more descriptive variable names --- src/suunto_d9_parser.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index f735a7e..6bf33b8 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -553,7 +553,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca if ((nsamples + 1) == marker) { while (offset < size) { unsigned int event = data[offset++]; - unsigned int seconds, type, unknown, heading; + unsigned int seconds, type, state, number, heading; unsigned int current, next; unsigned int he, o2, ppo2, idx; unsigned int length; @@ -582,7 +582,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; } - unknown = data[offset + 0]; + state = data[offset + 0]; seconds = data[offset + 1]; sample.event.type = SAMPLE_EVENT_SURFACE; sample.event.time = seconds; @@ -701,7 +701,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; } - unknown = data[offset + 0]; + number = data[offset + 0]; seconds = data[offset + 1]; heading = array_uint16_le (data + offset + 2); if (heading == 0xFFFF) { From 6c9a758648016412108f56c0f58044b6299d5bd3 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 1 Jan 2021 21:25:58 +0100 Subject: [PATCH 09/23] Implement the rbt sample The name of the RBT (Remaining Bottom Time) sample was taken from the Uwatec dive computers. The actual definition depends on the dive computer, but it usually corresponds to the air time remaining (with or without some additional factors taken into account). --- src/suunto_eonsteel_parser.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 33a6b3d..7a4c032 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -551,7 +551,8 @@ static void sample_gastime(struct sample_data *info, short gastime) if (gastime < 0) return; - // Hmm. We have no good way to report airtime remaining + sample.rbt = gastime / 60; + if (info->callback) info->callback (DC_SAMPLE_RBT, sample, info->userdata); } /* From b97acabb01446553acd76195174f2118eca6f389 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 17 Jul 2020 14:11:15 +0200 Subject: [PATCH 10/23] Remove unused variables --- src/hw_ostc_parser.c | 2 -- src/oceanic_atom2_parser.c | 2 -- src/suunto_d9_parser.c | 2 -- src/suunto_eonsteel_parser.c | 2 -- src/suunto_vyper_parser.c | 2 -- 5 files changed, 10 deletions(-) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 117064b..714318b 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -390,7 +390,6 @@ hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) { hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract; const unsigned char *data = abstract->data; - unsigned int size = abstract->size; // Cache the header data. dc_status_t rc = hw_ostc_parser_cache (parser); @@ -451,7 +450,6 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned { hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract; const unsigned char *data = abstract->data; - unsigned int size = abstract->size; // Cache the header data. dc_status_t rc = hw_ostc_parser_cache (parser); diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index e2a54ff..9ddb1d4 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -527,9 +527,7 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns { 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); diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index 6bf33b8..bd91743 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -348,9 +348,7 @@ static dc_status_t suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) { suunto_d9_parser_t *parser = (suunto_d9_parser_t*) abstract; - const unsigned char *data = abstract->data; - unsigned int size = abstract->size; // Cache the gas mix data. dc_status_t rc = suunto_d9_parser_cache (parser); diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 7a4c032..3c4040b 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -1246,8 +1246,6 @@ static float get_le32_float(const unsigned char *src) static int traverse_device_fields(suunto_eonsteel_parser_t *eon, const struct type_desc *desc, const unsigned char *data, int len) { - const char *name = desc->desc + strlen("sml.DeviceLog.Device."); - return 0; } diff --git a/src/suunto_vyper_parser.c b/src/suunto_vyper_parser.c index 80f7d54..369ad5c 100644 --- a/src/suunto_vyper_parser.c +++ b/src/suunto_vyper_parser.c @@ -234,9 +234,7 @@ static dc_status_t suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) { suunto_vyper_parser_t *parser = (suunto_vyper_parser_t *) abstract; - const unsigned char *data = abstract->data; - unsigned int size = abstract->size; dc_gasmix_t *gas = (dc_gasmix_t *) value; dc_tank_t *tank = (dc_tank_t *) value; From 548fce69f8a21525a934e2ef050dc0d394b374f4 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 17 Jul 2020 14:24:49 +0200 Subject: [PATCH 11/23] Fix -Wswitch compiler warning Add a default label to prevent warnings for all enum values not handled in the switch statement. It's intentional in this piece of code. --- src/suunto_eonsteel_parser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 3c4040b..0d519cd 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -1427,6 +1427,8 @@ static int traverse_sample_fields(suunto_eonsteel_parser_t *eon, const struct ty set_depth_field(eon, array_uint16_le(data)); data += 2; continue; + default: + break; } break; } From 7c9726da64db1477e71c16b3a93353fd5826c41e Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 18 Jul 2020 00:26:42 +0200 Subject: [PATCH 12/23] Fix -Wcast-qual compiler warning String literals have the type 'char[N]' by default. Allthough they are not really 'const', modifying a string literal is undefined behaviour. Therefore, to avoid mistakes, libdivecomputer uses the -Wwrite-strings compiler option to change the default type to 'const char[N]'. The cast that triggers the -Wcast-qual warning can be avoided by using a character array instead of string literal. --- examples/dctool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/dctool.c b/examples/dctool.c index ddcd596..3104bc4 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -240,7 +240,8 @@ main (int argc, char *argv[]) } // Translate the help option into a command. - char *argv_help[] = {(char *) "help", NULL, NULL}; + char helpcmd[] = "help"; + char *argv_help[] = {helpcmd, NULL, NULL}; if (help || argv[0] == NULL) { if (argv[0]) { argv_help[1] = argv[0]; From 8f383ac5314126d68afd71265a0c1bf866aa9ab7 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 18 Jul 2020 00:28:18 +0200 Subject: [PATCH 13/23] Fix -Wshadow compiler warnings Rename a few variables, parameters and functions to avoid shadowing others. --- src/context.c | 4 ++-- src/oceanic_vtpro.c | 4 ++-- src/reefnet_sensuspro_parser.c | 4 ++-- src/suunto_eonsteel_parser.c | 13 ++++++------- src/suunto_solution_parser.c | 8 ++++---- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/context.c b/src/context.c index c7642e6..88fd9b5 100644 --- a/src/context.c +++ b/src/context.c @@ -130,7 +130,7 @@ l_hexdump (char *str, size_t size, const unsigned char data[], size_t n) } static void -logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata) +loghandler (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata) { const char *loglevels[] = {"NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL"}; @@ -166,7 +166,7 @@ dc_context_new (dc_context_t **out) #ifdef ENABLE_LOGGING context->loglevel = DC_LOGLEVEL_WARNING; - context->logfunc = logfunc; + context->logfunc = loghandler; #else context->loglevel = DC_LOGLEVEL_NONE; context->logfunc = NULL; diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index 22d61fd..74b94ec 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -592,8 +592,8 @@ oceanic_vtpro_device_version (dc_device_t *abstract, unsigned char data[], unsig return rc; // Verify the checksum of the answer. - unsigned char crc = answer[PAGESIZE / 2]; - unsigned char ccrc = checksum_add_uint4 (answer, PAGESIZE / 2, 0x00); + crc = answer[PAGESIZE / 2]; + ccrc = checksum_add_uint4 (answer, PAGESIZE / 2, 0x00); if (crc != ccrc) { ERROR (abstract->context, "Unexpected answer checksum."); return DC_STATUS_PROTOCOL; diff --git a/src/reefnet_sensuspro_parser.c b/src/reefnet_sensuspro_parser.c index fe62668..7e68a72 100644 --- a/src/reefnet_sensuspro_parser.c +++ b/src/reefnet_sensuspro_parser.c @@ -163,8 +163,8 @@ reefnet_sensuspro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, while (offset + sizeof (footer) <= size && memcmp (data + offset, footer, sizeof (footer)) != 0) { - unsigned int value = array_uint16_le (data + offset); - unsigned int depth = (value & 0x01FF); + unsigned int raw = array_uint16_le (data + offset); + unsigned int depth = (raw & 0x01FF); if (depth > maxdepth) maxdepth = depth; diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 0d519cd..d8dcdcc 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -366,10 +366,10 @@ static int record_type(suunto_eonsteel_parser_t *eon, unsigned short type, const return 0; } -static int traverse_entry(suunto_eonsteel_parser_t *eon, const unsigned char *p, int len, eon_data_cb_t callback, void *user) +static int traverse_entry(suunto_eonsteel_parser_t *eon, const unsigned char *p, int size, eon_data_cb_t callback, void *user) { - const unsigned char *name, *data, *end, *last, *one_past_end = p + len; - int textlen, type; + const unsigned char *name, *data, *end, *last, *one_past_end = p + size; + int textlen, id; int rc; // First two bytes: zero and text length @@ -388,7 +388,7 @@ static int traverse_entry(suunto_eonsteel_parser_t *eon, const unsigned char *p, // Two bytes of 'type' followed by the name/descriptor, followed by the data data = name + textlen; - type = array_uint16_le(name); + id = array_uint16_le(name); name += 2; if (*name != '<') { @@ -396,7 +396,7 @@ static int traverse_entry(suunto_eonsteel_parser_t *eon, const unsigned char *p, return -1; } - record_type(eon, type, (const char *) name, textlen-3); + record_type(eon, id, (const char *) name, textlen-3); end = data; last = data; @@ -982,8 +982,7 @@ static int traverse_samples(unsigned short type, const struct type_desc *desc, c info->ceiling = 0.0; for (i = 0; i < EON_MAX_GROUP; i++) { - enum eon_sample type = desc->type[i]; - int bytes = handle_sample_type(desc, info, type, data); + int bytes = handle_sample_type(desc, info, desc->type[i], data); if (!bytes) break; diff --git a/src/suunto_solution_parser.c b/src/suunto_solution_parser.c index 9b2ac9d..34aab7d 100644 --- a/src/suunto_solution_parser.c +++ b/src/suunto_solution_parser.c @@ -110,10 +110,10 @@ suunto_solution_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u unsigned int depth = 0, maxdepth = 0; unsigned int offset = 3; while (offset < size && data[offset] != 0x80) { - unsigned char value = data[offset++]; - if (value < 0x7e || value > 0x82) { - depth += (signed char) value; - if (value == 0x7D || value == 0x83) { + unsigned char raw = data[offset++]; + if (raw < 0x7e || raw > 0x82) { + depth += (signed char) raw; + if (raw == 0x7D || raw == 0x83) { if (offset + 1 > size) return DC_STATUS_DATAFORMAT; depth += (signed char) data[offset++]; From 1130b7eadef1c7688c8b0386b4dd479f216553cb Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 20 Jul 2020 00:06:12 +0200 Subject: [PATCH 14/23] Fix -Wsign-compare compiler warnings Comparing signed and unsigned integer expressions can have unexpected results because the signed integer will get promoted to an unsigned integer. To avoid the warning, add an explicit cast to the unsigned type, along with a check to catch negative values. --- examples/dctool_parse.c | 2 +- examples/output_raw.c | 4 ++-- src/context.c | 2 +- src/hw_ostc3.c | 2 +- src/suunto_d9.c | 3 ++- src/suunto_eonsteel_parser.c | 6 ++---- src/suunto_vyper2.c | 3 ++- src/usbhid.c | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/dctool_parse.c b/examples/dctool_parse.c index 6ea8550..6b7da08 100644 --- a/examples/dctool_parse.c +++ b/examples/dctool_parse.c @@ -152,7 +152,7 @@ dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t goto cleanup; } - for (unsigned int i = 0; i < argc; ++i) { + for (int i = 0; i < argc; ++i) { // Read the input file. buffer = dctool_file_read (argv[i]); if (buffer == NULL) { diff --git a/examples/output_raw.c b/examples/output_raw.c index 951531e..9e71780 100644 --- a/examples/output_raw.c +++ b/examples/output_raw.c @@ -80,7 +80,7 @@ mktemplate_datetime (char *buffer, size_t size, dc_parser_t *parser) n = snprintf (buffer, size, "%04i%02i%02iT%02i%02i%02i", datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second); - if (n < 0 || n >= size) + if (n < 0 || (size_t) n >= size) return -1; return n; @@ -92,7 +92,7 @@ mktemplate_number (char *buffer, size_t size, unsigned int number) int n = 0; n = snprintf (buffer, size, "%04u", number); - if (n < 0 || n >= size) + if (n < 0 || (size_t) n >= size) return -1; return n; diff --git a/src/context.c b/src/context.c index 88fd9b5..cab6f33 100644 --- a/src/context.c +++ b/src/context.c @@ -77,7 +77,7 @@ l_vsnprintf (char *str, size_t size, const char *format, va_list ap) * enough. */ n = vsnprintf (str, size, format, ap); - if (n >= size) + if (n >= 0 && (size_t) n >= size) n = -1; #endif diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index c669ea2..3ed6bc7 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -1024,7 +1024,7 @@ hw_ostc3_firmware_readline (FILE *fp, dc_context_t *context, unsigned int addr, unsigned char ascii[39]; unsigned char faddr_byte[3]; unsigned int faddr = 0; - int n = 0; + size_t n = 0; if (size > 16) { ERROR (context, "Invalid arguments."); diff --git a/src/suunto_d9.c b/src/suunto_d9.c index ab6eee1..8b8320e 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -261,7 +261,8 @@ suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], u } // Verify the size of the package. - if (array_uint16_be (answer + 1) + 4 != asize) { + unsigned int len = array_uint16_be (answer + 1); + if (len + 4 != asize) { ERROR (abstract->context, "Unexpected answer size."); return DC_STATUS_PROTOCOL; } diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index d8dcdcc..a941518 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -137,7 +137,6 @@ static const struct { static enum eon_sample lookup_descriptor_type(suunto_eonsteel_parser_t *eon, struct type_desc *desc) { - int i; const char *name = desc->desc; // Not a sample type? Skip it @@ -160,7 +159,7 @@ static enum eon_sample lookup_descriptor_type(suunto_eonsteel_parser_t *eon, str name += 8; // .. and look it up in the table of sample type strings - for (i = 0; i < C_ARRAY_SIZE(type_translation); i++) { + for (size_t i = 0; i < C_ARRAY_SIZE(type_translation); i++) { if (!strcmp(name, type_translation[i].name)) return type_translation[i].type; } @@ -179,8 +178,7 @@ static parser_sample_event_t lookup_event(const char *name, const eon_event_t ev static const char *desc_type_name(enum eon_sample type) { - int i; - for (i = 0; i < C_ARRAY_SIZE(type_translation); i++) { + for (size_t i = 0; i < C_ARRAY_SIZE(type_translation); i++) { if (type == type_translation[i].type) return type_translation[i].name; } diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c index 02f38ed..7a9f7ce 100644 --- a/src/suunto_vyper2.c +++ b/src/suunto_vyper2.c @@ -252,7 +252,8 @@ suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[ } // Verify the size of the package. - if (array_uint16_be (answer + 1) + 4 != asize) { + unsigned int len = array_uint16_be (answer + 1); + if (len + 4 != asize) { ERROR (abstract->context, "Unexpected answer size."); return DC_STATUS_PROTOCOL; } diff --git a/src/usbhid.c b/src/usbhid.c index 9231e64..b3805ca 100644 --- a/src/usbhid.c +++ b/src/usbhid.c @@ -777,7 +777,7 @@ dc_usbhid_write (dc_iostream_t *abstract, const void *data, size_t size, size_t out: #ifdef _WIN32 - if (nbytes > size) { + if ((size_t) nbytes > size) { WARNING (abstract->context, "Number of bytes exceeds the buffer size (" DC_PRINTF_SIZE " > " DC_PRINTF_SIZE ")!", nbytes, size); nbytes = size; } From 0688b74099bc8550cfed55ad3a6aa8a06e4af17c Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 20 Jul 2020 00:24:17 +0200 Subject: [PATCH 15/23] Use an unsigned integer for the length This avoids -Wsign-compare compiler warnings due to comparison of integer expressions of different signedness. --- src/suunto_eonsteel_parser.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index a941518..033a2f2 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -95,7 +95,7 @@ typedef struct suunto_eonsteel_parser_t { } cache; } suunto_eonsteel_parser_t; -typedef int (*eon_data_cb_t)(unsigned short type, const struct type_desc *desc, const unsigned char *data, int len, void *user); +typedef int (*eon_data_cb_t)(unsigned short type, const struct type_desc *desc, const unsigned char *data, unsigned int len, void *user); typedef struct eon_event_t { const char *name; @@ -858,7 +858,7 @@ static void sample_setpoint_automatic(struct sample_data *info, unsigned char va DEBUG(info->eon->base.context, "sample_setpoint_automatic(%u)", value); } -static int handle_sample_type(const struct type_desc *desc, struct sample_data *info, enum eon_sample type, const unsigned char *data) +static unsigned int handle_sample_type(const struct type_desc *desc, struct sample_data *info, enum eon_sample type, const unsigned char *data) { switch (type) { case ES_dtime: @@ -966,7 +966,7 @@ static int handle_sample_type(const struct type_desc *desc, struct sample_data * } } -static int traverse_samples(unsigned short type, const struct type_desc *desc, const unsigned char *data, int len, void *user) +static int traverse_samples(unsigned short type, const struct type_desc *desc, const unsigned char *data, unsigned int len, void *user) { struct sample_data *info = (struct sample_data *) user; suunto_eonsteel_parser_t *eon = info->eon; @@ -980,7 +980,7 @@ static int traverse_samples(unsigned short type, const struct type_desc *desc, c info->ceiling = 0.0; for (i = 0; i < EON_MAX_GROUP; i++) { - int bytes = handle_sample_type(desc, info, desc->type[i], data); + unsigned int bytes = handle_sample_type(desc, info, desc->type[i], data); if (!bytes) break; @@ -1432,7 +1432,7 @@ static int traverse_sample_fields(suunto_eonsteel_parser_t *eon, const struct ty return 0; } -static int traverse_fields(unsigned short type, const struct type_desc *desc, const unsigned char *data, int len, void *user) +static int traverse_fields(unsigned short type, const struct type_desc *desc, const unsigned char *data, unsigned int len, void *user) { suunto_eonsteel_parser_t *eon = (suunto_eonsteel_parser_t *) user; From 10a4ec0b08af7fc7ae29d69c8598a3d1f9eca5b0 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 22 Jul 2020 00:12:24 +0200 Subject: [PATCH 16/23] Define DC_TIMEZONE_NONE as a signed integer The hexadecimal value 0x80000000 is too large to be represented as a signed 32bit integer. Therefore the default type for the constant is an unsigned 32bit integer. This is a bit annoying because the timezone field is actually defined as a signed integer, and thus comparisions produce -Wsign-compare compiler warnings. Fixed by switching to INT_MIN, which is the same underlying value but interpreted as a signed integer. --- include/libdivecomputer/datetime.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/libdivecomputer/datetime.h b/include/libdivecomputer/datetime.h index 768883d..e5b876f 100644 --- a/include/libdivecomputer/datetime.h +++ b/include/libdivecomputer/datetime.h @@ -22,11 +22,13 @@ #ifndef DC_DATETIME_H #define DC_DATETIME_H +#include + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#define DC_TIMEZONE_NONE 0x80000000 +#define DC_TIMEZONE_NONE INT_MIN #if defined (_WIN32) && !defined (__GNUC__) typedef __int64 dc_ticks_t; From b0cce363f1e39a55924d5379e22a668185793fef Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 22 Jul 2020 00:26:07 +0200 Subject: [PATCH 17/23] Limit the size to INT_MAX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allthough the input buffer size has type 'size_t', the return value of the function has only type 'int'. Hence the function can't support input buffers larger than INT_MAX. This allows to fix a -Wsign-compare compiler warning: operand of ?: changes signedness from ‘int’ to ‘size_t’ due to unsignedness of other operand. --- src/context.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/context.c b/src/context.c index cab6f33..21c1610 100644 --- a/src/context.c +++ b/src/context.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN @@ -104,7 +105,7 @@ l_hexdump (char *str, size_t size, const unsigned char data[], size_t n) '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - if (size == 0) + if (size == 0 || size > INT_MAX) return -1; /* The maximum number of bytes. */ @@ -126,7 +127,7 @@ l_hexdump (char *str, size_t size, const unsigned char data[], size_t n) /* Null terminate the hex string. */ str[length * 2] = 0; - return (n > maxlength ? -1 : length * 2); + return (n > maxlength ? -1 : (int) (length * 2)); } static void From fc76b4a25872d71341203fd69c7d72524e628ecf Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 24 Aug 2020 13:24:54 +0200 Subject: [PATCH 18/23] Use the cross-platform socket file descriptor type Windows and unix use a diferent data type for representing socket file descriptors (SOCKET vs int). This mismatch results in a compiler warning when comparing to S_INVALID. --- src/irda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/irda.c b/src/irda.c index 448c57c..2cc58ab 100644 --- a/src/irda.c +++ b/src/irda.c @@ -155,7 +155,7 @@ dc_irda_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_ } // Open the socket. - int fd = socket (AF_IRDA, SOCK_STREAM, 0); + s_socket_t fd = socket (AF_IRDA, SOCK_STREAM, 0); if (fd == S_INVALID) { s_errcode_t errcode = S_ERRNO; SYSERROR (context, errcode); From 5eddaeade6c4574a93516b1183e3283382324179 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 4 Sep 2020 07:58:03 +0200 Subject: [PATCH 19/23] Use an unsigned integer for the number of dives Because the dive_count variable is decremented, it doesn't contain the total number of dives, but the index of the last dive. A negative number indicates no dives. The same result can be obtained by using the total number of dives directly. That's not only more intuitive, but also fixes a -Wsign-compare compiler warning. --- src/cochran_commander.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 63a00ba..7e8348e 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -621,7 +621,7 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d // We track profile ringbuffer usage to determine which dives have profile data int profile_capacity_remaining = device->layout->rb_profile_end - device->layout->rb_profile_begin; - int dive_count = -1; + unsigned int dive_count = 0; data->fp_dive_num = -1; // Start at end of log @@ -629,7 +629,6 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d dive_count = data->dive_count; else dive_count = device->layout->rb_logbook_entry_count; - dive_count--; unsigned int sample_read_size = 0; data->invalid_profile_dive_num = -1; @@ -676,7 +675,7 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d // Loop through dives to find FP, Accumulate profile data size, // and find the last dive with invalid profile - for (unsigned int i = 0; i <= dive_count; ++i) { + for (unsigned int i = 0; i < dive_count; ++i) { unsigned int idx = (device->layout->rb_logbook_entry_count + head_dive - (i + 1)) % device->layout->rb_logbook_entry_count; unsigned char *log_entry = data->logbook + idx * device->layout->rb_logbook_entry_size; From ba6a8a43f722bd0b2f3fca953e119d0002ec2733 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 4 Sep 2020 08:10:00 +0200 Subject: [PATCH 20/23] Use an unsigned value to represent the undefined state This fixes some more -Wsign-compare compiler warnings. --- src/cochran_commander.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 7e8348e..e3677e9 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -41,6 +41,8 @@ #define COCHRAN_MODEL_EMC_16 4 #define COCHRAN_MODEL_EMC_20 5 +#define UNDEFINED 0xFFFFFFFF + typedef enum cochran_endian_t { ENDIAN_LE, ENDIAN_BE, @@ -57,8 +59,8 @@ typedef struct cochran_data_t { unsigned char *logbook; unsigned short int dive_count; - int fp_dive_num; - int invalid_profile_dive_num; + unsigned int fp_dive_num; + unsigned int invalid_profile_dive_num; unsigned int logbook_size; } cochran_data_t; @@ -622,7 +624,7 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d int profile_capacity_remaining = device->layout->rb_profile_end - device->layout->rb_profile_begin; unsigned int dive_count = 0; - data->fp_dive_num = -1; + data->fp_dive_num = UNDEFINED; // Start at end of log if (data->dive_count < device->layout->rb_logbook_entry_count) @@ -631,7 +633,7 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d dive_count = device->layout->rb_logbook_entry_count; unsigned int sample_read_size = 0; - data->invalid_profile_dive_num = -1; + data->invalid_profile_dive_num = UNDEFINED; // Remove the pre-dive events that occur after the last dive unsigned int rb_head_ptr = 0; @@ -952,7 +954,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call } // Change tail to dive following the fingerprint dive. - if (data.fp_dive_num > -1) + if (data.fp_dive_num != UNDEFINED) tail_dive = (data.fp_dive_num + 1) % layout->rb_logbook_entry_count; // Number of dives to read From d5dffb70be8279d3ef24fd1d7ad924c97c968185 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 3 Apr 2020 12:19:25 +0200 Subject: [PATCH 21/23] Avoid generating the SIGPIPE signal Handling the SIGPIPE signal in a library is tricky, because installing a signal handler does affects the entire application. But we can at least try to avoid generating the SIGPIPE signal ourselves. On Linux, that requires the use of the MSG_NOSIGNAL flag, and on Mac and BSD setting the SO_NOSIGPIPE socket option. --- src/socket.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/socket.c b/src/socket.c index e9412ab..84d58a4 100644 --- a/src/socket.c +++ b/src/socket.c @@ -24,6 +24,10 @@ #include "common-private.h" #include "context-private.h" +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + dc_status_t dc_socket_syserror (s_errcode_t errcode) { @@ -106,8 +110,22 @@ dc_socket_open (dc_iostream_t *abstract, int family, int type, int protocol) goto error; } +#ifdef SO_NOSIGPIPE + int optval = 1; + if (setsockopt(device->fd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) != 0) { + s_errcode_t errcode = S_ERRNO; + SYSERROR (abstract->context, errcode); + status = dc_socket_syserror(errcode); + goto error_close; + } +#endif + return DC_STATUS_SUCCESS; +#ifdef SO_NOSIGPIPE +error_close: + S_CLOSE (device->fd); +#endif error: dc_socket_exit (abstract->context); return status; @@ -304,7 +322,7 @@ dc_socket_write (dc_iostream_t *abstract, const void *data, size_t size, size_t break; // Timeout. } - s_ssize_t n = send (socket->fd, (const char *) data + nbytes, size - nbytes, 0); + s_ssize_t n = send (socket->fd, (const char *) data + nbytes, size - nbytes, MSG_NOSIGNAL); if (n < 0) { s_errcode_t errcode = S_ERRNO; if (errcode == S_EINTR || errcode == S_EAGAIN) From 0239329f06eea96812f54cde92b5b4db36f46bb4 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 11 Jan 2021 20:45:35 +0100 Subject: [PATCH 22/23] Add support for the new iX3M 2021 models The new iX3M 2021 models (refered to as 'iX3M with Sequared Buttons' in the Ratio support section) identify as iX5M in the Bluetooth name. Reported-by: Damian Zaremba --- src/descriptor.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/descriptor.c b/src/descriptor.c index f47c65a..7f4a966 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -384,6 +384,18 @@ static const dc_descriptor_t g_descriptors[] = { {"Ratio", "iDive Color Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x54, DC_TRANSPORT_SERIAL, NULL}, {"Ratio", "iDive Color Tech+",DC_FAMILY_DIVESYSTEM_IDIVE, 0x55, DC_TRANSPORT_SERIAL, NULL}, {"Ratio", "iDive Color Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x56, DC_TRANSPORT_SERIAL, NULL}, + {"Ratio", "iX3M 2021 GPS Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x60, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M 2021 GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x61, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M 2021 GPS Pro ", DC_FAMILY_DIVESYSTEM_IDIVE, 0x62, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M 2021 GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x63, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M 2021 GPS Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x64, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M 2021 GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x65, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M 2021 Pro Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x70, DC_TRANSPORT_SERIAL, NULL}, + {"Ratio", "iX3M 2021 Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x71, DC_TRANSPORT_SERIAL, NULL}, + {"Ratio", "iX3M 2021 Pro Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x72, DC_TRANSPORT_SERIAL, NULL}, + {"Ratio", "iX3M 2021 Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x73, DC_TRANSPORT_SERIAL, NULL}, + {"Ratio", "iX3M 2021 Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x74, DC_TRANSPORT_SERIAL, NULL}, + {"Ratio", "iX3M 2021 Pro Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x75, DC_TRANSPORT_SERIAL, NULL}, {"Seac", "Jack", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1000, DC_TRANSPORT_SERIAL, NULL}, {"Seac", "Guru", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1002, DC_TRANSPORT_SERIAL, NULL}, /* Cochran Commander */ @@ -630,6 +642,7 @@ static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, { static const char * const bluetooth[] = { "DS", + "IX5M", }; if (transport == DC_TRANSPORT_BLUETOOTH) { From 939470df526f4dc50ee2c5f33405bc38fcf90184 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 11 Jan 2021 20:54:53 +0100 Subject: [PATCH 23/23] Wait before sending the firmware data Without the small delay, sending the first frame often fails. Trying to read the ACK response byte just fails with a timeout, and no data is received at all. The bootloader is probably not ready to receive data yet. --- src/divesystem_idive.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index 0659d06..b544ecb 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -903,6 +903,9 @@ divesystem_idive_device_fwupdate (dc_device_t *abstract, const char *filename) goto error_free; } + // Wait before sending the firmware data. + dc_iostream_sleep (device->iostream, 100); + // Upload the firmware. unsigned int offset = 0; while (offset + 2 <= size) {