diff --git a/include/libdivecomputer/buffer.h b/include/libdivecomputer/buffer.h index 2af4822..8cbf27f 100644 --- a/include/libdivecomputer/buffer.h +++ b/include/libdivecomputer/buffer.h @@ -51,6 +51,9 @@ dc_buffer_append (dc_buffer_t *buffer, const unsigned char data[], size_t size); int dc_buffer_prepend (dc_buffer_t *buffer, const unsigned char data[], size_t size); +int +dc_buffer_insert (dc_buffer_t *buffer, size_t offset, const unsigned char data[], size_t size); + int dc_buffer_slice (dc_buffer_t *buffer, size_t offset, size_t size); diff --git a/src/buffer.c b/src/buffer.c index 5b203fb..86cc8c4 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -231,6 +231,72 @@ dc_buffer_prepend (dc_buffer_t *buffer, const unsigned char data[], size_t size) } +int +dc_buffer_insert (dc_buffer_t *buffer, size_t offset, const unsigned char data[], size_t size) +{ + if (buffer == NULL) + return 0; + + if (offset > buffer->size) + return 0; + + size_t head = buffer->offset; + size_t tail = buffer->capacity - (buffer->offset + buffer->size); + + unsigned char *ptr = buffer->data + buffer->offset; + + if (size <= head) { + if (buffer->size) + memmove (ptr - size, ptr, offset); + buffer->offset -= size; + } else if (size <= tail) { + if (buffer->size) + memmove (ptr + offset + size, ptr + offset, buffer->size - offset); + } else if (size <= tail + head) { + size_t n = buffer->size + size; + size_t available = buffer->capacity - n; + + size_t tmp_offset = head > tail ? available : 0; + + unsigned char *tmp = buffer->data; + + if (buffer->size) { + memmove (tmp + tmp_offset, ptr, offset); + memmove (tmp + tmp_offset + offset + size, ptr + offset, buffer->size - offset); + } + + buffer->offset = tmp_offset; + } else { + size_t n = buffer->size + size; + size_t capacity = dc_buffer_expand_calc (buffer, n); + size_t available = capacity - n; + + size_t tmp_offset = head > tail ? available : 0; + + unsigned char *tmp = (unsigned char *) malloc (capacity); + if (tmp == NULL) + return 0; + + if (buffer->size) { + memcpy (tmp + tmp_offset, ptr, offset); + memcpy (tmp + tmp_offset + offset + size, ptr + offset, buffer->size - offset); + } + + free (buffer->data); + buffer->data = tmp; + buffer->capacity = capacity; + buffer->offset = tmp_offset; + } + + if (size) + memcpy (buffer->data + buffer->offset + offset, data, size); + + buffer->size += size; + + return 1; +} + + int dc_buffer_slice (dc_buffer_t *buffer, size_t offset, size_t size) { diff --git a/src/cressi_goa.c b/src/cressi_goa.c index f6df023..e414743 100644 --- a/src/cressi_goa.c +++ b/src/cressi_goa.c @@ -485,7 +485,19 @@ cressi_goa_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v goto error_free_dive; } - if (callback && !callback(dive_data, dive_size, dive_data + FP_OFFSET - 5, sizeof(device->fingerprint), userdata)) + // Those 5 extra bytes contain the dive mode, which is required for + // parsing the dive data. Therefore, insert all 5 bytes again. The + // remaining 4 bytes appear to be some 32 bit address. + if (!dc_buffer_insert (dive, 2, logbook_data + offset + 2, 5)) { + ERROR (abstract->context, "Out of memory."); + status = DC_STATUS_NOMEMORY; + goto error_free_dive; + } + + dive_data = dc_buffer_get_data (dive); + dive_size = dc_buffer_get_size (dive); + + if (callback && !callback(dive_data, dive_size, dive_data + FP_OFFSET, sizeof(device->fingerprint), userdata)) break; } diff --git a/src/cressi_goa_parser.c b/src/cressi_goa_parser.c index d7599dc..35312db 100644 --- a/src/cressi_goa_parser.c +++ b/src/cressi_goa_parser.c @@ -28,11 +28,23 @@ #define ISINSTANCE(parser) dc_device_isinstance((parser), &cressi_goa_parser_vtable) -#define SZ_HEADER 0x5C +#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array)) + +#define SZ_HEADER 23 +#define SZ_HEADER_SCUBA 0x61 +#define SZ_HEADER_FREEDIVE 0x2B +#define SZ_HEADER_GAUGE 0x2D #define DEPTH 0 +#define DEPTH2 1 +#define TIME 2 #define TEMPERATURE 3 +#define SCUBA 0 +#define NITROX 1 +#define FREEDIVE 2 +#define GAUGE 3 + typedef struct cressi_goa_parser_t cressi_goa_parser_t; struct cressi_goa_parser_t { @@ -58,6 +70,13 @@ static const dc_parser_vtable_t cressi_goa_parser_vtable = { NULL /* destroy */ }; +static const unsigned int headersizes[] = { + SZ_HEADER_SCUBA, + SZ_HEADER_SCUBA, + SZ_HEADER_FREEDIVE, + SZ_HEADER_GAUGE, +}; + dc_status_t cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) { @@ -97,17 +116,29 @@ cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, un static dc_status_t cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) { - if (abstract->size < SZ_HEADER) + const unsigned char *data = abstract->data; + unsigned int size = abstract->size; + + if (size < SZ_HEADER) return DC_STATUS_DATAFORMAT; - const unsigned char *p = abstract->data; + unsigned int divemode = data[2]; + if (divemode >= C_ARRAY_SIZE(headersizes)) { + return DC_STATUS_DATAFORMAT; + } + + unsigned int headersize = headersizes[divemode]; + if (size < headersize) + return DC_STATUS_DATAFORMAT; + + const unsigned char *p = abstract->data + 0x11; if (datetime) { - datetime->year = array_uint16_le(p + 0x0C); - datetime->month = p[0x0E]; - datetime->day = p[0x0F]; - datetime->hour = p[0x10]; - datetime->minute = p[0x11]; + datetime->year = array_uint16_le(p); + datetime->month = p[2]; + datetime->day = p[3]; + datetime->hour = p[4]; + datetime->minute = p[5]; datetime->second = 0; datetime->timezone = DC_TIMEZONE_NONE; } @@ -119,10 +150,20 @@ static dc_status_t cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) { cressi_goa_parser_t *parser = (cressi_goa_parser_t *) abstract; - if (abstract->size < SZ_HEADER) + const unsigned char *data = abstract->data; + unsigned int size = abstract->size; + + if (size < SZ_HEADER) return DC_STATUS_DATAFORMAT; - const unsigned char *data = abstract->data; + unsigned int divemode = data[2]; + if (divemode >= C_ARRAY_SIZE(headersizes)) { + return DC_STATUS_DATAFORMAT; + } + + unsigned int headersize = headersizes[divemode]; + if (size < headersize) + return DC_STATUS_DATAFORMAT; if (!parser->cached) { sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER; @@ -140,19 +181,35 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign if (value) { switch (type) { case DC_FIELD_DIVETIME: - *((unsigned int *) value) = array_uint16_le (data + 0x14); + *((unsigned int *) value) = array_uint16_le (data + 0x19); break; case DC_FIELD_MAXDEPTH: *((double *) value) = parser->maxdepth; break; case DC_FIELD_GASMIX_COUNT: - *((unsigned int *) value) = 2; + *((unsigned int *) value) = divemode == SCUBA || divemode == NITROX ? 2 : 0; break; case DC_FIELD_GASMIX: gasmix->helium = 0.0; - gasmix->oxygen = data[0x1B + 2 * flags] / 100.0; + gasmix->oxygen = data[0x20 + 2 * flags] / 100.0; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; + case DC_FIELD_DIVEMODE: + switch (divemode) { + case SCUBA: + case NITROX: + *((dc_divemode_t *) value) = DC_DIVEMODE_OC; + break; + case GAUGE: + *((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE; + break; + case FREEDIVE: + *((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE; + break; + default: + return DC_STATUS_DATAFORMAT; + } + break; default: return DC_STATUS_UNSUPPORTED; } @@ -167,12 +224,28 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c const unsigned char *data = abstract->data; unsigned int size = abstract->size; - unsigned int time = 0; - unsigned int interval = 5; - unsigned int complete = 1; - unsigned int gasmix_previous = 0xFFFFFFFF; + if (size < SZ_HEADER) + return DC_STATUS_DATAFORMAT; - unsigned int offset = SZ_HEADER; + unsigned int divemode = data[2]; + if (divemode >= C_ARRAY_SIZE(headersizes)) { + return DC_STATUS_DATAFORMAT; + } + + unsigned int headersize = headersizes[divemode]; + if (size < headersize) + return DC_STATUS_DATAFORMAT; + + unsigned int interval = divemode == FREEDIVE ? 2 : 5; + + unsigned int time = 0; + unsigned int depth = 0; + unsigned int gasmix = 0, gasmix_previous = 0xFFFFFFFF; + unsigned int temperature = 0; + unsigned int have_temperature = 0; + unsigned int complete = 0; + + unsigned int offset = headersize; while (offset + 2 <= size) { dc_sample_value_t sample = {0}; @@ -181,35 +254,44 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c unsigned int type = (raw & 0x0003); unsigned int value = (raw & 0xFFFC) >> 2; - if (complete) { - // Time (seconds). + if (type == DEPTH || type == DEPTH2) { + depth = (value & 0x07FF); + gasmix = (value & 0x0800) >> 11; time += interval; - sample.time = time; - if (callback) callback (DC_SAMPLE_TIME, sample, userdata); - complete = 0; + complete = 1; + } else if (type == TEMPERATURE) { + temperature = value; + have_temperature = 1; + } else if (type == TIME) { + time += value; } - if (type == DEPTH) { + if (complete) { + // Time (seconds). + sample.time = time; + if (callback) callback (DC_SAMPLE_TIME, sample, userdata); + + // Temperature (1/10 °C). + if (have_temperature) { + sample.temperature = temperature / 10.0; + if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); + have_temperature = 0; + } + // Depth (1/10 m). - unsigned int depth = value & 0x07FF; sample.depth = depth / 10.0; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); - // Gas change. - unsigned int gasmix = (value & 0x0800) >> 11; - if (gasmix != gasmix_previous) { - sample.gasmix = gasmix; - if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); - gasmix_previous = gasmix; + // Gas change + if (divemode == SCUBA || divemode == NITROX) { + if (gasmix != gasmix_previous) { + sample.gasmix = gasmix; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); + gasmix_previous = gasmix; + } } - complete = 1; - } else if (type == TEMPERATURE) { - // Temperature (1/10 °C). - sample.temperature = value / 10.0; - if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); - } else { - WARNING(abstract->context, "Unknown sample type %u.", type); + complete = 0; } offset += 2; diff --git a/src/descriptor.c b/src/descriptor.c index 51349a1..0b99ccb 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -172,6 +172,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Scubapro", "Chromis", DC_FAMILY_UWATEC_SMART, 0x24, DC_TRANSPORT_SERIAL, NULL}, {"Scubapro", "Aladin A1", DC_FAMILY_UWATEC_SMART, 0x25, DC_TRANSPORT_BLE, dc_filter_uwatec}, {"Scubapro", "Mantis 2", DC_FAMILY_UWATEC_SMART, 0x26, DC_TRANSPORT_SERIAL, NULL}, + {"Scubapro", "Aladin A2", DC_FAMILY_UWATEC_SMART, 0x28, DC_TRANSPORT_BLE, dc_filter_uwatec}, {"Scubapro", "G2", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec}, {"Scubapro", "G2 Console", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec}, {"Scubapro", "G2 HUD", DC_FAMILY_UWATEC_SMART, 0x42, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec}, @@ -536,6 +537,7 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi "Aladin", "HUD", "A1", + "A2", }; if (transport == DC_TRANSPORT_IRDA) { diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 508097a..0982ba6 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -8,6 +8,7 @@ dc_buffer_reserve dc_buffer_resize dc_buffer_append dc_buffer_prepend +dc_buffer_insert dc_buffer_slice dc_buffer_get_size dc_buffer_get_data diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 366de96..8c804b9 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -92,141 +92,6 @@ static const oceanic_common_device_vtable_t oceanic_atom2_device_vtable = { oceanic_common_device_profile, }; -static const oceanic_common_version_t aeris_f10_version[] = { - {"FREEWAER \0\0 512K"}, - {"OCEANF10 \0\0 512K"}, - {"MUNDIAL R\0\0 512K"}, -}; - -static const oceanic_common_version_t aeris_f11_version[] = { - {"AERISF11 \0\0 1024"}, - {"OCEANF11 \0\0 1024"}, -}; - -static const oceanic_common_version_t aeris_manta_version[] = { - {"MANTA R\0\0 512K"}, -}; - -static const oceanic_common_version_t oceanic_atom1_version[] = { - {"ATOM rev\0\0 256K"}, -}; - -static const oceanic_common_version_t oceanic_atom2_version[] = { - {"2M ATOM r\0\0 512K"}, -}; - -static const oceanic_common_version_t oceanic_atom2a_version[] = { - {"INSIGHT2 \0\0 512K"}, - {"OCEVEO30 \0\0 512K"}, - {"ATMOSAI R\0\0 512K"}, - {"PROPLUS2 \0\0 512K"}, - {"OCEGEO20 \0\0 512K"}, - {"OCE GEO R\0\0 512K"}, - {"AQUAI200 \0\0 512K"}, - {"AQUA200C \0\0 512K"}, -}; - -static const oceanic_common_version_t oceanic_atom2b_version[] = { - {"ELEMENT2 \0\0 512K"}, - {"OCEVEO20 \0\0 512K"}, - {"TUSAZEN \0\0 512K"}, - {"AQUAI300 \0\0 512K"}, - {"HOLLDG03 \0\0 512K"}, - {"AQUAI100 \0\0 512K"}, - {"AQUA300C \0\0 512K"}, - {"OCEGEO40 \0\0 512K"}, - {"VEOSMART \0\0 512K"}, -}; - -static const oceanic_common_version_t oceanic_atom2c_version[] = { - {"2M EPIC r\0\0 512K"}, - {"EPIC1 R\0\0 512K"}, - {"AERIA300 \0\0 512K"}, -}; - -static const oceanic_common_version_t oceanic_default_version[] = { - {"OCE VT3 R\0\0 512K"}, - {"ELITET3 R\0\0 512K"}, - {"ELITET31 \0\0 512K"}, - {"DATAMASK \0\0 512K"}, - {"COMPMASK \0\0 512K"}, -}; - -static const oceanic_common_version_t sherwood_wisdom_version[] = { - {"WISDOM R\0\0 512K"}, -}; - -static const oceanic_common_version_t oceanic_proplus3_version[] = { - {"PROPLUS3 \0\0 512K"}, - {"PROPLUS4 \0\0 512K"}, -}; - -static const oceanic_common_version_t tusa_zenair_version[] = { - {"TUZENAIR \0\0 512K"}, - {"AMPHOSSW \0\0 512K"}, - {"AMPHOAIR \0\0 512K"}, - {"VOYAGE2G \0\0 512K"}, - {"TUSTALIS \0\0 512K"}, -}; - -static const oceanic_common_version_t oceanic_oc1_version[] = { - {"OCWATCH R\0\0 1024"}, - {"OC1WATCH \0\0 1024"}, - {"OCSWATCH \0\0 1024"}, - {"AQUAI550 \0\0 1024"}, - {"AQUA550C \0\0 1024"}, - {"WISDOM04 \0\0 1024"}, - {"AQUA470C \0\0 1024"}, -}; - -static const oceanic_common_version_t oceanic_oci_version[] = { - {"OCEANOCI \0\0 1024"}, -}; - -static const oceanic_common_version_t oceanic_atom3_version[] = { - {"OCEATOM3 \0\0 1024"}, - {"ATOM31 \0\0 1024"}, -}; - -static const oceanic_common_version_t oceanic_vt4_version[] = { - {"OCEANVT4 \0\0 1024"}, - {"OCEAVT41 \0\0 1024"}, - {"AERISAIR \0\0 1024"}, - {"SWVISION \0\0 1024"}, - {"XPSUBAIR \0\0 1024"}, -}; - -static const oceanic_common_version_t hollis_tx1_version[] = { - {"HOLLDG04 \0\0 2048"}, -}; - -static const oceanic_common_version_t oceanic_veo1_version[] = { - {"OCEVEO10 \0\0 8K"}, - {"AERIS XR1 NX R\0\0"}, -}; - -static const oceanic_common_version_t oceanic_reactpro_version[] = { - {"REACPRO2 \0\0 512K"}, -}; - -static const oceanic_common_version_t oceanic_proplusx_version[] = { - {"OCEANOCX \0\0 \0\0\0\0"}, -}; - -static const oceanic_common_version_t aqualung_i770r_version[] = { - {"AQUA770R \0\0 \0\0\0\0"}, -}; - -static const oceanic_common_version_t aeris_a300cs_version[] = { - {"AER300CS \0\0 2048"}, - {"OCEANVTX \0\0 2048"}, - {"AQUAI750 \0\0 2048"}, -}; - -static const oceanic_common_version_t aqualung_i450t_version[] = { - {"AQUAI450 \0\0 2048"}, -}; - static const oceanic_common_layout_t aeris_f10_layout = { 0x10000, /* memsize */ 0, /* highmem */ @@ -542,6 +407,98 @@ static const oceanic_common_layout_t aqualung_i450t_layout = { 0, /* pt_mode_serial */ }; +static const oceanic_common_version_t versions[] = { + {"OCEVEO10 \0\0 8K", 0, &oceanic_veo1_layout}, + {"AERIS XR1 NX R\0\0", 0, &oceanic_veo1_layout}, + + {"ATOM rev\0\0 256K", 0, &oceanic_atom1_layout}, + + {"MANTA R\0\0 512K", 0x3242, &oceanic_atom2a_layout}, + {"MANTA R\0\0 512K", 0, &oceanic_atom2c_layout}, + {"2M ATOM r\0\0 512K", 0x3349, &oceanic_atom2a_layout}, + {"2M ATOM r\0\0 512K", 0, &oceanic_atom2c_layout}, + + {"INSIGHT2 \0\0 512K", 0, &oceanic_atom2a_layout}, + {"OCEVEO30 \0\0 512K", 0, &oceanic_atom2a_layout}, + {"ATMOSAI R\0\0 512K", 0, &oceanic_atom2a_layout}, + {"PROPLUS2 \0\0 512K", 0, &oceanic_atom2a_layout}, + {"OCEGEO20 \0\0 512K", 0, &oceanic_atom2a_layout}, + {"OCE GEO R\0\0 512K", 0, &oceanic_atom2a_layout}, + {"AQUAI200 \0\0 512K", 0, &oceanic_atom2a_layout}, + {"AQUA200C \0\0 512K", 0, &oceanic_atom2a_layout}, + + {"ELEMENT2 \0\0 512K", 0, &oceanic_atom2b_layout}, + {"OCEVEO20 \0\0 512K", 0, &oceanic_atom2b_layout}, + {"TUSAZEN \0\0 512K", 0, &oceanic_atom2b_layout}, + {"AQUAI300 \0\0 512K", 0, &oceanic_atom2b_layout}, + {"HOLLDG03 \0\0 512K", 0, &oceanic_atom2b_layout}, + {"AQUAI100 \0\0 512K", 0, &oceanic_atom2b_layout}, + {"AQUA300C \0\0 512K", 0, &oceanic_atom2b_layout}, + {"OCEGEO40 \0\0 512K", 0, &oceanic_atom2b_layout}, + {"VEOSMART \0\0 512K", 0, &oceanic_atom2b_layout}, + + {"2M EPIC r\0\0 512K", 0, &oceanic_atom2c_layout}, + {"EPIC1 R\0\0 512K", 0, &oceanic_atom2c_layout}, + {"AERIA300 \0\0 512K", 0, &oceanic_atom2c_layout}, + + {"OCE VT3 R\0\0 512K", 0, &oceanic_default_layout}, + {"ELITET3 R\0\0 512K", 0, &oceanic_default_layout}, + {"ELITET31 \0\0 512K", 0, &oceanic_default_layout}, + {"DATAMASK \0\0 512K", 0, &oceanic_default_layout}, + {"COMPMASK \0\0 512K", 0, &oceanic_default_layout}, + + {"WISDOM R\0\0 512K", 0, &sherwood_wisdom_layout}, + + {"PROPLUS3 \0\0 512K", 0, &oceanic_proplus3_layout}, + {"PROPLUS4 \0\0 512K", 0, &oceanic_proplus3_layout}, + + {"TUZENAIR \0\0 512K", 0, &tusa_zenair_layout}, + {"AMPHOSSW \0\0 512K", 0, &tusa_zenair_layout}, + {"AMPHOAIR \0\0 512K", 0, &tusa_zenair_layout}, + {"VOYAGE2G \0\0 512K", 0, &tusa_zenair_layout}, + {"TUSTALIS \0\0 512K", 0, &tusa_zenair_layout}, + + {"REACPRO2 \0\0 512K", 0, &oceanic_reactpro_layout}, + + {"FREEWAER \0\0 512K", 0, &aeris_f10_layout}, + {"OCEANF10 \0\0 512K", 0, &aeris_f10_layout}, + {"MUNDIAL R\0\0 512K", 0, &aeris_f10_layout}, + + {"AERISF11 \0\0 1024", 0, &aeris_f11_layout}, + {"OCEANF11 \0\0 1024", 0, &aeris_f11_layout}, + + {"OCWATCH R\0\0 1024", 0, &oceanic_oc1_layout}, + {"OC1WATCH \0\0 1024", 0, &oceanic_oc1_layout}, + {"OCSWATCH \0\0 1024", 0, &oceanic_oc1_layout}, + {"AQUAI550 \0\0 1024", 0, &oceanic_oc1_layout}, + {"AQUA550C \0\0 1024", 0, &oceanic_oc1_layout}, + {"WISDOM04 \0\0 1024", 0, &oceanic_oc1_layout}, + {"AQUA470C \0\0 1024", 0, &oceanic_oc1_layout}, + + {"OCEANOCI \0\0 1024", 0, &oceanic_oci_layout}, + + {"OCEATOM3 \0\0 1024", 0, &oceanic_atom3_layout}, + {"ATOM31 \0\0 1024", 0, &oceanic_atom3_layout}, + + {"OCEANVT4 \0\0 1024", 0, &oceanic_vt4_layout}, + {"OCEAVT41 \0\0 1024", 0, &oceanic_vt4_layout}, + {"AERISAIR \0\0 1024", 0, &oceanic_vt4_layout}, + {"SWVISION \0\0 1024", 0, &oceanic_vt4_layout}, + {"XPSUBAIR \0\0 1024", 0, &oceanic_vt4_layout}, + + {"HOLLDG04 \0\0 2048", 0, &hollis_tx1_layout}, + + {"AER300CS \0\0 2048", 0, &aeris_a300cs_layout}, + {"OCEANVTX \0\0 2048", 0, &aeris_a300cs_layout}, + {"AQUAI750 \0\0 2048", 0, &aeris_a300cs_layout}, + + {"AQUAI450 \0\0 2048", 0, &aqualung_i450t_layout}, + + {"OCEANOCX \0\0 \0\0\0\0", 0, &oceanic_proplusx_layout}, + + {"AQUA770R \0\0 \0\0\0\0", 0, &aqualung_i770r_layout}, +}; + /* * The BLE GATT packet size is up to 20 bytes and the format is: * @@ -952,68 +909,10 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream } } - // Override the base class values. - if (OCEANIC_COMMON_MATCH (device->base.version, aeris_f10_version)) { - device->base.layout = &aeris_f10_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_f11_version)) { - device->base.layout = &aeris_f11_layout; - device->bigpage = 8; - } else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_manta_version)) { - if (array_uint16_be (device->base.version + 0x08) >= 0x3242) { - device->base.layout = &oceanic_atom2a_layout; - } else { - device->base.layout = &oceanic_atom2c_layout; - } - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom1_version)) { - device->base.layout = &oceanic_atom1_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom2_version)) { - if (array_uint16_be (device->base.version + 0x09) >= 0x3349) { - device->base.layout = &oceanic_atom2a_layout; - } else { - device->base.layout = &oceanic_atom2c_layout; - } - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom2a_version)) { - device->base.layout = &oceanic_atom2a_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom2b_version)) { - device->base.layout = &oceanic_atom2b_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom2c_version)) { - device->base.layout = &oceanic_atom2c_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, sherwood_wisdom_version)) { - device->base.layout = &sherwood_wisdom_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_proplus3_version)) { - device->base.layout = &oceanic_proplus3_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, tusa_zenair_version)) { - device->base.layout = &tusa_zenair_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_oc1_version)) { - device->base.layout = &oceanic_oc1_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_oci_version)) { - device->base.layout = &oceanic_oci_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom3_version)) { - device->base.layout = &oceanic_atom3_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_vt4_version)) { - device->base.layout = &oceanic_vt4_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, hollis_tx1_version)) { - device->base.layout = &hollis_tx1_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_veo1_version)) { - device->base.layout = &oceanic_veo1_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_reactpro_version)) { - device->base.layout = &oceanic_reactpro_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_proplusx_version)) { - device->base.layout = &oceanic_proplusx_layout; - device->bigpage = 16; - } else if (OCEANIC_COMMON_MATCH (device->base.version, aqualung_i770r_version)) { - device->base.layout = &aqualung_i770r_layout; - device->bigpage = 16; - } else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_a300cs_version)) { - device->base.layout = &aeris_a300cs_layout; - device->bigpage = 16; - } else if (OCEANIC_COMMON_MATCH (device->base.version, aqualung_i450t_version)) { - device->base.layout = &aqualung_i450t_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_default_version)) { - device->base.layout = &oceanic_default_layout; - } else { + // Detect the memory layout. + device->base.layout = OCEANIC_COMMON_MATCH(device->base.version, versions, &device->base.firmware); + if (device->base.layout == NULL) { WARNING (context, "Unsupported device detected (%s)!", device->base.version); - device->base.layout = &oceanic_default_layout; if (memcmp(device->base.version + 12, "256K", 4) == 0) { device->base.layout = &oceanic_atom1_layout; } else if (memcmp(device->base.version + 12, "512K", 4) == 0) { @@ -1027,6 +926,15 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream } } + // Set the big page support. + if (device->base.layout == &aeris_f11_layout) { + device->bigpage = 8; + } else if (device->base.layout == &oceanic_proplusx_layout || + device->base.layout == &aqualung_i770r_layout || + device->base.layout == &aeris_a300cs_layout) { + device->bigpage = 16; + } + *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; diff --git a/src/oceanic_common.c b/src/oceanic_common.c index 817e3e2..9a7c2e2 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -99,26 +99,52 @@ get_profile_last (const unsigned char data[], const oceanic_common_layout_t *lay static int -oceanic_common_match_pattern (const unsigned char *string, const unsigned char *pattern) +oceanic_common_match_pattern (const unsigned char *string, const unsigned char *pattern, unsigned int *firmware) { + unsigned int value = 0; + unsigned int count = 0; + for (unsigned int i = 0; i < PAGESIZE; ++i, ++pattern, ++string) { - if (*pattern != '\0' && *pattern != *string) - return 0; + if (*pattern != '\0') { + // Compare the pattern. + if (*pattern != *string) + return 0; + } else { + // Extract the firmware version. + // This is based on the assumption that (only) the first block of + // zeros in the pattern contains the firmware version. + if (i == 0 || *(pattern - 1) != '\0') + count++; + if (count == 1) { + value <<= 8; + value |= *string; + } + } + } + + if (firmware) { + *firmware = value; } return 1; } - -int -oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], unsigned int n) +const oceanic_common_layout_t * +oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], size_t n, unsigned int *firmware) { - for (unsigned int i = 0; i < n; ++i) { - if (oceanic_common_match_pattern (version, patterns[i])) - return 1; + for (size_t i = 0; i < n; ++i) { + unsigned int fw = 0; + if (oceanic_common_match_pattern (version, patterns[i].pattern, &fw) && + fw >= patterns[i].firmware) + { + if (firmware) { + *firmware = fw; + } + return patterns[i].layout; + } } - return 0; + return NULL; } @@ -128,6 +154,7 @@ oceanic_common_device_init (oceanic_common_device_t *device) assert (device != NULL); // Set the default values. + device->firmware = 0; memset (device->version, 0, sizeof (device->version)); memset (device->fingerprint, 0, sizeof (device->fingerprint)); device->layout = NULL; @@ -585,7 +612,7 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac // Emit a device info event. dc_event_devinfo_t devinfo; devinfo.model = array_uint16_be (id + 8); - devinfo.firmware = 0; + devinfo.firmware = device->firmware; if (layout->pt_mode_serial == 0) devinfo.serial = bcd2dec (id[10]) * 10000 + bcd2dec (id[11]) * 100 + bcd2dec (id[12]); else if (layout->pt_mode_serial == 1) diff --git a/src/oceanic_common.h b/src/oceanic_common.h index a5c55b8..915081e 100644 --- a/src/oceanic_common.h +++ b/src/oceanic_common.h @@ -31,9 +31,9 @@ extern "C" { #define PAGESIZE 0x10 #define FPMAXSIZE 0x20 -#define OCEANIC_COMMON_MATCH(version,patterns) \ +#define OCEANIC_COMMON_MATCH(version,patterns,firmware) \ oceanic_common_match ((version), (patterns), \ - sizeof (patterns) / sizeof *(patterns)) + sizeof (patterns) / sizeof *(patterns), (firmware)) typedef struct oceanic_common_layout_t { // Memory size. @@ -61,6 +61,7 @@ typedef struct oceanic_common_layout_t { typedef struct oceanic_common_device_t { dc_device_t base; + unsigned int firmware; unsigned char version[PAGESIZE]; unsigned char fingerprint[FPMAXSIZE]; const oceanic_common_layout_t *layout; @@ -73,10 +74,14 @@ typedef struct oceanic_common_device_vtable_t { dc_status_t (*profile) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata); } oceanic_common_device_vtable_t; -typedef unsigned char oceanic_common_version_t[PAGESIZE + 1]; +typedef struct oceanic_common_version_t { + unsigned char pattern[PAGESIZE + 1]; + unsigned int firmware; + const oceanic_common_layout_t *layout; +} oceanic_common_version_t; -int -oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], unsigned int n); +const oceanic_common_layout_t * +oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], size_t n, unsigned int *firmware); void oceanic_common_device_init (oceanic_common_device_t *device); diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index a6038d8..db323db 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -62,17 +62,6 @@ static const oceanic_common_device_vtable_t oceanic_veo250_device_vtable = { oceanic_common_device_profile, }; -static const oceanic_common_version_t oceanic_veo250_version[] = { - {"GENREACT \0\0 256K"}, - {"VEO 200 R\0\0 256K"}, - {"VEO 250 R\0\0 256K"}, - {"SEEMANN R\0\0 256K"}, - {"VEO 180 R\0\0 256K"}, - {"AERISXR2 \0\0 256K"}, - {"INSIGHT R\0\0 256K"}, - {"HO DGO2 R\0\0 256K"}, -}; - static const oceanic_common_layout_t oceanic_veo250_layout = { 0x8000, /* memsize */ 0, /* highmem */ @@ -88,6 +77,16 @@ static const oceanic_common_layout_t oceanic_veo250_layout = { 1, /* pt_mode_serial */ }; +static const oceanic_common_version_t versions[] = { + {"GENREACT \0\0 256K", 0, &oceanic_veo250_layout}, + {"VEO 200 R\0\0 256K", 0, &oceanic_veo250_layout}, + {"VEO 250 R\0\0 256K", 0, &oceanic_veo250_layout}, + {"SEEMANN R\0\0 256K", 0, &oceanic_veo250_layout}, + {"VEO 180 R\0\0 256K", 0, &oceanic_veo250_layout}, + {"AERISXR2 \0\0 256K", 0, &oceanic_veo250_layout}, + {"INSIGHT R\0\0 256K", 0, &oceanic_veo250_layout}, + {"HO DGO2 R\0\0 256K", 0, &oceanic_veo250_layout}, +}; static dc_status_t oceanic_veo250_send (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize) @@ -316,10 +315,9 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, dc_iostrea goto error_free; } - // Override the base class values. - if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_veo250_version)) { - device->base.layout = &oceanic_veo250_layout; - } else { + // Detect the memory layout. + device->base.layout = OCEANIC_COMMON_MATCH(device->base.version, versions, &device->base.firmware); + if (device->base.layout == NULL) { WARNING (context, "Unsupported device detected!"); device->base.layout = &oceanic_veo250_layout; } diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index cefeb7b..22d61fd 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -74,19 +74,6 @@ static const oceanic_common_device_vtable_t oceanic_vtpro_device_vtable = { oceanic_common_device_profile, }; -static const oceanic_common_version_t oceanic_vtpro_version[] = { - {"VERSAPRO \0\0 256K"}, - {"ATMOSTWO \0\0 256K"}, - {"PROPLUS2 \0\0 256K"}, - {"ATMOSAIR \0\0 256K"}, - {"VTPRO r\0\0 256K"}, - {"ELITE r\0\0 256K"}, -}; - -static const oceanic_common_version_t oceanic_wisdom_version[] = { - {"WISDOM r\0\0 256K"}, -}; - static const oceanic_common_layout_t oceanic_vtpro_layout = { 0x8000, /* memsize */ 0, /* highmem */ @@ -132,6 +119,17 @@ static const oceanic_common_layout_t aeris_500ai_layout = { 2, /* pt_mode_serial */ }; +static const oceanic_common_version_t versions[] = { + {"VERSAPRO \0\0 256K", 0, &oceanic_vtpro_layout}, + {"ATMOSTWO \0\0 256K", 0, &oceanic_vtpro_layout}, + {"PROPLUS2 \0\0 256K", 0, &oceanic_vtpro_layout}, + {"ATMOSAIR \0\0 256K", 0, &oceanic_vtpro_layout}, + {"VTPRO r\0\0 256K", 0, &oceanic_vtpro_layout}, + {"ELITE r\0\0 256K", 0, &oceanic_vtpro_layout}, + + {"WISDOM r\0\0 256K", 0, &oceanic_wisdom_layout}, +}; + static dc_status_t oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize) { @@ -491,16 +489,15 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, dc_iostream goto error_free; } - // Override the base class values. + // Detect the memory layout. if (model == AERIS500AI) { device->base.layout = &aeris_500ai_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_wisdom_version)) { - device->base.layout = &oceanic_wisdom_layout; - } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_vtpro_version)) { - device->base.layout = &oceanic_vtpro_layout; } else { - WARNING (context, "Unsupported device detected!"); - device->base.layout = &oceanic_vtpro_layout; + device->base.layout = OCEANIC_COMMON_MATCH(device->base.version, versions, &device->base.firmware); + if (device->base.layout == NULL) { + WARNING (context, "Unsupported device detected!"); + device->base.layout = &oceanic_vtpro_layout; + } } *out = (dc_device_t*) device; diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 5974dbe..be74b1c 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -50,6 +50,7 @@ #define CHROMIS 0x24 #define ALADINA1 0x25 #define MANTIS2 0x26 +#define ALADINA2 0x28 #define G2 0x32 #define G2HUD 0x42 @@ -532,7 +533,7 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) parser->model == CHROMIS || parser->model == MANTIS2 || parser->model == G2 || parser->model == ALADINSPORTMATRIX || parser->model == ALADINSQUARE || parser->model == G2HUD || - parser->model == ALADINA1) { + parser->model == ALADINA1 || parser->model == ALADINA2 ) { unsigned int offset = header->tankpressure + 2 * i; endpressure = array_uint16_le(data + offset); beginpressure = array_uint16_le(data + offset + 2 * header->ngases); @@ -626,6 +627,7 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i case G2HUD: case ALADINSPORTMATRIX: case ALADINA1: + case ALADINA2: parser->headersize = 84; parser->header = &uwatec_smart_trimix_header; parser->samples = uwatec_smart_galileo_samples; @@ -969,7 +971,7 @@ uwatec_smart_parse (uwatec_smart_parser_t *parser, dc_sample_callback_t callback parser->model == CHROMIS || parser->model == MANTIS2 || parser->model == G2 || parser->model == ALADINSPORTMATRIX || parser->model == ALADINSQUARE || parser->model == G2HUD || - parser->model == ALADINA1) { + parser->model == ALADINA1 || parser->model == ALADINA2 ) { // Uwatec Galileo id = uwatec_galileo_identify (data[offset]); } else {