Merge branch 'horizon'

This commit is contained in:
Jef Driesen 2020-12-24 14:06:03 +01:00
commit 099fda0d2b
3 changed files with 126 additions and 55 deletions

View File

@ -294,6 +294,7 @@ static const dc_descriptor_t g_descriptors[] = {
{"Mares", "Quad Air", DC_FAMILY_MARES_ICONHD , 0x23, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Quad Air", DC_FAMILY_MARES_ICONHD , 0x23, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
{"Mares", "Smart Air", DC_FAMILY_MARES_ICONHD , 0x24, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Smart Air", DC_FAMILY_MARES_ICONHD , 0x24, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
{"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
{"Mares", "Horizon", DC_FAMILY_MARES_ICONHD , 0x2C, DC_TRANSPORT_SERIAL, NULL},
/* Heinrichs Weikamp */ /* Heinrichs Weikamp */
{"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL}, {"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL},
{"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL}, {"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL},

View File

@ -49,6 +49,7 @@
#define QUADAIR 0x23 #define QUADAIR 0x23
#define SMARTAIR 0x24 #define SMARTAIR 0x24
#define QUAD 0x29 #define QUAD 0x29
#define HORIZON 0x2C
#define MAXRETRIES 4 #define MAXRETRIES 4
@ -128,6 +129,12 @@ static const mares_iconhd_layout_t mares_iconhdnet_layout = {
0x100000, /* rb_profile_end */ 0x100000, /* rb_profile_end */
}; };
static const mares_iconhd_layout_t mares_genius_layout = {
0x1000000, /* memsize */
0x0100000, /* rb_profile_begin */
0x1000000, /* rb_profile_end */
};
static const mares_iconhd_layout_t mares_matrix_layout = { static const mares_iconhd_layout_t mares_matrix_layout = {
0x40000, /* memsize */ 0x40000, /* memsize */
0x0A000, /* rb_profile_begin */ 0x0A000, /* rb_profile_begin */
@ -156,6 +163,7 @@ mares_iconhd_get_model (mares_iconhd_device_t *device)
{"Quad Air", QUADAIR}, {"Quad Air", QUADAIR},
{"Smart Air", SMARTAIR}, {"Smart Air", SMARTAIR},
{"Quad", QUAD}, {"Quad", QUAD},
{"Horizon", HORIZON},
}; };
// Check the product name in the version packet against the list // Check the product name in the version packet against the list
@ -560,8 +568,9 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
device->packetsize = 256; device->packetsize = 256;
break; break;
case GENIUS: case GENIUS:
device->layout = &mares_iconhdnet_layout; case HORIZON:
device->packetsize = 256; device->layout = &mares_genius_layout;
device->packetsize = 4096;
device->fingerprint_size = 4; device->fingerprint_size = 4;
break; break;
case ICONHDNET: case ICONHDNET:
@ -952,7 +961,7 @@ mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
devinfo.serial = array_uint32_le (serial); devinfo.serial = array_uint32_le (serial);
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
if (device->model == GENIUS) { if (device->model == GENIUS || device->model == HORIZON) {
return mares_iconhd_device_foreach_object (abstract, callback, userdata); return mares_iconhd_device_foreach_object (abstract, callback, userdata);
} else { } else {
return mares_iconhd_device_foreach_raw (abstract, callback, userdata); return mares_iconhd_device_foreach_raw (abstract, callback, userdata);

View File

@ -38,6 +38,7 @@
#define GENIUS 0x1C #define GENIUS 0x1C
#define QUADAIR 0x23 #define QUADAIR 0x23
#define SMARTAIR 0x24 #define SMARTAIR 0x24
#define HORIZON 0x2C
#define NGASMIXES_ICONHD 3 #define NGASMIXES_ICONHD 3
#define NGASMIXES_GENIUS 5 #define NGASMIXES_GENIUS 5
@ -58,6 +59,8 @@
#define GENIUS_TRIMIX 3 #define GENIUS_TRIMIX 3
#define GENIUS_GAUGE 4 #define GENIUS_GAUGE 4
#define GENIUS_FREEDIVE 5 #define GENIUS_FREEDIVE 5
#define GENIUS_SCR 6
#define GENIUS_OC 7
// Record types and sizes // Record types and sizes
#define DSTR_TYPE 0x44535452 // Dive start record #define DSTR_TYPE 0x44535452 // Dive start record
@ -66,6 +69,8 @@
#define TISS_SIZE 138 #define TISS_SIZE 138
#define DPRS_TYPE 0x44505253 // Sample record #define DPRS_TYPE 0x44505253 // Sample record
#define DPRS_SIZE 34 #define DPRS_SIZE 34
#define SDPT_TYPE 0x53445054 // SCR sample record
#define SDPT_SIZE 78
#define AIRS_TYPE 0x41495253 // Air integration record #define AIRS_TYPE 0x41495253 // Air integration record
#define AIRS_SIZE 16 #define AIRS_SIZE 16
#define DEND_TYPE 0x44454E44 // Dive end record #define DEND_TYPE 0x44454E44 // Dive end record
@ -128,6 +133,7 @@ struct mares_iconhd_parser_t {
unsigned int model; unsigned int model;
// Cached fields. // Cached fields.
unsigned int cached; unsigned int cached;
unsigned int logformat;
unsigned int mode; unsigned int mode;
unsigned int nsamples; unsigned int nsamples;
unsigned int samplesize; unsigned int samplesize;
@ -331,6 +337,7 @@ mares_iconhd_cache (mares_iconhd_parser_t *parser)
parser->base.size = length; parser->base.size = length;
// Cache the data for later use. // Cache the data for later use.
parser->logformat = 0;
parser->mode = mode; parser->mode = mode;
parser->nsamples = nsamples; parser->nsamples = nsamples;
parser->samplesize = samplesize; parser->samplesize = samplesize;
@ -358,30 +365,39 @@ mares_genius_cache (mares_iconhd_parser_t *parser)
const unsigned char *data = parser->base.data; const unsigned char *data = parser->base.data;
unsigned int size = parser->base.size; unsigned int size = parser->base.size;
if (size < 4) { if (size < 20) {
ERROR (abstract->context, "Buffer overflow detected!"); ERROR (abstract->context, "Buffer overflow detected!");
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
// Check the header type and version. // Check the header type and version.
unsigned int type = array_uint16_le (data); unsigned int type = array_uint16_le (data);
unsigned int major = data[2]; unsigned int minor = data[2];
unsigned int minor = data[3]; unsigned int major = data[3];
if (type != 1 || major != 0 || minor != 0) { if (type != 1 || major != 0 || minor > 1) {
ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).", ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).",
type, major, minor); type, major, minor);
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
// Get the data format.
unsigned int logformat = data[0x10];
// The Horizon header has 8 bytes extra at offset 0x18.
unsigned int extra = 0;
if (logformat == 1) {
extra = 8;
}
// Get the header size. // Get the header size.
unsigned int headersize = 0xB8; unsigned int headersize = 0xB8 + extra;
if (headersize > size) { if (headersize > size) {
ERROR (abstract->context, "Buffer overflow detected!"); ERROR (abstract->context, "Buffer overflow detected!");
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
// Get the number of samples in the profile data. // Get the number of samples in the profile data.
unsigned int nsamples = array_uint16_le (data + 0x20); unsigned int nsamples = array_uint16_le (data + 0x20 + extra);
// Get the dive settings. // Get the dive settings.
unsigned int settings = array_uint32_le (data + 0x0C); unsigned int settings = array_uint32_le (data + 0x0C);
@ -389,8 +405,11 @@ mares_genius_cache (mares_iconhd_parser_t *parser)
// Get the dive mode. // Get the dive mode.
unsigned int mode = settings & 0xF; unsigned int mode = settings & 0xF;
// Get the sample size.
unsigned int samplesize = logformat == 1 ? SDPT_SIZE: DPRS_SIZE;
// Calculate the total number of bytes for this dive. // Calculate the total number of bytes for this dive.
unsigned int nbytes = headersize + 4 + DSTR_SIZE + TISS_SIZE + nsamples * DPRS_SIZE + (nsamples / 4) * AIRS_SIZE + DEND_SIZE; unsigned int nbytes = headersize + 4 + DSTR_SIZE + TISS_SIZE + nsamples * samplesize + (nsamples / 4) * AIRS_SIZE + DEND_SIZE;
if (nbytes > size) { if (nbytes > size) {
ERROR (abstract->context, "Buffer overflow detected!"); ERROR (abstract->context, "Buffer overflow detected!");
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
@ -402,7 +421,7 @@ mares_genius_cache (mares_iconhd_parser_t *parser)
mares_iconhd_gasmix_t gasmix[NGASMIXES_GENIUS] = {0}; mares_iconhd_gasmix_t gasmix[NGASMIXES_GENIUS] = {0};
mares_iconhd_tank_t tank[NTANKS_GENIUS] = {0}; mares_iconhd_tank_t tank[NTANKS_GENIUS] = {0};
for (unsigned int i = 0; i < NGASMIXES_GENIUS; i++) { for (unsigned int i = 0; i < NGASMIXES_GENIUS; i++) {
unsigned int offset = 0x54 + i * 20; unsigned int offset = 0x54 + extra + i * 20;
unsigned int gasmixparams = array_uint32_le(data + offset + 0); unsigned int gasmixparams = array_uint32_le(data + offset + 0);
unsigned int beginpressure = array_uint16_le(data + offset + 4); unsigned int beginpressure = array_uint16_le(data + offset + 4);
unsigned int endpressure = array_uint16_le(data + offset + 6); unsigned int endpressure = array_uint16_le(data + offset + 6);
@ -441,9 +460,10 @@ mares_genius_cache (mares_iconhd_parser_t *parser)
} }
// Cache the data for later use. // Cache the data for later use.
parser->logformat = logformat;
parser->mode = mode; parser->mode = mode;
parser->nsamples = nsamples; parser->nsamples = nsamples;
parser->samplesize = DPRS_SIZE; parser->samplesize = samplesize;
parser->headersize = headersize; parser->headersize = headersize;
parser->settings = settings; parser->settings = settings;
parser->interval = 5; parser->interval = 5;
@ -468,7 +488,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser)
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
if (parser->model == GENIUS) { if (parser->model == GENIUS || parser->model == HORIZON) {
return mares_genius_cache (parser); return mares_genius_cache (parser);
} else { } else {
return mares_iconhd_cache (parser); return mares_iconhd_cache (parser);
@ -493,7 +513,8 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
// Set the default values. // Set the default values.
parser->model = model; parser->model = model;
parser->cached = 0; parser->cached = 0;
parser->mode = (model == GENIUS) ? GENIUS_AIR : ICONHD_AIR; parser->logformat = 0;
parser->mode = (model == GENIUS || model == HORIZON) ? GENIUS_AIR : ICONHD_AIR;
parser->nsamples = 0; parser->nsamples = 0;
parser->samplesize = 0; parser->samplesize = 0;
parser->headersize = 0; parser->headersize = 0;
@ -526,7 +547,8 @@ mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data,
// Reset the cache. // Reset the cache.
parser->cached = 0; parser->cached = 0;
parser->mode = (parser->model == GENIUS) ? GENIUS_AIR : ICONHD_AIR; parser->logformat = 0;
parser->mode = (parser->model == GENIUS || parser->model == HORIZON) ? GENIUS_AIR : ICONHD_AIR;
parser->nsamples = 0; parser->nsamples = 0;
parser->samplesize = 0; parser->samplesize = 0;
parser->headersize = 0; parser->headersize = 0;
@ -562,7 +584,7 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime
// Pointer to the header data. // Pointer to the header data.
const unsigned char *p = abstract->data; const unsigned char *p = abstract->data;
if (parser->model != GENIUS) { if (parser->model != GENIUS && parser->model != HORIZON) {
p += abstract->size - parser->headersize; p += abstract->size - parser->headersize;
if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) { if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) {
p += 4; p += 4;
@ -570,7 +592,7 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime
} }
// Offset to the date/time field. // Offset to the date/time field.
if (parser->model == GENIUS) { if (parser->model == GENIUS || parser->model == HORIZON) {
p += 0x08; p += 0x08;
} else if (parser->model == SMARTAPNEA) { } else if (parser->model == SMARTAPNEA) {
p += 0x40; p += 0x40;
@ -581,7 +603,7 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime
} }
if (datetime) { if (datetime) {
if (parser->model == GENIUS) { if (parser->model == GENIUS || parser->model == HORIZON) {
unsigned int timestamp = array_uint32_le (p); unsigned int timestamp = array_uint32_le (p);
datetime->hour = (timestamp ) & 0x1F; datetime->hour = (timestamp ) & 0x1F;
datetime->minute = (timestamp >> 5) & 0x3F; datetime->minute = (timestamp >> 5) & 0x3F;
@ -616,14 +638,21 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
// Pointer to the header data. // Pointer to the header data.
const unsigned char *p = abstract->data; const unsigned char *p = abstract->data;
if (parser->model != GENIUS) { if (parser->model != GENIUS && parser->model != HORIZON) {
p += abstract->size - parser->headersize; p += abstract->size - parser->headersize;
if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) { if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) {
p += 4; p += 4;
} }
} }
unsigned int metric = parser->model == GENIUS ? p[0x34] : parser->settings & 0x0100; // The Horizon header has 8 bytes extra at offset 0x18.
unsigned int extra = 0;
if (parser->logformat == 1) {
extra = 8;
}
unsigned int metric = (parser->model == GENIUS || parser->model == HORIZON) ?
p[0x34 + extra] : parser->settings & 0x0100;
dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
dc_tank_t *tank = (dc_tank_t *) value; dc_tank_t *tank = (dc_tank_t *) value;
@ -632,7 +661,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
if (value) { if (value) {
switch (type) { switch (type) {
case DC_FIELD_DIVETIME: case DC_FIELD_DIVETIME:
if (parser->model == GENIUS) { if (parser->model == GENIUS || parser->model == HORIZON) {
*((unsigned int *) value) = parser->nsamples * parser->interval; *((unsigned int *) value) = parser->nsamples * parser->interval;
} else if (parser->model == SMARTAPNEA) { } else if (parser->model == SMARTAPNEA) {
*((unsigned int *) value) = array_uint16_le (p + 0x24); *((unsigned int *) value) = array_uint16_le (p + 0x24);
@ -649,8 +678,8 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
} }
break; break;
case DC_FIELD_MAXDEPTH: case DC_FIELD_MAXDEPTH:
if (parser->model == GENIUS) if (parser->model == GENIUS || parser->model == HORIZON)
*((double *) value) = array_uint16_le (p + 0x22) / 10.0; *((double *) value) = array_uint16_le (p + 0x22 + extra) / 10.0;
else if (parser->model == SMARTAPNEA) else if (parser->model == SMARTAPNEA)
*((double *) value) = array_uint16_le (p + 0x3A) / 10.0; *((double *) value) = array_uint16_le (p + 0x3A) / 10.0;
else if (parser->mode == ICONHD_FREEDIVE) else if (parser->mode == ICONHD_FREEDIVE)
@ -691,8 +720,8 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
} }
break; break;
case DC_FIELD_ATMOSPHERIC: case DC_FIELD_ATMOSPHERIC:
if (parser->model == GENIUS) if (parser->model == GENIUS || parser->model == HORIZON)
*((double *) value) = array_uint16_le (p + 0x3E) / 1000.0; *((double *) value) = array_uint16_le (p + 0x3E + extra) / 1000.0;
else if (parser->model == SMARTAPNEA) else if (parser->model == SMARTAPNEA)
*((double *) value) = array_uint16_le (p + 0x38) / 1000.0; *((double *) value) = array_uint16_le (p + 0x38) / 1000.0;
else if (parser->mode == ICONHD_FREEDIVE) else if (parser->mode == ICONHD_FREEDIVE)
@ -701,7 +730,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
*((double *) value) = array_uint16_le (p + 0x22) / 8000.0; *((double *) value) = array_uint16_le (p + 0x22) / 8000.0;
break; break;
case DC_FIELD_SALINITY: case DC_FIELD_SALINITY:
if (parser->model == GENIUS) { if (parser->model == GENIUS || parser->model == HORIZON) {
unsigned int salinity = (parser->settings >> 5) & 0x03; unsigned int salinity = (parser->settings >> 5) & 0x03;
switch (salinity) { switch (salinity) {
case WATER_FRESH: case WATER_FRESH:
@ -737,8 +766,8 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
} }
break; break;
case DC_FIELD_TEMPERATURE_MINIMUM: case DC_FIELD_TEMPERATURE_MINIMUM:
if (parser->model == GENIUS) if (parser->model == GENIUS || parser->model == HORIZON)
*((double *) value) = (signed short) array_uint16_le (p + 0x28) / 10.0; *((double *) value) = (signed short) array_uint16_le (p + 0x28 + extra) / 10.0;
else if (parser->model == SMARTAPNEA) else if (parser->model == SMARTAPNEA)
*((double *) value) = (signed short) array_uint16_le (p + 0x3E) / 10.0; *((double *) value) = (signed short) array_uint16_le (p + 0x3E) / 10.0;
else if (parser->mode == ICONHD_FREEDIVE) else if (parser->mode == ICONHD_FREEDIVE)
@ -747,8 +776,8 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
*((double *) value) = (signed short) array_uint16_le (p + 0x42) / 10.0; *((double *) value) = (signed short) array_uint16_le (p + 0x42) / 10.0;
break; break;
case DC_FIELD_TEMPERATURE_MAXIMUM: case DC_FIELD_TEMPERATURE_MAXIMUM:
if (parser->model == GENIUS) if (parser->model == GENIUS || parser->model == HORIZON)
*((double *) value) = (signed short) array_uint16_le (p + 0x26) / 10.0; *((double *) value) = (signed short) array_uint16_le (p + 0x26 + extra) / 10.0;
else if (parser->model == SMARTAPNEA) else if (parser->model == SMARTAPNEA)
*((double *) value) = (signed short) array_uint16_le (p + 0x3C) / 10.0; *((double *) value) = (signed short) array_uint16_le (p + 0x3C) / 10.0;
else if (parser->mode == ICONHD_FREEDIVE) else if (parser->mode == ICONHD_FREEDIVE)
@ -757,12 +786,13 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
*((double *) value) = (signed short) array_uint16_le (p + 0x44) / 10.0; *((double *) value) = (signed short) array_uint16_le (p + 0x44) / 10.0;
break; break;
case DC_FIELD_DIVEMODE: case DC_FIELD_DIVEMODE:
if (parser->model == GENIUS) { if (parser->model == GENIUS || parser->model == HORIZON) {
switch (parser->mode) { switch (parser->mode) {
case GENIUS_AIR: case GENIUS_AIR:
case GENIUS_NITROX_SINGLE: case GENIUS_NITROX_SINGLE:
case GENIUS_NITROX_MULTI: case GENIUS_NITROX_MULTI:
case GENIUS_TRIMIX: case GENIUS_TRIMIX:
case GENIUS_OC:
*((dc_divemode_t *) value) = DC_DIVEMODE_OC; *((dc_divemode_t *) value) = DC_DIVEMODE_OC;
break; break;
case GENIUS_GAUGE: case GENIUS_GAUGE:
@ -771,6 +801,9 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
case GENIUS_FREEDIVE: case GENIUS_FREEDIVE:
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE; *((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
break; break;
case GENIUS_SCR:
*((dc_divemode_t *) value) = DC_DIVEMODE_SCR;
break;
default: default:
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
@ -823,19 +856,20 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
// Previous gas mix - initialize with impossible value // Previous gas mix - initialize with impossible value
unsigned int gasmix_previous = 0xFFFFFFFF; unsigned int gasmix_previous = 0xFFFFFFFF;
unsigned int isairintegrated = (parser->model == ICONHDNET || parser->model == QUADAIR || parser->model == SMARTAIR || parser->model == GENIUS); unsigned int isairintegrated = (parser->model == ICONHDNET || parser->model == QUADAIR ||
parser->model == SMARTAIR || parser->model == GENIUS || parser->model == HORIZON);
unsigned int offset = 4; unsigned int offset = 4;
unsigned int marker = 0; unsigned int marker = 0;
if (parser->model == GENIUS) { if (parser->model == GENIUS || parser->model == HORIZON) {
// Skip the dive header. // Skip the dive header.
data += parser->headersize; data += parser->headersize;
// Check the profile type and version. // Check the profile type and version.
unsigned int type = array_uint16_le (data); unsigned int type = array_uint16_le (data);
unsigned int major = data[2]; unsigned int minor = data[2];
unsigned int minor = data[3]; unsigned int major = data[3];
if (type != 0 || major != 2 || minor != 0) { if (type > 1 || major != 0 || minor != 2) {
ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).", ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).",
type, major, minor); type, major, minor);
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
@ -894,7 +928,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
offset += 2 * parser->samplerate; offset += 2 * parser->samplerate;
} }
} else if (parser->model != GENIUS && parser->mode == ICONHD_FREEDIVE) { } else if (parser->model != GENIUS && parser->model != HORIZON && parser->mode == ICONHD_FREEDIVE) {
unsigned int maxdepth = array_uint16_le (data + offset + 0); unsigned int maxdepth = array_uint16_le (data + offset + 0);
unsigned int divetime = array_uint16_le (data + offset + 2); unsigned int divetime = array_uint16_le (data + offset + 2);
unsigned int surftime = array_uint16_le (data + offset + 4); unsigned int surftime = array_uint16_le (data + offset + 4);
@ -921,18 +955,46 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
nsamples++; nsamples++;
} else { } else {
unsigned int depth = 0, temperature = 0; unsigned int depth = 0, temperature = 0;
unsigned int gasmix = 0, misc = 0, alarms = 0; unsigned int gasmix = 0, alarms = 0;
if (parser->model == GENIUS) { unsigned int decostop = 0, decodepth = 0, decotime = 0, tts = 0;
if (!mares_genius_isvalid (data + offset, DPRS_SIZE, DPRS_TYPE)) { if (parser->model == GENIUS || parser->model == HORIZON) {
ERROR (abstract->context, "Invalid DPRS record."); if (parser->logformat == 1) {
return DC_STATUS_DATAFORMAT; if (!mares_genius_isvalid (data + offset, SDPT_SIZE, SDPT_TYPE)) {
} ERROR (abstract->context, "Invalid SDPT record.");
return DC_STATUS_DATAFORMAT;
}
depth = array_uint16_le (data + offset + marker + 0); unsigned int misc = 0, deco = 0;
temperature = array_uint16_le (data + offset + marker + 4); depth = array_uint16_le (data + offset + marker + 2);
alarms = array_uint32_le (data + offset + marker + 0x0C); temperature = array_uint16_le (data + offset + marker + 6);
misc = array_uint32_le (data + offset + marker + 0x14); alarms = array_uint32_le (data + offset + marker + 0x14);
gasmix = (misc >> 6) & 0xF; misc = array_uint32_le (data + offset + marker + 0x18);
deco = array_uint32_le (data + offset + marker + 0x1C);
gasmix = (misc >> 6) & 0x0F;
decostop = (misc >> 10) & 0x01;
if (decostop) {
decodepth = (deco >> 3) & 0x7F;
decotime = (deco >> 10) & 0xFF;
tts = (deco >> 18) & 0x3FFF;
} else {
decotime = deco & 0xFF;
}
} else {
if (!mares_genius_isvalid (data + offset, DPRS_SIZE, DPRS_TYPE)) {
ERROR (abstract->context, "Invalid DPRS record.");
return DC_STATUS_DATAFORMAT;
}
unsigned int misc = 0;
depth = array_uint16_le (data + offset + marker + 0);
temperature = array_uint16_le (data + offset + marker + 4);
decotime = array_uint16_le (data + offset + marker + 0x0A);
alarms = array_uint32_le (data + offset + marker + 0x0C);
misc = array_uint32_le (data + offset + marker + 0x14);
gasmix = (misc >> 6) & 0x0F;
decostop = (misc >> 18) & 0x01;
decodepth = (misc >> 19) & 0x7F;
}
} else { } else {
depth = array_uint16_le (data + offset + 0); depth = array_uint16_le (data + offset + 0);
temperature = array_uint16_le (data + offset + 2) & 0x0FFF; temperature = array_uint16_le (data + offset + 2) & 0x0FFF;
@ -965,10 +1027,8 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
} }
} }
if (parser->model == GENIUS) { if (parser->model == GENIUS || parser->model == HORIZON) {
// Deco stop / NDL. // Deco stop / NDL.
unsigned int decostop = (misc >> 18) & 0x01;
unsigned int decodepth = (misc >> 19) & 0x7F;
if (decostop) { if (decostop) {
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.depth = decodepth; sample.deco.depth = decodepth;
@ -976,7 +1036,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
sample.deco.type = DC_DECO_NDL; sample.deco.type = DC_DECO_NDL;
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
} }
sample.deco.time = array_uint16_le (data + offset + marker + 0x0A) * 60; sample.deco.time = decotime * 60;
if (callback) callback (DC_SAMPLE_DECO, sample, userdata); if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
// Alarms // Alarms
@ -1013,7 +1073,8 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
// Some extra data. // Some extra data.
if (isairintegrated && (nsamples % 4) == 0) { if (isairintegrated && (nsamples % 4) == 0) {
if (parser->model == GENIUS && !mares_genius_isvalid (data + offset, AIRS_SIZE, AIRS_TYPE)) { if ((parser->model == GENIUS || parser->model == HORIZON) &&
!mares_genius_isvalid (data + offset, AIRS_SIZE, AIRS_TYPE)) {
ERROR (abstract->context, "Invalid AIRS record."); ERROR (abstract->context, "Invalid AIRS record.");
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
@ -1028,12 +1089,12 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
WARNING (abstract->context, "Invalid tank with non-zero pressure."); WARNING (abstract->context, "Invalid tank with non-zero pressure.");
} }
offset += (parser->model == GENIUS) ? AIRS_SIZE : 8; offset += (parser->model == GENIUS || parser->model == HORIZON) ? AIRS_SIZE : 8;
} }
} }
} }
if (parser->model == GENIUS) { if (parser->model == GENIUS || parser->model == HORIZON) {
// Skip the DEND record. // Skip the DEND record.
if (!mares_genius_isvalid (data + offset, DEND_SIZE, DEND_TYPE)) { if (!mares_genius_isvalid (data + offset, DEND_SIZE, DEND_TYPE)) {
ERROR (abstract->context, "Invalid DEND record."); ERROR (abstract->context, "Invalid DEND record.");