diff --git a/include/libdivecomputer/divesystem_idive.h b/include/libdivecomputer/divesystem_idive.h index e1e66d5..4a9d817 100644 --- a/include/libdivecomputer/divesystem_idive.h +++ b/include/libdivecomputer/divesystem_idive.h @@ -33,9 +33,15 @@ extern "C" { dc_status_t divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, const char *name); +dc_status_t +divesystem_idive_device_open2 (dc_device_t **device, dc_context_t *context, const char *name, unsigned int model); + dc_status_t divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context); +dc_status_t +divesystem_idive_parser_create2 (dc_parser_t **parser, dc_context_t *context, unsigned int model); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/descriptor.c b/src/descriptor.c index 18c8d77..c5b3228 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -254,6 +254,10 @@ 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 Tec", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24}, + {"DiveSystem", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25}, }; typedef struct dc_descriptor_iterator_t { diff --git a/src/device.c b/src/device.c index d95585d..504b8cf 100644 --- a/src/device.c +++ b/src/device.c @@ -163,7 +163,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr rc = citizen_aqualand_device_open (&device, context, name); break; case DC_FAMILY_DIVESYSTEM_IDIVE: - rc = divesystem_idive_device_open (&device, context, name); + rc = divesystem_idive_device_open2 (&device, context, name, dc_descriptor_get_model (descriptor)); break; default: return DC_STATUS_INVALIDARGS; diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index eecfb5a..585bd58 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -37,6 +37,11 @@ rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ ) +#define IX3M_EASY 0x22 +#define IX3M_DEEP 0x23 +#define IX3M_TEC 0x24 +#define IX3M_REB 0x25 + #define MAXRETRIES 9 #define MAXPACKET 0xFF @@ -45,23 +50,26 @@ #define NAK 0x15 #define BUSY 0x60 -#define CMD_ID 0x10 -#define CMD_RANGE 0x98 -#define CMD_HEADER 0xA0 -#define CMD_SAMPLE 0xA8 - -#define SZ_ID 0x0A -#define SZ_RANGE 0x04 -#define SZ_HEADER 0x32 -#define SZ_SAMPLE 0x2A - #define NSTEPS 1000 #define STEP(i,n) (NSTEPS * (i) / (n)) +typedef struct divesystem_idive_command_t { + unsigned char cmd; + unsigned int size; +} divesystem_idive_command_t; + +typedef struct divesystem_idive_commands_t { + divesystem_idive_command_t id; + divesystem_idive_command_t range; + divesystem_idive_command_t header; + divesystem_idive_command_t sample; +} divesystem_idive_commands_t; + typedef struct divesystem_idive_device_t { dc_device_t base; serial_t *port; unsigned char fingerprint[4]; + unsigned int model; } divesystem_idive_device_t; static dc_status_t divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size); @@ -78,9 +86,29 @@ static const dc_device_vtable_t divesystem_idive_device_vtable = { divesystem_idive_device_close /* close */ }; +static const divesystem_idive_commands_t idive = { + {0x10, 0x0A}, + {0x98, 0x04}, + {0xA0, 0x32}, + {0xA8, 0x2A}, +}; + +static const divesystem_idive_commands_t ix3m = { + {0x11, 0x1A}, + {0x78, 0x04}, + {0x79, 0x36}, + {0x7A, 0x36}, +}; dc_status_t divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, const char *name) +{ + return divesystem_idive_device_open2 (out, context, name, 0); +} + + +dc_status_t +divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) { if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -98,6 +126,7 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, const ch // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); + device->model = model; // Open the device. int rc = serial_open (&device->port, context, name); @@ -334,39 +363,43 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb { dc_status_t rc = DC_STATUS_SUCCESS; divesystem_idive_device_t *device = (divesystem_idive_device_t *) abstract; + unsigned char packet[MAXPACKET - 2]; + + const divesystem_idive_commands_t *commands = &idive; + if (device->model >= IX3M_EASY && device->model <= IX3M_REB) { + commands = &ix3m; + } // Enable progress notifications. dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - unsigned char cmd_id[] = {CMD_ID, 0xED}; - unsigned char id[SZ_ID]; - rc = divesystem_idive_transfer (device, cmd_id, sizeof(cmd_id), id, sizeof(id)); + unsigned char cmd_id[] = {commands->id.cmd, 0xED}; + rc = divesystem_idive_transfer (device, cmd_id, sizeof(cmd_id), packet, commands->id.size); if (rc != DC_STATUS_SUCCESS) return rc; // Emit a device info event. dc_event_devinfo_t devinfo; - devinfo.model = array_uint16_le (id); + devinfo.model = array_uint16_le (packet); devinfo.firmware = 0; - devinfo.serial = array_uint32_le (id + 6); + devinfo.serial = array_uint32_le (packet + 6); device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Emit a vendor event. dc_event_vendor_t vendor; - vendor.data = id; - vendor.size = sizeof (id); + vendor.data = packet; + vendor.size = commands->id.size; device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); - unsigned char cmd_range[] = {CMD_RANGE, 0x8D}; - unsigned char range[4]; - rc = divesystem_idive_transfer (device, cmd_range, sizeof(cmd_range), range, sizeof(range)); + unsigned char cmd_range[] = {commands->range.cmd, 0x8D}; + rc = divesystem_idive_transfer (device, cmd_range, sizeof(cmd_range), packet, commands->range.size); if (rc != DC_STATUS_SUCCESS) return rc; // Get the range of the available dive numbers. - unsigned int first = array_uint16_le (range + 0); - unsigned int last = array_uint16_le (range + 2); + unsigned int first = array_uint16_le (packet + 0); + unsigned int last = array_uint16_le (packet + 2); if (first > last) { ERROR(abstract->context, "Invalid dive numbers."); return DC_STATUS_DATAFORMAT; @@ -386,34 +419,32 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb for (unsigned int i = 0; i < ndives; ++i) { unsigned int number = last - i; - unsigned char cmd_header[] = {CMD_HEADER, + unsigned char cmd_header[] = {commands->header.cmd, (number ) & 0xFF, (number >> 8) & 0xFF}; - unsigned char header[SZ_HEADER]; - rc = divesystem_idive_transfer (device, cmd_header, sizeof(cmd_header), header, sizeof(header)); + rc = divesystem_idive_transfer (device, cmd_header, sizeof(cmd_header), packet, commands->header.size); if (rc != DC_STATUS_SUCCESS) return rc; - if (memcmp(header + 7, device->fingerprint, sizeof(device->fingerprint)) == 0) + if (memcmp(packet + 7, device->fingerprint, sizeof(device->fingerprint)) == 0) break; - unsigned int nsamples = array_uint16_le (header + 1); + unsigned int nsamples = array_uint16_le (packet + 1); // Update and emit a progress event. progress.current = i * NSTEPS + STEP(1, nsamples + 1); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); dc_buffer_clear(buffer); - dc_buffer_reserve(buffer, SZ_HEADER + SZ_SAMPLE * nsamples); - dc_buffer_append(buffer, header, sizeof(header)); + dc_buffer_reserve(buffer, commands->header.size + commands->sample.size * nsamples); + dc_buffer_append(buffer, packet, commands->header.size); for (unsigned int j = 0; j < nsamples; ++j) { unsigned int idx = j + 1; - unsigned char cmd_sample[] = {CMD_SAMPLE, + unsigned char cmd_sample[] = {commands->sample.cmd, (idx ) & 0xFF, (idx >> 8) & 0xFF}; - unsigned char sample[SZ_SAMPLE]; - rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), sample, sizeof(sample)); + rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), packet, commands->sample.size); if (rc != DC_STATUS_SUCCESS) return rc; @@ -421,7 +452,7 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb progress.current = i * NSTEPS + STEP(j + 2, nsamples + 1); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - dc_buffer_append(buffer, sample, sizeof(sample)); + dc_buffer_append(buffer, packet, commands->sample.size); } unsigned char *data = dc_buffer_get_data(buffer); diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index dc0e5d0..c1ea98c 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -29,8 +29,15 @@ #define ISINSTANCE(parser) dc_device_isinstance((parser), &divesystem_idive_parser_vtable) -#define SZ_HEADER 0x32 -#define SZ_SAMPLE 0x2A +#define IX3M_EASY 0x22 +#define IX3M_DEEP 0x23 +#define IX3M_TEC 0x24 +#define IX3M_REB 0x25 + +#define SZ_HEADER_IDIVE 0x32 +#define SZ_SAMPLE_IDIVE 0x2A +#define SZ_HEADER_IX3M 0x36 +#define SZ_SAMPLE_IX3M 0x36 #define NGASMIXES 8 @@ -40,6 +47,8 @@ typedef struct divesystem_idive_parser_t divesystem_idive_parser_t; struct divesystem_idive_parser_t { dc_parser_t base; + unsigned int headersize; + unsigned int samplesize; // Cached fields. unsigned int cached; unsigned int divetime; @@ -67,6 +76,13 @@ static const dc_parser_vtable_t divesystem_idive_parser_vtable = { dc_status_t divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context) +{ + return divesystem_idive_parser_create2 (out, context, 0); +} + + +dc_status_t +divesystem_idive_parser_create2 (dc_parser_t **out, dc_context_t *context, unsigned int model) { if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -82,6 +98,13 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context) parser_init (&parser->base, context, &divesystem_idive_parser_vtable); // Set the default values. + if (model >= IX3M_EASY && model <= IX3M_REB) { + parser->headersize = SZ_HEADER_IX3M; + parser->samplesize = SZ_SAMPLE_IX3M; + } else { + parser->headersize = SZ_HEADER_IDIVE; + parser->samplesize = SZ_SAMPLE_IDIVE; + } parser->cached = 0; parser->divetime = 0; parser->maxdepth = 0; @@ -129,7 +152,9 @@ divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *da static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) { - if (abstract->size < SZ_HEADER) + divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) abstract; + + if (abstract->size < parser->headersize) return DC_STATUS_DATAFORMAT; dc_ticks_t ticks = array_uint32_le(abstract->data + 7) + EPOCH; @@ -147,7 +172,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) abstract; const unsigned char *data = abstract->data; - if (abstract->size < SZ_HEADER) + if (abstract->size < parser->headersize) return DC_STATUS_DATAFORMAT; if (!parser->cached) { @@ -201,8 +226,8 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba unsigned int o2_previous = 0xFFFFFFFF; unsigned int he_previous = 0xFFFFFFFF; - unsigned int offset = SZ_HEADER; - while (offset + SZ_SAMPLE <= size) { + unsigned int offset = parser->headersize; + while (offset + parser->samplesize <= size) { dc_sample_value_t sample = {0}; // Time (seconds). @@ -279,7 +304,7 @@ 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); - offset += SZ_SAMPLE; + offset += parser->samplesize; } // Cache the data for later use. diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 562099d..a45c06a 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -70,6 +70,7 @@ shearwater_petrel_parser_create diverite_nitekq_parser_create citizen_aqualand_parser_create divesystem_idive_parser_create +divesystem_idive_parser_create2 dc_device_open dc_device_close @@ -175,3 +176,4 @@ diverite_nitekq_device_open diverite_nitekq_extract_dives citizen_aqualand_device_open divesystem_idive_device_open +divesystem_idive_device_open2 diff --git a/src/parser.c b/src/parser.c index 4d0d97e..5f9a7a7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -140,7 +140,7 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) rc = citizen_aqualand_parser_create (&parser, context); break; case DC_FAMILY_DIVESYSTEM_IDIVE: - rc = divesystem_idive_parser_create (&parser, context); + rc = divesystem_idive_parser_create2 (&parser, context, device->devinfo.model); break; default: return DC_STATUS_INVALIDARGS;