From 1b7eaaa831052d81f45163e5445ad7676cc6da1f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 11 Sep 2012 20:26:20 +0200 Subject: [PATCH 1/6] Add support for the Oceanic OCS. --- src/oceanic_atom2.c | 2 ++ src/oceanic_atom2_parser.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 30fb325..5f72e1a 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -77,6 +77,7 @@ static const unsigned char oceanic_vt41_version[] = "OCEAVT41 \0\0 1024"; static const unsigned char oceanic_geo2_version[] = "OCEGEO20 \0\0 512K"; static const unsigned char oceanic_oc1a_version[] = "OCWATCH R\0\0 1024"; static const unsigned char oceanic_oc1b_version[] = "OC1WATCH \0\0 1024"; +static const unsigned char oceanic_ocs_version[] = "OCSWATCH \0\0 1024"; static const unsigned char oceanic_veo1_version[] = "OCEVEO10 \0\0 8K"; static const unsigned char oceanic_veo2_version[] = "OCEVEO20 \0\0 512K"; static const unsigned char oceanic_veo3_version[] = "OCEVEO30 \0\0 512K"; @@ -369,6 +370,7 @@ oceanic_atom2_device_open (device_t **out, const char* name) // Override the base class values. if (oceanic_common_match (oceanic_oc1a_version, device->version, sizeof (device->version)) || oceanic_common_match (oceanic_oc1b_version, device->version, sizeof (device->version)) || + oceanic_common_match (oceanic_ocs_version, device->version, sizeof (device->version)) || oceanic_common_match (oceanic_atom3_version, device->version, sizeof (device->version)) || oceanic_common_match (oceanic_atom31_version, device->version, sizeof (device->version)) || oceanic_common_match (oceanic_vt4_version, device->version, sizeof (device->version)) || diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index bb7cec3..af69c86 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -46,6 +46,7 @@ #define VT4 0x4447 #define OC1B 0x4449 #define ATOM3 0x444C +#define OCS 0x4450 #define VT41 0x4452 #define ATOM31 0x4456 @@ -165,6 +166,7 @@ oceanic_atom2_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime) switch (parser->model) { case OC1A: case OC1B: + case OCS: case VT4: case VT41: case ATOM3: @@ -266,7 +268,8 @@ oceanic_atom2_parser_get_field (parser_t *abstract, parser_field_type_t type, un unsigned int footersize = 2 * PAGESIZE / 2; if (parser->model == DATAMASK || parser->model == COMPUMASK || parser->model == GEO || parser->model == GEO20 || - parser->model == VEO20 || parser->model == VEO30) { + parser->model == VEO20 || parser->model == VEO30 || + parser->model == OCS) { headersize -= PAGESIZE; } else if (parser->model == VT4 || parser->model == VT41) { headersize += PAGESIZE; @@ -359,7 +362,8 @@ oceanic_atom2_parser_samples_foreach (parser_t *abstract, sample_callback_t call unsigned int footersize = 2 * PAGESIZE / 2; if (parser->model == DATAMASK || parser->model == COMPUMASK || parser->model == GEO || parser->model == GEO20 || - parser->model == VEO20 || parser->model == VEO30) { + parser->model == VEO20 || parser->model == VEO30 || + parser->model == OCS) { headersize -= PAGESIZE; } else if (parser->model == VT4 || parser->model == VT41) { headersize += PAGESIZE; @@ -402,7 +406,7 @@ oceanic_atom2_parser_samples_foreach (parser_t *abstract, sample_callback_t call samplesize = 2; unsigned int have_temperature = 1, have_pressure = 1; - if (parser->model == VEO30) { + if (parser->model == VEO30 || parser->model == OCS) { have_pressure = 0; } else if (parser->model == F10) { have_temperature = 0; @@ -506,6 +510,8 @@ oceanic_atom2_parser_samples_foreach (parser_t *abstract, sample_callback_t call parser->model == VEO30 || parser->model == OC1A || parser->model == OC1B) { temperature = data[offset + 3]; + } else if (parser->model == OCS) { + temperature = data[offset + 1]; } else if (parser->model == VT4 || parser->model == VT41 || parser->model == ATOM3 || parser->model == ATOM31) { temperature = ((data[offset + 7] & 0xF0) >> 4) | ((data[offset + 7] & 0x0C) << 2) | ((data[offset + 5] & 0x0C) << 4); } else { From 074bee70a2fb67ecf88526b0e5ec5fa05f5a1536 Mon Sep 17 00:00:00 2001 From: Sascha Kettler Date: Mon, 17 Sep 2012 21:01:38 +0200 Subject: [PATCH 2/6] Fixed date parsing for Oceanic VEO 3.0 --- src/oceanic_atom2_parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index af69c86..9ba0375 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -179,6 +179,7 @@ oceanic_atom2_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime) break; case VT3: case VEO20: + case VEO30: case GEO20: datetime->year = ((p[3] & 0xE0) >> 1) + (p[4] & 0x0F) + 2000; datetime->month = (p[4] & 0xF0) >> 4; From ddf6fca65f155cce05588386de9ac043291e4b8a Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 7 May 2011 14:13:50 +0200 Subject: [PATCH 3/6] Add support for the Uwatec Galileo Trimix. --- src/uwatec_smart_parser.c | 47 +++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 4305aa4..1931bd8 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -37,6 +37,7 @@ #define ALADINTEC2G 0x13 #define SMARTCOM 0x14 #define SMARTTEC 0x18 +#define GALILEOTRIMIX 0x19 #define SMARTZ 0x1C typedef struct uwatec_smart_parser_t uwatec_smart_parser_t; @@ -207,6 +208,7 @@ uwatec_smart_parser_get_field (parser_t *abstract, parser_field_type_t type, uns unsigned int size = abstract->size; unsigned int header = 0; + unsigned int trimix = 0; const uwatec_smart_header_info_t *table = NULL; // Load the correct table. @@ -216,7 +218,12 @@ uwatec_smart_parser_get_field (parser_t *abstract, parser_field_type_t type, uns table = &uwatec_smart_pro_header; break; case GALILEO: + case GALILEOTRIMIX: header = 152; + if (data[43] & 0x80) { + header = 0xB1; + trimix = 1; + } table = &uwatec_galileo_sol_header; break; case ALADINTEC: @@ -257,7 +264,10 @@ uwatec_smart_parser_get_field (parser_t *abstract, parser_field_type_t type, uns *((double *) value) = array_uint16_le (data + table->maxdepth) / 100.0; break; case FIELD_TYPE_GASMIX_COUNT: - *((unsigned int *) value) = table->ngases; + if (trimix) + *((unsigned int *) value) = 0; + else + *((unsigned int *) value) = table->ngases; break; case FIELD_TYPE_GASMIX: gasmix->helium = 0.0; @@ -340,6 +350,8 @@ typedef enum { BEARING, ALARMS, TIME, + UNKNOWN1, + UNKNOWN2, } uwatec_smart_sample_t; typedef struct uwatec_smart_sample_info_t { @@ -429,6 +441,8 @@ uwatec_smart_sample_info_t uwatec_galileo_sol_table [] = { {HEARTRATE, 1, 0, 8, 0, 1}, // 1111 0111 dddddddd {BEARING, 1, 0, 8, 0, 2}, // 1111 1000 dddddddd dddddddd {ALARMS, 1, 2, 8, 0, 1}, // 1111 1001 dddddddd + {UNKNOWN1, 1, 0, 8, 0, 0}, // 1111 1010 (8 bytes) + {UNKNOWN2, 1, 0, 8, 0, 1}, // 1111 1011 dddddddd (n-1 bytes) }; static parser_status_t @@ -445,6 +459,7 @@ uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callb const uwatec_smart_sample_info_t *table = NULL; unsigned int entries = 0; unsigned int header = 0; + unsigned int trimix = 0; // Load the correct table. switch (parser->model) { @@ -454,7 +469,12 @@ uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callb entries = NELEMENTS (uwatec_smart_pro_table); break; case GALILEO: + case GALILEOTRIMIX: header = 152; + if (data[43] & 0x80) { + header = 0xB1; + trimix = 1; + } table = uwatec_galileo_sol_table; entries = NELEMENTS (uwatec_galileo_sol_table); break; @@ -515,7 +535,7 @@ uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callb // Process the type bits in the bitstream. unsigned int id = 0; - if (parser->model == GALILEO) { + if (parser->model == GALILEO || parser->model == GALILEOTRIMIX) { // Uwatec Galileo id = uwatec_galileo_identify (data[offset]); } else { @@ -588,8 +608,13 @@ uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callb break; case PRESSURE: if (table[id].absolute) { - tank = table[id].index; - pressure = value / 4.0; + if (trimix) { + tank = (value & 0xF000) >> 24; + pressure = (value & 0x0FFF) / 4.0; + } else { + tank = table[id].index; + pressure = value / 4.0; + } have_pressure = 1; } else { pressure += svalue / 4.0; @@ -627,6 +652,20 @@ uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callb case TIME: complete = value; break; + case UNKNOWN1: + if (offset + 8 > size) { + WARNING ("Incomplete sample data."); + return PARSER_STATUS_ERROR; + } + offset += 8; + break; + case UNKNOWN2: + if (value < 1 || offset + value - 1 > size) { + WARNING ("Incomplete sample data."); + return PARSER_STATUS_ERROR; + } + offset += value - 1; + break; default: WARNING ("Unknown sample type."); break; From 2487167778e40062cada3b78c12b3b6e048e29c4 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 20 Sep 2012 23:08:22 +0200 Subject: [PATCH 4/6] Don't exceed the maximum number of bytes. We received data from a device where the end-of-profile marker is missing. Because the device fails to locate the last dive, it goes into an infinite loop, and keeps sending the same sequence of dives over and over again. As a result, we receive more data than expected, and the assert in the progress event is triggered. We now keep track of the maximum number of bytes remaining and abort once the limit is passed. The values of the progress events are capped at the maximum value to avoid the assertion. --- src/suunto_vyper.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index 6cd9124..d2fd14a 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -437,6 +437,8 @@ suunto_vyper_read_dive (device_t *abstract, dc_buffer_t *buffer, int init, devic // Update and emit a progress event. if (progress) { progress->current += len; + if (progress->current > progress->maximum) + progress->current = progress->maximum; device_event_emit (abstract, DEVICE_EVENT_PROGRESS, progress); } @@ -554,10 +556,17 @@ suunto_vyper_device_foreach (device_t *abstract, dive_callback_t callback, void return DEVICE_STATUS_MEMORY; unsigned int ndives = 0; + unsigned int remaining = layout->rb_profile_end - layout->rb_profile_begin; while ((rc = suunto_vyper_read_dive (abstract, buffer, (ndives == 0), &progress)) == DEVICE_STATUS_SUCCESS) { unsigned char *data = dc_buffer_get_data (buffer); unsigned int size = dc_buffer_get_size (buffer); + if (size > remaining) { + WARNING ("Unexpected number of bytes received."); + dc_buffer_free (buffer); + return DEVICE_STATUS_ERROR; + } + if (size == 0) { dc_buffer_free (buffer); return DEVICE_STATUS_SUCCESS; @@ -573,6 +582,7 @@ suunto_vyper_device_foreach (device_t *abstract, dive_callback_t callback, void return DEVICE_STATUS_SUCCESS; } + remaining -= size; ndives++; } From 136f1d1fe1b1b40585b97f1344ff0974171e402d Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 21 Sep 2012 19:28:48 +0200 Subject: [PATCH 5/6] Fix the gas mix parsing. The Suunto D9tx stores the gas mix definitions at a different offset compared to the D4i and D6i. --- src/suunto_d9_parser.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index 5263c9b..020a7dc 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -219,7 +219,10 @@ suunto_d9_parser_get_field (parser_t *abstract, parser_field_type_t type, unsign if (parser->model == HELO2) { gasmix->helium = data[0x58 - SKIP + 6 * flags + 2] / 100.0; gasmix->oxygen = data[0x58 - SKIP + 6 * flags + 1] / 100.0; - } else if (parser->model == D4i || parser->model == D6i || parser->model == D9tx) { + } else if (parser->model == D9tx) { + gasmix->helium = data[0x87 + 6 * flags + 2] / 100.0; + gasmix->oxygen = data[0x87 + 6 * flags + 1] / 100.0; + } else if (parser->model == D4i || parser->model == D6i) { gasmix->helium = data[0x5F + 6 * flags + 2] / 100.0; gasmix->oxygen = data[0x5F + 6 * flags + 1] / 100.0; } else { From 4df5e490083fe235293d3c17903b48d56100775a Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 20 Sep 2012 23:19:32 +0200 Subject: [PATCH 6/6] Take the gas model into account to parse the gas mixes. When the gas model setting is set to air, the individual gas mix definitions retain their previous (non-air) values. This is convenient to avoid having to adjust the gas mixes again on your next nitrox or mixed gas dive. But the consequence is that for air dives, the gas model should take precedence over the individual gas mix definitions, and a single mix with air is returned instead. --- src/suunto_d9_parser.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index 020a7dc..67fa49a 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -42,6 +42,12 @@ #define D6i 0x1A #define D9tx 0x1B +#define AIR 0 +#define NITROX 1 +#define GAUGE 2 +#define FREEDIVE 3 +#define MIXED 4 + typedef struct suunto_d9_parser_t suunto_d9_parser_t; struct suunto_d9_parser_t { @@ -185,6 +191,14 @@ suunto_d9_parser_get_field (parser_t *abstract, parser_field_type_t type, unsign if (size < config) return PARSER_STATUS_ERROR; + // Gas model + unsigned int gasmodel_offset = 0x1D - SKIP; + if (parser->model == HELO2) + gasmodel_offset += 6; + if (parser->model == D4i || parser->model == D6i || parser->model == D9tx) + gasmodel_offset = 0x1D; + unsigned int gasmodel = data[gasmodel_offset]; + gasmix_t *gasmix = (gasmix_t *) value; if (value) { @@ -203,7 +217,9 @@ suunto_d9_parser_get_field (parser_t *abstract, parser_field_type_t type, unsign *((double *) value) = array_uint16_le (data + 0x0D - SKIP) / 100.0; break; case FIELD_TYPE_GASMIX_COUNT: - if (parser->model == HELO2) { + if (gasmodel == AIR) { + *((unsigned int *) value) = 1; + } else if (parser->model == HELO2) { *((unsigned int *) value) = 8; } else if (parser->model == D9tx) { *((unsigned int *) value) = 8; @@ -216,7 +232,10 @@ suunto_d9_parser_get_field (parser_t *abstract, parser_field_type_t type, unsign } break; case FIELD_TYPE_GASMIX: - if (parser->model == HELO2) { + if (gasmodel == AIR) { + gasmix->helium = 0.0; + gasmix->oxygen = 0.21; + } else if (parser->model == HELO2) { gasmix->helium = data[0x58 - SKIP + 6 * flags + 2] / 100.0; gasmix->oxygen = data[0x58 - SKIP + 6 * flags + 1] / 100.0; } else if (parser->model == D9tx) {