diff --git a/src/array.c b/src/array.c index 26a6c1b..13a73e5 100644 --- a/src/array.c +++ b/src/array.c @@ -146,6 +146,20 @@ array_convert_hex2bin (const unsigned char input[], unsigned int isize, unsigned return 0; } +unsigned int +array_convert_str2num (const unsigned char data[], unsigned int size) +{ + unsigned int value = 0; + for (unsigned int i = 0; i < size; ++i) { + if (data[i] < '0' || data[i] > '9') + break; + value *= 10; + value += data[i] - '0'; + } + + return value; +} + unsigned int array_uint_be (const unsigned char data[], unsigned int n) { diff --git a/src/array.h b/src/array.h index 49e8ab1..cd0a3a1 100644 --- a/src/array.h +++ b/src/array.h @@ -49,6 +49,9 @@ array_convert_bin2hex (const unsigned char input[], unsigned int isize, unsigned int array_convert_hex2bin (const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize); +unsigned int +array_convert_str2num (const unsigned char data[], unsigned int size); + unsigned int array_uint_be (const unsigned char data[], unsigned int n); diff --git a/src/descriptor.c b/src/descriptor.c index af15103..b774062 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -176,14 +176,17 @@ static const dc_descriptor_t g_descriptors[] = { {"Sherwood", "Wisdom 3", DC_FAMILY_OCEANIC_ATOM2, 0x4458}, {"Aeris", "A300", DC_FAMILY_OCEANIC_ATOM2, 0x445A}, {"Hollis", "TX1", DC_FAMILY_OCEANIC_ATOM2, 0x4542}, + {"Beuchat", "Mundial 2", DC_FAMILY_OCEANIC_ATOM2, 0x4543}, {"Sherwood", "Amphos", DC_FAMILY_OCEANIC_ATOM2, 0x4545}, {"Sherwood", "Amphos Air", DC_FAMILY_OCEANIC_ATOM2, 0x4546}, {"Oceanic", "Pro Plus 3", DC_FAMILY_OCEANIC_ATOM2, 0x4548}, {"Aeris", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4549}, {"Oceanic", "OCi", DC_FAMILY_OCEANIC_ATOM2, 0x454B}, {"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C}, + {"Beuchat", "Mundial 3", DC_FAMILY_OCEANIC_ATOM2, 0x4550}, {"Oceanic", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4554}, {"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557}, + {"Aqualung", "i300", DC_FAMILY_OCEANIC_ATOM2, 0x4559}, {"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641}, /* Mares Nemo */ {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0}, diff --git a/src/mares_darwin_parser.c b/src/mares_darwin_parser.c index 42cccb4..d4d13da 100644 --- a/src/mares_darwin_parser.c +++ b/src/mares_darwin_parser.c @@ -34,6 +34,10 @@ #define DARWIN 0 #define DARWINAIR 1 +#define AIR 0 +#define GAUGE 1 +#define NITROX 2 + typedef struct mares_darwin_parser_t mares_darwin_parser_t; struct mares_darwin_parser_t { @@ -133,6 +137,8 @@ mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_tank_t *tank = (dc_tank_t *) value; + unsigned int mode = p[0x0C] & 0x03; + if (value) { switch (type) { case DC_FIELD_DIVETIME: @@ -142,11 +148,19 @@ mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = array_uint16_be (p + 0x08) / 10.0; break; case DC_FIELD_GASMIX_COUNT: - *((unsigned int *) value) = 1; + if (mode == GAUGE) { + *((unsigned int *) value) = 0; + } else { + *((unsigned int *) value) = 1; + } break; case DC_FIELD_GASMIX: gasmix->helium = 0.0; - gasmix->oxygen = 0.21; + if (mode == NITROX) { + gasmix->oxygen = p[0x0E] / 100.0; + } else { + gasmix->oxygen = 0.21; + } gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; case DC_FIELD_TEMPERATURE_MINIMUM: @@ -171,6 +185,19 @@ mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi return DC_STATUS_UNSUPPORTED; } break; + case DC_FIELD_DIVEMODE: + switch (mode) { + case AIR: + case NITROX: + *((dc_divemode_t *) value) = DC_DIVEMODE_OC; + break; + case GAUGE: + *((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE; + break; + default: + return DC_STATUS_DATAFORMAT; + } + break; default: return DC_STATUS_UNSUPPORTED; } diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 3bd81db..9904131 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -83,6 +83,7 @@ static const dc_device_vtable_t oceanic_atom2_device_vtable = { static const oceanic_common_version_t aeris_f10_version[] = { {"FREEWAER \0\0 512K"}, + {"MUNDIAL R\0\0 512K"}, }; static const oceanic_common_version_t aeris_f11_version[] = { @@ -128,6 +129,7 @@ static const oceanic_common_version_t oceanic_default_version[] = { {"DATAMASK \0\0 512K"}, {"COMPMASK \0\0 512K"}, {"HOLLDG03 \0\0 512K"}, + {"AQUAI300 \0\0 512K"}, }; static const oceanic_common_version_t oceanic_proplus3_version[] = { diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 485bcbd..a85acff 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -69,14 +69,17 @@ #define WISDOM3 0x4458 #define A300 0x445A #define TX1 0x4542 +#define MUNDIAL2 0x4543 #define AMPHOS 0x4545 #define AMPHOSAIR 0x4546 #define PROPLUS3 0x4548 #define F11A 0x4549 #define OCI 0x454B #define A300CS 0x454C +#define MUNDIAL3 0x4550 #define F11B 0x4554 #define VTX 0x4557 +#define I300 0x4559 #define I450T 0x4641 #define NORMAL 0 @@ -148,7 +151,8 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned model == VEO20 || model == VEO30 || model == OCS || model == PROPLUS3 || model == A300 || model == MANTA || - model == INSIGHT2 || model == ZEN) { + model == INSIGHT2 || model == ZEN || + model == I300) { parser->headersize -= PAGESIZE; } else if (model == VT4 || model == VT41) { parser->headersize += PAGESIZE; @@ -156,7 +160,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned parser->headersize += 2 * PAGESIZE; } else if (model == ATOM1) { parser->headersize -= 2 * PAGESIZE; - } else if (model == F10) { + } else if (model == F10 || model == MUNDIAL2 || model == MUNDIAL3) { parser->headersize = 3 * PAGESIZE; parser->footersize = 0; } else if (model == F11A || model == F11B) { @@ -214,7 +218,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim unsigned int header = 8; if (parser->model == F10 || parser->model == F11A || - parser->model == F11B) + parser->model == F11B || parser->model == MUNDIAL2 || + parser->model == MUNDIAL3) header = 32; if (abstract->size < header) @@ -253,6 +258,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim case PROPLUS3: case DATAMASK: case COMPUMASK: + case INSIGHT2: + case I300: datetime->year = ((p[3] & 0xE0) >> 1) + (p[4] & 0x0F) + 2000; datetime->month = (p[4] & 0xF0) >> 4; datetime->day = p[3] & 0x1F; @@ -272,6 +279,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim case F10: case F11A: case F11B: + case MUNDIAL2: + case MUNDIAL3: datetime->year = bcd2dec (p[6]) + 2000; datetime->month = bcd2dec (p[7]); datetime->day = bcd2dec (p[8]); @@ -374,7 +383,8 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser) // Get the dive mode. unsigned int mode = NORMAL; if (parser->model == F10 || parser->model == F11A || - parser->model == F11B) { + parser->model == F11B || parser->model == MUNDIAL2 || + parser->model == MUNDIAL3) { mode = FREEDIVE; } else if (parser->model == T3B || parser->model == VT3 || parser->model == DG03) { @@ -482,14 +492,16 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns switch (type) { case DC_FIELD_DIVETIME: if (parser->model == F10 || parser->model == F11A || - parser->model == F11B) + parser->model == F11B || parser->model == MUNDIAL2 || + parser->model == MUNDIAL3) *((unsigned int *) value) = bcd2dec (data[2]) + bcd2dec (data[3]) * 60; else *((unsigned int *) value) = parser->divetime; break; case DC_FIELD_MAXDEPTH: if (parser->model == F10 || parser->model == F11A || - parser->model == F11B) + parser->model == F11B || parser->model == MUNDIAL2 || + parser->model == MUNDIAL3) *((double *) value) = array_uint16_le (data + 4) / 16.0 * FEET; else *((double *) value) = array_uint16_le (data + parser->footer + 4) / 16.0 * FEET; @@ -613,7 +625,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int samplesize = PAGESIZE / 2; if (parser->mode == FREEDIVE) { if (parser->model == F10 || parser->model == F11A || - parser->model == F11B) { + parser->model == F11B || parser->model == MUNDIAL2 || + parser->model == MUNDIAL3) { samplesize = 2; } else { samplesize = 4; @@ -633,7 +646,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == ELEMENT2 || parser->model == VEO20 || parser->model == A300 || parser->model == ZEN || parser->model == GEO || parser->model == GEO20 || - parser->model == MANTA) { + parser->model == MANTA || parser->model == I300) { have_pressure = 0; } @@ -747,7 +760,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == VEO30 || parser->model == OC1A || parser->model == OC1B || parser->model == OC1C || parser->model == OCI || parser->model == A300 || - parser->model == I450T) { + parser->model == I450T || parser->model == I300) { temperature = data[offset + 3]; } else if (parser->model == OCS || parser->model == TX1) { temperature = data[offset + 1]; @@ -807,7 +820,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == VEO30 || parser->model == OC1A || parser->model == OC1B || parser->model == OC1C || parser->model == OCI || parser->model == A300 || - parser->model == I450T) + parser->model == I450T || parser->model == I300) depth = (data[offset + 4] + (data[offset + 5] << 8)) & 0x0FFF; else if (parser->model == ATOM1) depth = data[offset + 3] * 16; diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index ec5027e..1179b03 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -742,7 +742,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca offset += 2; break; case 0x06: // Gas Change - if (parser->model == DX) + if (parser->model == DX || parser->model == VYPERNOVO) length = 5; else length = 4; @@ -753,7 +753,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca unknown = data[offset + 0]; he = data[offset + 1]; o2 = data[offset + 2]; - if (parser->model == DX) { + if (parser->model == DX || parser->model == VYPERNOVO) { seconds = data[offset + 4]; } else { seconds = data[offset + 3]; diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index 4abae67..e0da495 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -59,6 +59,8 @@ typedef struct suunto_eonsteel_device_t { #endif unsigned int magic; unsigned short seq; + unsigned char version[0x30]; + unsigned char fingerprint[4]; } suunto_eonsteel_device_t; // The EON Steel implements a small filesystem @@ -88,13 +90,14 @@ struct directory_entry { #define READDIR_CMD 0x0910 #define DIR_CLOSE_CMD 0x0a10 +static dc_status_t suunto_eonsteel_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size); static dc_status_t suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callback, void *userdata); static dc_status_t suunto_eonsteel_device_close(dc_device_t *abstract); static const dc_device_vtable_t suunto_eonsteel_device_vtable = { sizeof(suunto_eonsteel_device_t), DC_FAMILY_SUUNTO_EONSTEEL, - NULL, /* set_fingerprint */ + suunto_eonsteel_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ NULL, /* write */ NULL, /* dump */ @@ -565,7 +568,7 @@ static int initialize_eonsteel(suunto_eonsteel_device_t *eon) ERROR(eon->base.context, "Failed to send initialization command"); return -1; } - if (receive_header(eon, &hdr, buf, sizeof(buf)) < 0) { + if (receive_header(eon, &hdr, eon->version, sizeof(eon->version)) < 0) { ERROR(eon->base.context, "Failed to receive initial reply"); return -1; } @@ -593,6 +596,8 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char // Set up the magic handshake fields eon->magic = INIT_MAGIC; eon->seq = INIT_SEQ; + memset (eon->version, 0, sizeof (eon->version)); + memset (eon->fingerprint, 0, sizeof (eon->fingerprint)); #if __APPLE__ && HAVE_HIDAPI @@ -670,6 +675,22 @@ static int count_dir_entries(struct directory_entry *de) return count; } +static dc_status_t +suunto_eonsteel_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size) +{ + suunto_eonsteel_device_t *device = (suunto_eonsteel_device_t *) abstract; + + if (size && size != sizeof (device->fingerprint)) + return DC_STATUS_INVALIDARGS; + + if (size) + memcpy (device->fingerprint, data, sizeof (device->fingerprint)); + else + memset (device->fingerprint, 0, sizeof (device->fingerprint)); + + return DC_STATUS_SUCCESS; +} + static dc_status_t suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) { @@ -684,6 +705,13 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac if (get_file_list(eon, &de) < 0) return DC_STATUS_IO; + // Emit a device info event. + dc_event_devinfo_t devinfo; + devinfo.model = 0; + devinfo.firmware = array_uint32_be (eon->version + 0x20); + devinfo.serial = array_convert_str2num(eon->version + 0x10, 16); + device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); + file = dc_buffer_new(0); progress.maximum = count_dir_entries(de); progress.current = 0; @@ -693,6 +721,8 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac int len; struct directory_entry *next = de->next; unsigned char buf[4]; + const unsigned char *data = NULL; + unsigned int size = 0; if (device_is_cancelled(abstract)) skip = 1; @@ -719,13 +749,17 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac rc = read_file(eon, pathname, file); if (rc < 0) break; - if (!callback) - break; - if (!callback(dc_buffer_get_data(file), dc_buffer_get_size(file), NULL, 0, userdata)) - skip = 1; - // We've used up the buffer, so create a new one - file = dc_buffer_new(0); + data = dc_buffer_get_data(file); + size = dc_buffer_get_size(file); + + if (memcmp (data, eon->fingerprint, sizeof (eon->fingerprint)) == 0) { + skip = 1; + break; + } + + if (callback && !callback(data, size, data, sizeof(eon->fingerprint), userdata)) + skip = 1; } progress.current++; device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);