From be8b95fdf9fce93a63bbd43d5d1c7e54bbe09efb Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 5 Sep 2017 20:25:30 +0200 Subject: [PATCH 01/13] Implement the tank pressure With the new APOS4 firmware, the latest ix3m and idive models support a wireless tank sensor. For dives without a tank pressure sensor, the pressure field in the sample is zero. Thus the first non-zero value indicates the presence of a tank sensor. --- src/divesystem_idive_parser.c | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index f37d142..ca5c2b1 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -64,6 +64,8 @@ struct divesystem_idive_parser_t { unsigned int ngasmixes; unsigned int oxygen[NGASMIXES]; unsigned int helium[NGASMIXES]; + unsigned int beginpressure; + unsigned int endpressure; }; static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size); @@ -113,6 +115,8 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign parser->oxygen[i] = 0; parser->helium[i] = 0; } + parser->beginpressure = 0; + parser->endpressure = 0; *out = (dc_parser_t*) parser; @@ -135,6 +139,8 @@ divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *da parser->oxygen[i] = 0; parser->helium[i] = 0; } + parser->beginpressure = 0; + parser->endpressure = 0; return DC_STATUS_SUCCESS; } @@ -173,6 +179,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, } dc_gasmix_t *gasmix = (dc_gasmix_t *) value; + dc_tank_t *tank = (dc_tank_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; if (value) { @@ -191,6 +198,19 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, gasmix->oxygen = parser->oxygen[flags] / 100.0; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; + case DC_FIELD_TANK_COUNT: + if (parser->beginpressure == 0 && parser->endpressure == 0) + return DC_STATUS_UNSUPPORTED; + *((unsigned int *) value) = 1; + break; + case DC_FIELD_TANK: + tank->type = DC_TANKVOLUME_NONE; + tank->volume = 0.0; + tank->workpressure = 0.0; + tank->beginpressure = parser->beginpressure; + tank->endpressure = parser->endpressure; + tank->gasmix = DC_GASMIX_UNKNOWN; + break; case DC_FIELD_ATMOSPHERIC: if (parser->model >= IX3M_EASY) { *((double *) value) = array_uint16_le (data + 11) / 10000.0; @@ -249,6 +269,8 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba unsigned int he_previous = 0xFFFFFFFF; unsigned int mode_previous = INVALID; unsigned int divemode = INVALID; + unsigned int beginpressure = 0; + unsigned int endpressure = 0; unsigned int nsamples = array_uint16_le (data + 1); unsigned int samplesize = SZ_SAMPLE_IDIVE; @@ -363,10 +385,26 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba sample.cns = cns / 100.0; if (callback) callback (DC_SAMPLE_CNS, sample, userdata); + // Tank Pressure + if (samplesize == SZ_SAMPLE_IX3M_APOS4) { + unsigned int pressure = data[offset + 49]; + if (beginpressure == 0 && pressure != 0) { + beginpressure = pressure; + } + if (beginpressure) { + sample.pressure.tank = 0; + sample.pressure.value = pressure; + if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); + endpressure = pressure; + } + } + offset += samplesize; } // Cache the data for later use. + parser->beginpressure = beginpressure; + parser->endpressure = endpressure; for (unsigned int i = 0; i < ngasmixes; ++i) { parser->helium[i] = helium[i]; parser->oxygen[i] = oxygen[i]; From c839134130ac7bcd5b06514bd4cdc61f73f6257f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 10 Sep 2017 21:17:03 +0200 Subject: [PATCH 02/13] Add support for the Suunto D4f --- src/descriptor.c | 1 + src/suunto_d9.c | 7 +++++-- src/suunto_d9_parser.c | 21 +++++++++++++-------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index 87311e2..18c3af5 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -95,6 +95,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Suunto", "DX", DC_FAMILY_SUUNTO_D9, 0x1C}, {"Suunto", "Vyper Novo", DC_FAMILY_SUUNTO_D9, 0x1D}, {"Suunto", "Zoop Novo", DC_FAMILY_SUUNTO_D9, 0x1E}, + {"Suunto", "D4f", DC_FAMILY_SUUNTO_D9, 0x20}, /* Suunto EON Steel */ #ifdef USBHID {"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0}, diff --git a/src/suunto_d9.c b/src/suunto_d9.c index 56f8c40..6f5b81c 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -40,6 +40,7 @@ #define DX 0x1C #define VYPERNOVO 0x1D #define ZOOPNOVO 0x1E +#define D4F 0x20 typedef struct suunto_d9_device_t { suunto_common2_device_t base; @@ -101,7 +102,8 @@ suunto_d9_device_autodetect (suunto_d9_device_t *device, unsigned int model) // Use the model number as a hint to speedup the detection. unsigned int hint = 0; if (model == D4i || model == D6i || model == D9tx || - model == DX || model == VYPERNOVO || model == ZOOPNOVO) + model == DX || model == VYPERNOVO || model == ZOOPNOVO || + model == D4F) hint = 1; for (unsigned int i = 0; i < C_ARRAY_SIZE(baudrates); ++i) { @@ -191,7 +193,8 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam // Override the base class values. model = device->base.version[0]; if (model == D4i || model == D6i || model == D9tx || - model == VYPERNOVO || model == ZOOPNOVO) + model == VYPERNOVO || model == ZOOPNOVO || + model == D4F) device->base.layout = &suunto_d9tx_layout; else if (model == DX) device->base.layout = &suunto_dx_layout; diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index 6c96fa0..1f89fe4 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -46,6 +46,7 @@ #define DX 0x1C #define VYPERNOVO 0x1D #define ZOOPNOVO 0x1E +#define D4F 0x20 #define ID_D6I_V1_MIX2 0x1871C062 #define ID_D6I_V1_MIX3 0x1871C063 @@ -138,7 +139,8 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser) gasmode_offset = 0x1F; gasmix_offset = 0x54; gasmix_count = 8; - } else if (parser->model == D4i || parser->model == ZOOPNOVO) { + } else if (parser->model == D4i || parser->model == ZOOPNOVO || + parser->model == D4F) { gasmode_offset = 0x1D; if (id == ID_D4I_V2) gasmix_offset = 0x67; @@ -175,7 +177,7 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser) } else if (parser->model == HELO2 || parser->model == D4i || parser->model == D6i || parser->model == D9tx || parser->model == DX || parser->model == ZOOPNOVO || - parser->model == VYPERNOVO) { + parser->model == VYPERNOVO || parser->model == D4F) { config = gasmix_offset + gasmix_count * 6; } if (config + 1 > size) @@ -196,7 +198,7 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser) if (parser->model == HELO2 || parser->model == D4i || parser->model == D6i || parser->model == D9tx || parser->model == DX || parser->model == ZOOPNOVO || - parser->model == VYPERNOVO) { + parser->model == VYPERNOVO || parser->model == D4F) { parser->oxygen[i] = data[gasmix_offset + 6 * i + 1]; parser->helium[i] = data[gasmix_offset + 6 * i + 2]; } else { @@ -214,7 +216,7 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser) parser->gasmix = data[0x26]; } else if (parser->model == D4i || parser->model == D6i || parser->model == D9tx || parser->model == ZOOPNOVO || - parser->model == VYPERNOVO) { + parser->model == VYPERNOVO || parser->model == D4F) { if (id == ID_D4I_V2 || id == ID_D6I_V2) { parser->gasmix = data[0x2D]; } else { @@ -291,7 +293,7 @@ suunto_d9_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) offset = 0x17; else if (parser->model == D4i || parser->model == D6i || parser->model == D9tx || parser->model == ZOOPNOVO || - parser->model == VYPERNOVO) + parser->model == VYPERNOVO || parser->model == D4F) offset = 0x13; if (abstract->size < offset + 7) @@ -302,7 +304,8 @@ suunto_d9_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) if (datetime) { if (parser->model == D4i || parser->model == D6i || parser->model == D9tx || parser->model == DX || - parser->model == ZOOPNOVO || parser->model == VYPERNOVO) { + parser->model == ZOOPNOVO || parser->model == VYPERNOVO || + parser->model == D4F) { datetime->year = p[0] + (p[1] << 8); datetime->month = p[2]; datetime->day = p[3]; @@ -346,7 +349,8 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne *((unsigned int *) value) = array_uint16_le (data + 0x0B); else if (parser->model == D4i || parser->model == D6i || parser->model == D9tx || parser->model == DX || - parser->model == ZOOPNOVO || parser->model == VYPERNOVO) + parser->model == ZOOPNOVO || parser->model == VYPERNOVO || + parser->model == D4F) *((unsigned int *) value) = array_uint16_le (data + 0x0D); else if (parser->model == HELO2) *((unsigned int *) value) = array_uint16_le (data + 0x0D) * 60; @@ -457,7 +461,8 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca unsigned int interval_sample_offset = 0x18; if (parser->model == HELO2 || parser->model == D4i || parser->model == D6i || parser->model == D9tx || - parser->model == ZOOPNOVO || parser->model == VYPERNOVO) + parser->model == ZOOPNOVO || parser->model == VYPERNOVO || + parser->model == D4F) interval_sample_offset = 0x1E; else if (parser->model == DX) interval_sample_offset = 0x22; From ca4c261f6e31b782512b4cfb670e1bda0779d129 Mon Sep 17 00:00:00 2001 From: John Van Ostrand Date: Wed, 6 Sep 2017 16:02:03 -0400 Subject: [PATCH 03/13] Retry read operations on failure Using FTDI for custom I/O resulted in very unrealible reads. This patch allows more reliable use of FTDI custom I/O, like what might be needed when used on a mobile device like Android. [Jef Driesen: Modified to retry only for non-fatal errors. This simply restores the code from commit b3d2c603ddec9758fb36706bbde46ce23ca9f0ed, which was removed in commit 55e8f83eb5d934e65fbf587d427de267f174c651.] --- src/cochran_commander.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/cochran_commander.c b/src/cochran_commander.c index b515909..f079c09 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -539,6 +539,37 @@ cochran_commander_read (cochran_commander_device_t *device, dc_event_progress_t } +static unsigned int +cochran_commander_read_retry (cochran_commander_device_t *device, dc_event_progress_t *progress, unsigned int address, unsigned char data[], unsigned int size) +{ + // Save the state of the progress events. + unsigned int saved = 0; + if (progress) { + saved = progress->current; + } + + unsigned int nretries = 0; + dc_status_t rc = DC_STATUS_SUCCESS; + while ((rc = cochran_commander_read (device, progress, address, data, size)) != DC_STATUS_SUCCESS) { + // Automatically discard a corrupted packet, + // and request a new one. + if (rc != DC_STATUS_PROTOCOL && rc != DC_STATUS_TIMEOUT) + return rc; + + // Abort if the maximum number of retries is reached. + if (nretries++ >= MAXRETRIES) + return rc; + + // Restore the state of the progress events. + if (progress) { + progress->current = saved; + } + } + + return rc; +} + + /* * For corrupt dives the end-of-samples pointer is 0xFFFFFFFF * search for a reasonable size, e.g. using next dive start sample @@ -798,7 +829,7 @@ cochran_commander_device_read (dc_device_t *abstract, unsigned int address, unsi { cochran_commander_device_t *device = (cochran_commander_device_t *) abstract; - return cochran_commander_read(device, NULL, address, data, size); + return cochran_commander_read_retry(device, NULL, address, data, size); } @@ -842,7 +873,7 @@ cochran_commander_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) return rc; // Read the sample data, logbook and sample data are contiguous - rc = cochran_commander_read (device, &progress, device->layout->rb_logbook_begin, dc_buffer_get_data(buffer), size); + rc = cochran_commander_read_retry (device, &progress, device->layout->rb_logbook_begin, dc_buffer_get_data(buffer), size); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to read the sample data."); return rc; @@ -919,7 +950,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call } // Request log book - rc = cochran_commander_read(device, &progress, layout->rb_logbook_begin, data.logbook, data.logbook_size); + rc = cochran_commander_read_retry(device, &progress, layout->rb_logbook_begin, data.logbook, data.logbook_size); if (rc != DC_STATUS_SUCCESS) { status = rc; goto error; From 0220782aa86d84a9f11b37f32bb0be5e3cd58ca6 Mon Sep 17 00:00:00 2001 From: John Van Ostrand Date: Wed, 6 Sep 2017 16:02:04 -0400 Subject: [PATCH 04/13] Change communication parameter to work better with FTDI The parameters used with the FTDI USB serial port drivers didn't work well with directly with libftdi1. The new baud rate results in the same effective baud rates for both. The rbstream block size was reduced to help with the unreliability of the libftdi communications. --- src/cochran_commander.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cochran_commander.c b/src/cochran_commander.c index f079c09..525db90 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -199,8 +199,8 @@ static const cochran_device_layout_t cochran_emc14_device_layout = { COCHRAN_MODEL_EMC_14, // model 32, // address_bits ENDIAN_LE, // endian - 806400, // baudrate - 65536, // rbstream_size + 850000, // baudrate + 32768, // rbstream_size 0x0D2, // cf_dive_count 0x13E, // cf_last_log 0x142, // cf_last_interdive @@ -224,8 +224,8 @@ static const cochran_device_layout_t cochran_emc16_device_layout = { COCHRAN_MODEL_EMC_16, // model 32, // address_bits ENDIAN_LE, // endian - 806400, // baudrate - 65536, // rbstream_size + 850000, // baudrate + 32768, // rbstream_size 0x0D2, // cf_dive_count 0x13E, // cf_last_log 0x142, // cf_last_interdive @@ -249,8 +249,8 @@ static const cochran_device_layout_t cochran_emc20_device_layout = { COCHRAN_MODEL_EMC_20, // model 32, // address_bits ENDIAN_LE, // endian - 806400, // baudrate - 65536, // rbstream_size + 850000, // baudrate + 32768, // rbstream_size 0x0D2, // cf_dive_count 0x13E, // cf_last_log 0x142, // cf_last_interdive @@ -372,7 +372,7 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_ // Give the DC time to process the command. dc_serial_sleep(device->port, 45); - // Rates are odd, like 806400 for the EMC, 115200 for commander + // Rates are odd, like 850400 for the EMC, 115200 for commander status = dc_serial_configure(device->port, device->layout->baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the high baud rate."); @@ -523,7 +523,7 @@ cochran_commander_read (cochran_commander_device_t *device, dc_event_progress_t return DC_STATUS_UNSUPPORTED; } - dc_serial_sleep(device->port, 800); + dc_serial_sleep(device->port, 550); // set back to 9600 baud rc = cochran_commander_serial_setup(device); From 50c4f18cf67ef480e9a01493f02eecb0a0aa70f2 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 12 Sep 2017 20:00:41 +0200 Subject: [PATCH 05/13] Implement the ndl/deco sample --- src/oceanic_veo250_parser.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/oceanic_veo250_parser.c b/src/oceanic_veo250_parser.c index a3acf57..966308f 100644 --- a/src/oceanic_veo250_parser.c +++ b/src/oceanic_veo250_parser.c @@ -34,6 +34,7 @@ #define REACTPRO 0x4247 #define VEO200 0x424B #define VEO250 0x424C +#define INSIGHT 0x425A #define REACTPROWHITE 0x4354 typedef struct oceanic_veo250_parser_t oceanic_veo250_parser_t; @@ -256,6 +257,31 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback sample.temperature = (temperature - 32.0) * (5.0 / 9.0); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); + // NDL / Deco + unsigned int have_deco = 0; + unsigned int decostop = 0, decotime = 0; + if (parser->model == REACTPRO || parser->model == REACTPROWHITE || + parser->model == INSIGHT) { + decostop = (data[offset + 7] & 0xF0) >> 4; + decotime = ((data[offset + 3] & 0xC0) << 2) | data[offset + 4]; + have_deco = 1; + } else { + 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 = decostop * 10 * FEET; + } else { + sample.deco.type = DC_DECO_NDL; + sample.deco.depth = 0.0; + } + sample.deco.time = decotime * 60; + if (callback) callback (DC_SAMPLE_DECO, sample, userdata); + } + offset += PAGESIZE / 2; } From fa53d1351b2e098add73ac0d5a47316c2e87c4d8 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 12 Sep 2017 22:16:29 +0200 Subject: [PATCH 06/13] Fix the Sherwood Insight temperature --- src/oceanic_veo250_parser.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/oceanic_veo250_parser.c b/src/oceanic_veo250_parser.c index 966308f..fc7c6ed 100644 --- a/src/oceanic_veo250_parser.c +++ b/src/oceanic_veo250_parser.c @@ -249,7 +249,8 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback // Temperature (°F) unsigned int temperature; - if (parser->model == REACTPRO || parser->model == REACTPROWHITE) { + if (parser->model == REACTPRO || parser->model == REACTPROWHITE || + parser->model == INSIGHT) { temperature = data[offset + 6]; } else { temperature = data[offset + 7]; From 87adab39d76d6cb4b116c0ed0be5c4ad22f4a1f1 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 12 Sep 2017 20:48:14 +0200 Subject: [PATCH 07/13] Rename the DiveSystem vendor to Ratio At the time support for the Orca and iDive series was implemented, they were being sold under the "DiveSystem" brand. But nowadays, the newer iDive and iX3M series are being sold under the "Ratio" brand. Since this frequently confuses end-users, let's rename the libdivecomputer vendor name as well. The Orca and the original iDive series remain under the DiveSystem brand. --- src/descriptor.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index 18c3af5..a9c51eb 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -293,7 +293,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0}, /* Citizen Hyper Aqualand */ {"Citizen", "Hyper Aqualand", DC_FAMILY_CITIZEN_AQUALAND, 0}, - /* DiveSystem iDive */ + /* DiveSystem/Ratio iDive */ {"DiveSystem", "Orca", DC_FAMILY_DIVESYSTEM_IDIVE, 0x02}, {"DiveSystem", "iDive Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03}, {"DiveSystem", "iDive DAN", DC_FAMILY_DIVESYSTEM_IDIVE, 0x04}, @@ -304,17 +304,17 @@ static const dc_descriptor_t g_descriptors[] = { {"DiveSystem", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x09}, {"DiveSystem", "iDive X3M", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0A}, {"DiveSystem", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0B}, - {"DiveSystem", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22}, - {"DiveSystem", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23}, - {"DiveSystem", "iX3M Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24}, - {"DiveSystem", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25}, - {"DiveSystem", "iX3M Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x32}, - {"DiveSystem", "iX3M Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x34}, - {"DiveSystem", "iX3M Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x35}, - {"DiveSystem", "iDive2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x40}, - {"DiveSystem", "iDive2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x42}, - {"DiveSystem", "iDive2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x44}, - {"DiveSystem", "iDive2 Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x45}, + {"Ratio", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22}, + {"Ratio", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23}, + {"Ratio", "iX3M Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24}, + {"Ratio", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25}, + {"Ratio", "iX3M Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x32}, + {"Ratio", "iX3M Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x34}, + {"Ratio", "iX3M Pro Tech+",DC_FAMILY_DIVESYSTEM_IDIVE, 0x35}, + {"Ratio", "iDive Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x40}, + {"Ratio", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x42}, + {"Ratio", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x44}, + {"Ratio", "iDive Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x45}, /* Cochran Commander */ {"Cochran", "Commander TM", DC_FAMILY_COCHRAN_COMMANDER, 0}, {"Cochran", "Commander I", DC_FAMILY_COCHRAN_COMMANDER, 1}, From b683eca5c8529410c973cf0a462538a23f7657e2 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 28 Sep 2017 21:45:46 +0200 Subject: [PATCH 08/13] Use the correct data type for the return value --- src/cochran_commander.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 525db90..688c019 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -539,7 +539,7 @@ cochran_commander_read (cochran_commander_device_t *device, dc_event_progress_t } -static unsigned int +static dc_status_t cochran_commander_read_retry (cochran_commander_device_t *device, dc_event_progress_t *progress, unsigned int address, unsigned char data[], unsigned int size) { // Save the state of the progress events. From 52e03944c0a04a8fcec8a283293d08c5cc64c86f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 27 Sep 2017 19:47:43 +0200 Subject: [PATCH 09/13] Move platform specific macros to a common header file --- msvc/libdivecomputer.vcproj | 4 ++++ src/Makefile.am | 1 + src/hw_ostc3.c | 5 +--- src/irda.c | 5 +--- src/platform.h | 44 ++++++++++++++++++++++++++++++++++++ src/suunto_eonsteel.c | 5 +--- src/suunto_eonsteel_parser.c | 12 +--------- 7 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 src/platform.h diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj index c194f9f..242276a 100644 --- a/msvc/libdivecomputer.vcproj +++ b/msvc/libdivecomputer.vcproj @@ -692,6 +692,10 @@ RelativePath="..\include\libdivecomputer\parser.h" > + + diff --git a/src/Makefile.am b/src/Makefile.am index 387b284..97062e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -63,6 +63,7 @@ libdivecomputer_la_SOURCES = \ diverite_nitekq.h diverite_nitekq.c diverite_nitekq_parser.c \ citizen_aqualand.h citizen_aqualand.c citizen_aqualand_parser.c \ divesystem_idive.h divesystem_idive.c divesystem_idive_parser.c \ + platform.h \ ringbuffer.h ringbuffer.c \ rbstream.h rbstream.c \ checksum.h checksum.c \ diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index a1a5efd..7ce7fd5 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -30,10 +30,7 @@ #include "serial.h" #include "array.h" #include "aes.h" - -#ifdef _MSC_VER -#define snprintf _snprintf -#endif +#include "platform.h" #define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable) diff --git a/src/irda.c b/src/irda.c index 0f20970..d085ec0 100644 --- a/src/irda.c +++ b/src/irda.c @@ -53,6 +53,7 @@ #include "common-private.h" #include "context-private.h" #include "array.h" +#include "platform.h" #ifdef _WIN32 typedef int s_ssize_t; @@ -82,10 +83,6 @@ typedef int s_errcode_t; #define S_CLOSE close #endif -#ifdef _MSC_VER -#define snprintf _snprintf -#endif - struct dc_irda_t { dc_context_t *context; #ifdef _WIN32 diff --git a/src/platform.h b/src/platform.h new file mode 100644 index 0000000..f1d8155 --- /dev/null +++ b/src/platform.h @@ -0,0 +1,44 @@ +/* + * libdivecomputer + * + * Copyright (C) 2017 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DC_PLATFORM_H +#define DC_PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef _MSC_VER +#define snprintf _snprintf +#define strcasecmp _stricmp +#if _MSC_VER < 1800 +// The rint() function is only available in MSVC 2013 and later +// versions. Our replacement macro isn't entirely correct, because the +// rounding rules for halfway cases are slightly different (away from +// zero vs to even). But for our use-case, that's not a problem. +#define rint(x) ((x) >= 0.0 ? floor((x) + 0.5): ceil((x) - 0.5)) +#endif +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DC_PLATFORM_H */ diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index 2e6d4c4..09f21a9 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -28,10 +28,7 @@ #include "device-private.h" #include "array.h" #include "usbhid.h" - -#ifdef _MSC_VER -#define snprintf _snprintf -#endif +#include "platform.h" typedef struct suunto_eonsteel_device_t { dc_device_t base; diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 0ebee01..a7f817d 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -28,17 +28,7 @@ #include "context-private.h" #include "parser-private.h" #include "array.h" - -#ifdef _MSC_VER -#define strcasecmp _stricmp -#if _MSC_VER < 1800 -// The rint() function is only available in MSVC 2013 and later -// versions. Our replacement macro isn't entirely correct, because the -// rounding rules for halfway cases are slightly different (away from -// zero vs to even). But for our use-case, that's not a problem. -#define rint(x) ((x) >= 0.0 ? floor((x) + 0.5): ceil((x) - 0.5)) -#endif -#endif +#include "platform.h" #define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) From 5a00224c935516b2abe71582b6026a9156d4f5b0 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 27 Sep 2017 19:53:18 +0200 Subject: [PATCH 10/13] Use the correct printf format for the size_t type --- src/platform.h | 6 ++++++ src/suunto_eonsteel.c | 2 +- src/uwatec_g2.c | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/platform.h b/src/platform.h index f1d8155..877e320 100644 --- a/src/platform.h +++ b/src/platform.h @@ -26,6 +26,12 @@ extern "C" { #endif /* __cplusplus */ +#ifdef _WIN32 +#define DC_PRINTF_SIZE "%Iu" +#else +#define DC_PRINTF_SIZE "%zu" +#endif + #ifdef _MSC_VER #define snprintf _snprintf #define strcasecmp _stricmp diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index 09f21a9..07cd85c 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -137,7 +137,7 @@ static int receive_packet(suunto_eonsteel_device_t *eon, unsigned char *buffer, return -1; } if (transferred != PACKET_SIZE) { - ERROR(eon->base.context, "incomplete read interrupt transfer (got %zu, expected %d)", transferred, PACKET_SIZE); + ERROR(eon->base.context, "incomplete read interrupt transfer (got " DC_PRINTF_SIZE ", expected %d)", transferred, PACKET_SIZE); return -1; } if (buf[0] != 0x3f) { diff --git a/src/uwatec_g2.c b/src/uwatec_g2.c index 6e35104..f6b0b02 100644 --- a/src/uwatec_g2.c +++ b/src/uwatec_g2.c @@ -28,6 +28,7 @@ #include "device-private.h" #include "usbhid.h" #include "array.h" +#include "platform.h" #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_g2_device_vtable) @@ -76,7 +77,7 @@ receive_data (uwatec_g2_device_t *device, dc_event_progress_t *progress, unsigne return rc; } if (transferred != PACKET_SIZE) { - ERROR (device->base.context, "incomplete read interrupt transfer (got %zu, expected %d)", transferred, PACKET_SIZE); + ERROR (device->base.context, "incomplete read interrupt transfer (got " DC_PRINTF_SIZE ", expected %d)", transferred, PACKET_SIZE); return DC_STATUS_PROTOCOL; } len = buf[0]; From a28d2feb4f3712c13bfc7f1f89ee9f92b9679f7e Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 22 Sep 2017 21:36:39 +0200 Subject: [PATCH 11/13] Replace the size macro with the sizeof operator --- src/uwatec_g2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/uwatec_g2.c b/src/uwatec_g2.c index f6b0b02..b04d761 100644 --- a/src/uwatec_g2.c +++ b/src/uwatec_g2.c @@ -71,17 +71,17 @@ receive_data (uwatec_g2_device_t *device, dc_event_progress_t *progress, unsigne dc_status_t rc = DC_STATUS_SUCCESS; unsigned int len = 0; - rc = dc_usbhid_read (device->usbhid, buf, PACKET_SIZE, &transferred); + rc = dc_usbhid_read (device->usbhid, buf, sizeof(buf), &transferred); if (rc != DC_STATUS_SUCCESS) { ERROR (device->base.context, "read interrupt transfer failed"); return rc; } - if (transferred != PACKET_SIZE) { - ERROR (device->base.context, "incomplete read interrupt transfer (got " DC_PRINTF_SIZE ", expected %d)", transferred, PACKET_SIZE); + if (transferred != sizeof(buf)) { + ERROR (device->base.context, "incomplete read interrupt transfer (got " DC_PRINTF_SIZE ", expected " DC_PRINTF_SIZE ")", transferred, sizeof(buf)); return DC_STATUS_PROTOCOL; } len = buf[0]; - if (len >= PACKET_SIZE) { + if (len >= sizeof(buf)) { ERROR (device->base.context, "read interrupt transfer returns impossible packet size (%d)", len); return DC_STATUS_PROTOCOL; } @@ -112,7 +112,7 @@ uwatec_g2_transfer (uwatec_g2_device_t *device, const unsigned char command[], u dc_status_t status = DC_STATUS_SUCCESS; size_t transferred = 0; - if (csize + 2 > PACKET_SIZE) { + if (csize + 2 > sizeof(buf)) { ERROR (device->base.context, "command too big (%d)", csize); return DC_STATUS_INVALIDARGS; } From ddb7276bf017e60e76a8d55cc119bfa485ba4210 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 22 Sep 2017 21:50:28 +0200 Subject: [PATCH 12/13] Use a fixed size packet for sending The Windows HID api always expects to receive a fixed size buffer (corresponding to the largest report supported by the device). But unlike the hidapi library, the libusb library doesn't automatically pad the buffer to the expected size when trying to send less bytes. Thus when trying to submit the transfer, the underlying Windows api call immediately fails with ERROR_INVALID_PARAMETER. To workaround this problem, pad the data packet with zeros manually and always send the entire packet (1 byte report ID and 32 bytes payload). --- src/uwatec_g2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/uwatec_g2.c b/src/uwatec_g2.c index b04d761..4ef949f 100644 --- a/src/uwatec_g2.c +++ b/src/uwatec_g2.c @@ -32,7 +32,8 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_g2_device_vtable) -#define PACKET_SIZE 64 +#define RX_PACKET_SIZE 64 +#define TX_PACKET_SIZE 32 typedef struct uwatec_g2_device_t { dc_device_t base; @@ -66,7 +67,7 @@ static dc_status_t receive_data (uwatec_g2_device_t *device, dc_event_progress_t *progress, unsigned char *data, unsigned int size) { while (size) { - unsigned char buf[PACKET_SIZE]; + unsigned char buf[RX_PACKET_SIZE]; size_t transferred = 0; dc_status_t rc = DC_STATUS_SUCCESS; unsigned int len = 0; @@ -108,7 +109,7 @@ receive_data (uwatec_g2_device_t *device, dc_event_progress_t *progress, unsigne static dc_status_t uwatec_g2_transfer (uwatec_g2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { - unsigned char buf[PACKET_SIZE]; + unsigned char buf[TX_PACKET_SIZE + 1]; dc_status_t status = DC_STATUS_SUCCESS; size_t transferred = 0; @@ -122,7 +123,8 @@ uwatec_g2_transfer (uwatec_g2_device_t *device, const unsigned char command[], u buf[0] = 0; buf[1] = csize; memcpy(buf + 2, command, csize); - status = dc_usbhid_write (device->usbhid, buf, csize + 2, &transferred); + memset(buf + 2 + csize, 0, sizeof(buf) - (csize + 2)); + status = dc_usbhid_write (device->usbhid, buf, sizeof(buf), &transferred); if (status != DC_STATUS_SUCCESS) { ERROR (device->base.context, "Failed to send the command."); return status; From bcb64b3297b0366331de7aed12f1fdf7165ac0d6 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 22 Sep 2017 22:16:56 +0200 Subject: [PATCH 13/13] Workaround for a Windows libusb issue When libusb uses the Windows HID api internally, it does automatically prepend a zero report ID to the data for devices which support only a single report. But apparently it also returns a size of one byte extra! As a workaround, the number of bytes is limited to the actual size. See commit c9ed92d3f55c259931527a27d018eb5791a176dd for a similar issue in the hidapi library. --- src/usbhid.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/usbhid.c b/src/usbhid.c index b697f47..38931b8 100644 --- a/src/usbhid.c +++ b/src/usbhid.c @@ -45,6 +45,7 @@ #include "usbhid.h" #include "common-private.h" #include "context-private.h" +#include "platform.h" struct dc_usbhid_t { /* Library context. */ @@ -432,15 +433,16 @@ dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *act nbytes = 0; goto out; } - -#ifdef _WIN32 - if (nbytes > size) { - nbytes = size; - } -#endif #endif out: +#ifdef _WIN32 + if (nbytes > size) { + WARNING (usbhid->context, "Number of bytes exceeds the buffer size (" DC_PRINTF_SIZE " > " DC_PRINTF_SIZE ")!", nbytes, size); + nbytes = size; + } +#endif + HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes); out_invalidargs: